From b507b3e5913344a97e90ba27b221e28924f555ab Mon Sep 17 00:00:00 2001 From: David Snopek Date: Wed, 11 Oct 2023 22:59:59 -0500 Subject: [PATCH] Automatically register only engine classes whose header has been included --- binding_generator.py | 64 +------------------ .../classes/editor_plugin_registration.hpp | 62 ++++++++++++++++++ include/godot_cpp/classes/wrapped.hpp | 17 +++++ include/godot_cpp/core/class_db.hpp | 11 ++-- include/godot_cpp/godot.hpp | 3 - ...gin.cpp => editor_plugin_registration.cpp} | 6 +- src/classes/wrapped.cpp | 25 ++++++++ src/godot.cpp | 4 +- 8 files changed, 114 insertions(+), 78 deletions(-) create mode 100644 include/godot_cpp/classes/editor_plugin_registration.hpp rename src/classes/{editor_plugin.cpp => editor_plugin_registration.cpp} (95%) diff --git a/binding_generator.py b/binding_generator.py index 9c3284dfc..0ff238b67 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) @@ -1285,7 +1279,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append(f"#include ") if class_name == "EditorPlugin": - result.append("#include ") + result.append("#include ") if len(fully_used_classes) > 0: result.append("") @@ -1437,30 +1431,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append("};") result.append("") - if class_name == "EditorPlugin": - result.append("class EditorPlugins {") - result.append("private:") - result.append("\tstatic Vector plugin_classes;") - result.append("") - result.append("public:") - result.append("\tstatic void add_plugin_class(const StringName &p_class_name);") - result.append("\tstatic void remove_plugin_class(const StringName &p_class_name);") - result.append("\tstatic void deinitialize(GDExtensionInitializationLevel p_level);") - result.append("") - - result.append("\ttemplate ") - result.append("\tstatic void add_by_type() {") - result.append("\t\tadd_plugin_class(T::get_class_static());") - result.append("\t}") - - result.append("\ttemplate ") - result.append("\tstatic void remove_by_type() {") - result.append("\t\tremove_plugin_class(T::get_class_static());") - result.append("\t}") - - result.append("};") - result.append("") - result.append("} // namespace godot") result.append("") @@ -1685,38 +1655,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/editor_plugin_registration.hpp b/include/godot_cpp/classes/editor_plugin_registration.hpp new file mode 100644 index 000000000..1ccde314e --- /dev/null +++ b/include/godot_cpp/classes/editor_plugin_registration.hpp @@ -0,0 +1,62 @@ +/**************************************************************************/ +/* editor_plugin_registration.hpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef GODOT_EDITOR_PLUGIN_REGISTRATION_HPP +#define GODOT_EDITOR_PLUGIN_REGISTRATION_HPP + +#include + +namespace godot { + +class EditorPlugin; +class StringName; + +class EditorPlugins { +private: + static Vector plugin_classes; + +public: + static void add_plugin_class(const StringName &p_class_name); + static void remove_plugin_class(const StringName &p_class_name); + static void deinitialize(GDExtensionInitializationLevel p_level); + + template + static void add_by_type() { + add_plugin_class(T::get_class_static()); + } + template + static void remove_by_type() { + remove_plugin_class(T::get_class_static()); + } +}; + +} // namespace godot + +#endif // GODOT_EDITOR_PLUGIN_REGISTRATION_HPP diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 879346bf7..2bbffc021 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 @@ -352,6 +368,7 @@ public: // Don't use this for your classes, use GDCLASS() instead. #define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) \ private: \ + inline static ::godot::internal::EngineClassRegistration _gde_engine_class_registration_helper; \ void operator=(const m_class &p_rval) {} \ \ protected: \ diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index ef18c6e0e..17e093a7d 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 4561a75f1..507ca0297 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/editor_plugin.cpp b/src/classes/editor_plugin_registration.cpp similarity index 95% rename from src/classes/editor_plugin.cpp rename to src/classes/editor_plugin_registration.cpp index ca98a8925..99819bee8 100644 --- a/src/classes/editor_plugin.cpp +++ b/src/classes/editor_plugin_registration.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* editor_plugin.cpp */ +/* editor_plugin_registration.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include +#include -#include +#include namespace godot { diff --git a/src/classes/wrapped.cpp b/src/classes/wrapped.cpp index 5b425c711..37fcf65a6 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::vector &get_engine_class_registration_callbacks() { + static std::vector 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().push_back(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::vector &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 05413ff16..ebf440021 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -30,7 +30,7 @@ #include -#include +#include #include #include #include @@ -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; }