make_virtuals.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. script_call = """ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\
  2. if (_script_instance) {\\
  3. Callable::CallError ce;\\
  4. $CALLSIARGS\\
  5. $CALLSIBEGIN_script_instance->callp(_gdvirtual_##$VARNAME##_sn, $CALLSIARGPASS, ce);\\
  6. if (ce.error == Callable::CallError::CALL_OK) {\\
  7. $CALLSIRET\\
  8. return true;\\
  9. }\\
  10. }"""
  11. script_has_method = """ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\
  12. if (_script_instance && _script_instance->has_method(_gdvirtual_##$VARNAME##_sn)) {\\
  13. return true;\\
  14. }"""
  15. proto = """#define GDVIRTUAL$VER($ALIAS $RET m_name $ARG)\\
  16. StringName _gdvirtual_##$VARNAME##_sn = #m_name;\\
  17. mutable bool _gdvirtual_##$VARNAME##_initialized = false;\\
  18. mutable void *_gdvirtual_##$VARNAME = nullptr;\\
  19. _FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_call($CALLARGS) $CONST {\\
  20. $SCRIPTCALL\\
  21. if (unlikely(_get_extension() && !_gdvirtual_##$VARNAME##_initialized)) {\\
  22. MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
  23. uint32_t hash = mi.get_compatibility_hash();\\
  24. _gdvirtual_##$VARNAME = nullptr;\\
  25. if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
  26. _gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
  27. } else if (_get_extension()->get_virtual2) {\\
  28. _gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
  29. }\\
  30. _GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
  31. _GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_initialized);\\
  32. _gdvirtual_##$VARNAME##_initialized = true;\\
  33. }\\
  34. if (_gdvirtual_##$VARNAME) {\\
  35. $CALLPTRARGS\\
  36. $CALLPTRRETDEF\\
  37. if (_get_extension()->call_virtual_with_data) {\\
  38. _get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##$VARNAME##_sn, _gdvirtual_##$VARNAME, $CALLPTRARGPASS, $CALLPTRRETPASS);\\
  39. $CALLPTRRET\\
  40. } else {\\
  41. ((GDExtensionClassCallVirtual)_gdvirtual_##$VARNAME)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\
  42. $CALLPTRRET\\
  43. }\\
  44. return true;\\
  45. }\\
  46. $REQCHECK\\
  47. $RVOID\\
  48. return false;\\
  49. }\\
  50. _FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_overridden() const {\\
  51. $SCRIPTHASMETHOD\\
  52. if (unlikely(_get_extension() && !_gdvirtual_##$VARNAME##_initialized)) {\\
  53. MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
  54. uint32_t hash = mi.get_compatibility_hash();\\
  55. _gdvirtual_##$VARNAME = nullptr;\\
  56. if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
  57. _gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
  58. } else if (_get_extension()->get_virtual2) {\\
  59. _gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
  60. }\\
  61. _GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
  62. _GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_initialized);\\
  63. _gdvirtual_##$VARNAME##_initialized = true;\\
  64. }\\
  65. if (_gdvirtual_##$VARNAME) {\\
  66. return true;\\
  67. }\\
  68. return false;\\
  69. }\\
  70. _FORCE_INLINE_ static MethodInfo _gdvirtual_##$VARNAME##_get_method_info() {\\
  71. MethodInfo method_info;\\
  72. method_info.name = #m_name;\\
  73. method_info.flags = $METHOD_FLAGS;\\
  74. $FILL_METHOD_INFO\\
  75. return method_info;\\
  76. }
  77. """
  78. def generate_version(argcount, const=False, returns=False, required=False, compat=False):
  79. s = proto
  80. if compat:
  81. s = s.replace("$SCRIPTCALL", "")
  82. s = s.replace("$SCRIPTHASMETHOD", "")
  83. else:
  84. s = s.replace("$SCRIPTCALL", script_call)
  85. s = s.replace("$SCRIPTHASMETHOD", script_has_method)
  86. sproto = str(argcount)
  87. method_info = ""
  88. method_flags = "METHOD_FLAG_VIRTUAL"
  89. if returns:
  90. sproto += "R"
  91. s = s.replace("$RET", "m_ret,")
  92. s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors
  93. s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;")
  94. method_info += "method_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
  95. method_info += "\t\tmethod_info.return_val_metadata = GetTypeInfo<m_ret>::METADATA;"
  96. else:
  97. s = s.replace("$RET ", "")
  98. s = s.replace("\t\t$RVOID\\\n", "")
  99. s = s.replace("\t\t\t$CALLPTRRETDEF\\\n", "")
  100. if const:
  101. sproto += "C"
  102. method_flags += " | METHOD_FLAG_CONST"
  103. s = s.replace("$CONST", "const")
  104. else:
  105. s = s.replace("$CONST ", "")
  106. if required:
  107. sproto += "_REQUIRED"
  108. method_flags += " | METHOD_FLAG_VIRTUAL_REQUIRED"
  109. s = s.replace(
  110. "$REQCHECK",
  111. 'ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");',
  112. )
  113. else:
  114. s = s.replace("\t\t$REQCHECK\\\n", "")
  115. if compat:
  116. sproto += "_COMPAT"
  117. s = s.replace("$COMPAT", "true")
  118. s = s.replace("$ALIAS", "m_alias,")
  119. s = s.replace("$VARNAME", "m_alias")
  120. else:
  121. s = s.replace("$COMPAT", "false")
  122. s = s.replace("$ALIAS ", "")
  123. s = s.replace("$VARNAME", "m_name")
  124. s = s.replace("$METHOD_FLAGS", method_flags)
  125. s = s.replace("$VER", sproto)
  126. argtext = ""
  127. callargtext = ""
  128. callsiargs = ""
  129. callsiargptrs = ""
  130. callptrargsptr = ""
  131. if argcount > 0:
  132. argtext += ", "
  133. callsiargs = f"Variant vargs[{argcount}] = {{ "
  134. callsiargptrs = f"\t\t\tconst Variant *vargptrs[{argcount}] = {{ "
  135. callptrargsptr = f"\t\t\tGDExtensionConstTypePtr argptrs[{argcount}] = {{ "
  136. callptrargs = ""
  137. for i in range(argcount):
  138. if i > 0:
  139. argtext += ", "
  140. callargtext += ", "
  141. callsiargs += ", "
  142. callsiargptrs += ", "
  143. callptrargs += "\t\t\t"
  144. callptrargsptr += ", "
  145. argtext += f"m_type{i + 1}"
  146. callargtext += f"m_type{i + 1} arg{i + 1}"
  147. callsiargs += f"arg{i + 1}"
  148. callsiargptrs += f"&vargs[{i}]"
  149. callptrargs += (
  150. f"PtrToArg<m_type{i + 1}>::EncodeT argval{i + 1} = (PtrToArg<m_type{i + 1}>::EncodeT)arg{i + 1};\\\n"
  151. )
  152. callptrargsptr += f"&argval{i + 1}"
  153. if method_info:
  154. method_info += "\\\n\t\t"
  155. method_info += f"method_info.arguments.push_back(GetTypeInfo<m_type{i + 1}>::get_class_info());\\\n"
  156. method_info += f"\t\tmethod_info.arguments_metadata.push_back(GetTypeInfo<m_type{i + 1}>::METADATA);"
  157. if argcount:
  158. callsiargs += " };\\\n"
  159. callsiargptrs += " };"
  160. s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs)
  161. s = s.replace("$CALLSIARGPASS", f"(const Variant **)vargptrs, {argcount}")
  162. callptrargsptr += " };"
  163. s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr)
  164. s = s.replace("$CALLPTRARGPASS", "reinterpret_cast<GDExtensionConstTypePtr *>(argptrs)")
  165. else:
  166. s = s.replace("\t\t\t$CALLSIARGS\\\n", "")
  167. s = s.replace("$CALLSIARGPASS", "nullptr, 0")
  168. s = s.replace("\t\t\t$CALLPTRARGS\\\n", "")
  169. s = s.replace("$CALLPTRARGPASS", "nullptr")
  170. if returns:
  171. if argcount > 0:
  172. callargtext += ", "
  173. callargtext += "m_ret &r_ret"
  174. s = s.replace("$CALLSIBEGIN", "Variant ret = ")
  175. s = s.replace("$CALLSIRET", "r_ret = VariantCaster<m_ret>::cast(ret);")
  176. s = s.replace("$CALLPTRRETPASS", "&ret")
  177. s = s.replace("$CALLPTRRET", "r_ret = (m_ret)ret;")
  178. else:
  179. s = s.replace("$CALLSIBEGIN", "")
  180. s = s.replace("\t\t\t\t$CALLSIRET\\\n", "")
  181. s = s.replace("$CALLPTRRETPASS", "nullptr")
  182. s = s.replace("\t\t\t\t$CALLPTRRET\\\n", "")
  183. s = s.replace(" $ARG", argtext)
  184. s = s.replace("$CALLARGS", callargtext)
  185. if method_info:
  186. s = s.replace("$FILL_METHOD_INFO", method_info)
  187. else:
  188. s = s.replace("\t\t$FILL_METHOD_INFO\\\n", method_info)
  189. return s
  190. def run(target, source, env):
  191. max_versions = 12
  192. txt = """/* THIS FILE IS GENERATED DO NOT EDIT */
  193. #ifndef GDVIRTUAL_GEN_H
  194. #define GDVIRTUAL_GEN_H
  195. #include "core/object/script_instance.h"
  196. #include <utility>
  197. #ifdef TOOLS_ENABLED
  198. #define _GDVIRTUAL_TRACK(m_virtual, m_initialized)\\
  199. if (_get_extension()->reloadable) {\\
  200. VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);\\
  201. tracker->method = (void **)&m_virtual;\\
  202. tracker->initialized = &m_initialized;\\
  203. tracker->next = virtual_method_list;\\
  204. virtual_method_list = tracker;\\
  205. }
  206. #else
  207. #define _GDVIRTUAL_TRACK(m_virtual, m_initialized)
  208. #endif
  209. #ifndef DISABLE_DEPRECATED
  210. #define _GDVIRTUAL_GET_DEPRECATED(m_virtual, m_name_sn, m_compat)\\
  211. else if (m_compat || ClassDB::get_virtual_method_compatibility_hashes(get_class_static(), m_name_sn).size() == 0) {\\
  212. if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\
  213. m_virtual = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &m_name_sn);\\
  214. } else if (_get_extension()->get_virtual) {\\
  215. m_virtual = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &m_name_sn);\\
  216. }\\
  217. }
  218. #else
  219. #define _GDVIRTUAL_GET_DEPRECATED(m_name, m_name_sn, m_compat)
  220. #endif
  221. """
  222. for i in range(max_versions + 1):
  223. txt += f"/* {i} Arguments */\n\n"
  224. txt += generate_version(i, False, False)
  225. txt += generate_version(i, False, True)
  226. txt += generate_version(i, True, False)
  227. txt += generate_version(i, True, True)
  228. txt += generate_version(i, False, False, True)
  229. txt += generate_version(i, False, True, True)
  230. txt += generate_version(i, True, False, True)
  231. txt += generate_version(i, True, True, True)
  232. txt += generate_version(i, False, False, False, True)
  233. txt += generate_version(i, False, True, False, True)
  234. txt += generate_version(i, True, False, False, True)
  235. txt += generate_version(i, True, True, False, True)
  236. txt += "#endif // GDVIRTUAL_GEN_H\n"
  237. with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
  238. f.write(txt)