make_virtuals.py 7.8 KB

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