diff --git a/binding_generator.py b/binding_generator.py index 9c3284dfc0..937975d764 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -131,8 +131,6 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False): if sources: utility_functions_source_path = source_gen_folder / "variant" / "utility_functions.cpp" files.append(str(utility_functions_source_path.as_posix())) - register_engine_classes_source_path = source_gen_folder / "register_engine_classes.cpp" - files.append(str(register_engine_classes_source_path.as_posix())) return files @@ -1207,10 +1205,6 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): generate_engine_class_source(class_api, used_classes, fully_used_classes, use_template_get_node) ) - register_engine_classes_filename = Path(output_dir) / "src" / "register_engine_classes.cpp" - with register_engine_classes_filename.open("w+", encoding="utf-8") as source_file: - source_file.write(generate_register_engine_classes_source(api)) - for native_struct in api["native_structures"]: struct_name = native_struct["name"] snake_struct_name = camel_to_snake(struct_name) @@ -1437,6 +1431,13 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append("};") result.append("") + result.append("namespace {") + result.append( + f"\tinline static ::godot::internal::EngineClassRegistration<{class_name}> _gde_{snake_class_name.lower()}_registration_helper;" + ) + result.append("}") + result.append("") + if class_name == "EditorPlugin": result.append("class EditorPlugins {") result.append("private:") @@ -1685,38 +1686,6 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us return "\n".join(result) -def generate_register_engine_classes_source(api): - includes = [] - registrations = [] - - for class_api in api["classes"]: - if class_api["name"] == "ClassDB": - continue - - class_name = class_api["name"] - snake_class_name = camel_to_snake(class_name) - - includes.append(f"#include ") - registrations.append(f"\tClassDB::register_engine_class<{class_name}>();") - - result = [] - add_header(f"register_engine_classes.cpp", result) - - result.append("#include ") - result.append("") - result = result + includes - result.append("") - result.append("namespace godot {") - result.append("") - result.append("void GDExtensionBinding::register_engine_classes() {") - result = result + registrations - result.append("}") - result.append("") - result.append("} // namespace godot ") - - return "\n".join(result) - - def generate_global_constants(api, output_dir): include_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "classes" source_gen_folder = Path(output_dir) / "src" / "classes" diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 879346bf74..3534c192e4 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -111,6 +111,22 @@ namespace internal { GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size); void free_c_property_list(GDExtensionPropertyInfo *plist); +typedef void (*EngineClassRegistrationCallback)(); +void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback); +void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks); +void register_engine_classes(); + +template +struct EngineClassRegistration { + EngineClassRegistration() { + add_engine_class_registration_callback(&EngineClassRegistration::callback); + } + + static void callback() { + register_engine_class(T::get_class_static(), &T::_gde_binding_callbacks); + } +}; + } // namespace internal } // namespace godot diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index ef18c6e0e3..17e093a7d3 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -119,8 +119,10 @@ class ClassDB { static void register_abstract_class(); template static void register_internal_class(); - template - static void register_engine_class(); + + _FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) { + instance_binding_callbacks[p_name] = p_callbacks; + } template static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args); @@ -233,11 +235,6 @@ void ClassDB::register_internal_class() { ClassDB::_register_class(false, false); } -template -void ClassDB::register_engine_class() { - instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks; -} - template MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) { Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index 4561a75f1f..507ca0297e 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -196,9 +196,6 @@ enum ModuleInitializationLevel { }; class GDExtensionBinding { -private: - static void register_engine_classes(); - public: using Callback = void (*)(ModuleInitializationLevel p_level); diff --git a/src/classes/wrapped.cpp b/src/classes/wrapped.cpp index 5b425c7110..cad405a7e9 100644 --- a/src/classes/wrapped.cpp +++ b/src/classes/wrapped.cpp @@ -28,12 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#include + #include #include #include +#include + namespace godot { const StringName *Wrapped::_get_extension_class_name() const { @@ -81,6 +85,11 @@ void postinitialize_handler(Wrapped *p_wrapped) { namespace internal { +std::unordered_set &get_engine_class_registration_callbacks() { + static std::unordered_set engine_class_registration_callbacks; + return engine_class_registration_callbacks; +} + GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size) { GDExtensionPropertyInfo *plist = nullptr; // Linked list size can be expensive to get so we cache it @@ -106,6 +115,22 @@ void free_c_property_list(GDExtensionPropertyInfo *plist) { memfree(plist); } +void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback) { + get_engine_class_registration_callbacks().insert(p_callback); +} + +void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) { + ClassDB::_register_engine_class(p_name, p_callbacks); +} + +void register_engine_classes() { + std::unordered_set &engine_class_registration_callbacks = get_engine_class_registration_callbacks(); + for (EngineClassRegistrationCallback cb : engine_class_registration_callbacks) { + cb(); + } + engine_class_registration_callbacks.clear(); +} + } // namespace internal } // namespace godot diff --git a/src/godot.cpp b/src/godot.cpp index 05413ff160..b80696430d 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -416,7 +416,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge ERR_FAIL_NULL_V_MSG(init_callback, false, "Initialization callback must be defined."); Variant::init_bindings(); - register_engine_classes(); + godot::internal::register_engine_classes(); return true; }