make_virtuals.py 8.2 KB

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