From aef0f1e24828a94cc3e0c7e4b8ac6ffc6425b202 Mon Sep 17 00:00:00 2001 From: George Marques Date: Thu, 9 Sep 2021 21:47:45 -0300 Subject: [PATCH] Change initialization to allow custom level callbacks Now it needs a callback for each level so custom logic (like loading singletons) can be performed. --- include/godot_cpp/core/class_db.hpp | 10 ++- include/godot_cpp/godot.hpp | 35 +++++++++ src/core/class_db.cpp | 1 + src/godot.cpp | 110 +++++++++++++++++++++++++++- test/src/register_types.cpp | 9 +-- 5 files changed, 153 insertions(+), 12 deletions(-) diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index e569661..23c2cc8 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -63,6 +63,10 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, Args... args) } class ClassDB { + static GDNativeInitializationLevel current_level; + + friend class godot::GDExtensionBinding; + public: struct PropertySetGet { int index; @@ -98,7 +102,7 @@ private: public: template - static void register_class(GDNativeInitializationLevel p_level = GDNATIVE_INITIALIZATION_SCENE); + static void register_class(); template static MethodBind *bind_method(N p_method_name, M p_method); @@ -132,11 +136,11 @@ public: } template -void ClassDB::register_class(GDNativeInitializationLevel p_level) { +void ClassDB::register_class() { ClassInfo cl; cl.name = T::get_class_static(); cl.parent_name = T::get_parent_class_static(); - cl.level = p_level; + cl.level = current_level; cl.constructor = T::create; cl.destructor = T::free; cl.object_instance = T::set_object_instance; diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index f2bdf73..eedc1c5 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -45,12 +45,47 @@ extern "C" void *token; class GDExtensionBinding { public: + using Callback = void (*)(); + + static Callback core_init; + static Callback server_init; + static Callback scene_init; + static Callback editor_init; + static Callback core_terminate; + static Callback server_terminate; + static Callback scene_terminate; + static Callback editor_terminate; static GDNativeBool init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization); + +public: static void initialize_level(void *userdata, GDNativeInitializationLevel p_level); static void deinitialize_level(void *userdata, GDNativeInitializationLevel p_level); static void *create_instance_callback(void *p_token, void *p_instance); static void free_instance_callback(void *p_token, void *p_instance, void *p_binding); + + class InitObject { + const GDNativeInterface *interface; + const GDNativeExtensionClassLibraryPtr library; + GDNativeInitialization *initialization; + + public: + InitObject(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) : + interface(p_interface), + library(p_library), + initialization(r_initialization) {} + + void register_core_initializer(Callback p_core_init) const; + void register_server_initializer(Callback p_server_init) const; + void register_scene_initializer(Callback p_scene_init) const; + void register_editor_initializer(Callback p_editor_init) const; + void register_core_terminator(Callback p_core_terminate) const; + void register_server_terminator(Callback p_server_terminate) const; + void register_scene_terminator(Callback p_scene_terminate) const; + void register_editor_terminator(Callback p_editor_terminate) const; + + GDNativeBool init() const; + }; }; } // namespace godot diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp index 57e77c3..a1265da 100644 --- a/src/core/class_db.cpp +++ b/src/core/class_db.cpp @@ -40,6 +40,7 @@ namespace godot { std::unordered_map ClassDB::classes; +GDNativeInitializationLevel ClassDB::current_level = GDNATIVE_INITIALIZATION_CORE; MethodDefinition D_METHOD(const char *p_name) { return MethodDefinition(p_name); diff --git a/src/godot.cpp b/src/godot.cpp index 309c596..fa45b19 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -41,12 +41,21 @@ namespace godot { namespace internal { -const GDNativeInterface *interface; -GDNativeExtensionClassLibraryPtr library; -void *token; +const GDNativeInterface *interface = nullptr; +GDNativeExtensionClassLibraryPtr library = nullptr; +void *token = nullptr; } // namespace internal +GDExtensionBinding::Callback GDExtensionBinding::core_init = nullptr; +GDExtensionBinding::Callback GDExtensionBinding::server_init = nullptr; +GDExtensionBinding::Callback GDExtensionBinding::scene_init = nullptr; +GDExtensionBinding::Callback GDExtensionBinding::editor_init = nullptr; +GDExtensionBinding::Callback GDExtensionBinding::core_terminate = nullptr; +GDExtensionBinding::Callback GDExtensionBinding::server_terminate = nullptr; +GDExtensionBinding::Callback GDExtensionBinding::scene_terminate = nullptr; +GDExtensionBinding::Callback GDExtensionBinding::editor_terminate = nullptr; + GDNativeBool GDExtensionBinding::init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) { internal::interface = p_interface; internal::library = p_library; @@ -54,7 +63,18 @@ GDNativeBool GDExtensionBinding::init(const GDNativeInterface *p_interface, cons r_initialization->initialize = initialize_level; r_initialization->deinitialize = deinitialize_level; - r_initialization->minimum_initialization_level = GDNATIVE_INITIALIZATION_CORE; + + if (core_init) { + r_initialization->minimum_initialization_level = GDNATIVE_INITIALIZATION_CORE; + } else if (server_init) { + r_initialization->minimum_initialization_level = GDNATIVE_INITIALIZATION_SERVERS; + } else if (scene_init) { + r_initialization->minimum_initialization_level = GDNATIVE_INITIALIZATION_SCENE; + } else if (editor_init) { + r_initialization->minimum_initialization_level = GDNATIVE_INITIALIZATION_EDITOR; + } else { + ERR_FAIL_V_MSG(false, "At least one initialization callback must be defined."); + } Variant::init_bindings(); @@ -62,11 +82,57 @@ GDNativeBool GDExtensionBinding::init(const GDNativeInterface *p_interface, cons } void GDExtensionBinding::initialize_level(void *userdata, GDNativeInitializationLevel p_level) { + ClassDB::current_level = p_level; + switch (p_level) { + case GDNATIVE_INITIALIZATION_CORE: + if (core_init) { + core_init(); + } + break; + case GDNATIVE_INITIALIZATION_SERVERS: + if (server_init) { + server_init(); + } + break; + case GDNATIVE_INITIALIZATION_SCENE: + if (scene_init) { + scene_init(); + } + break; + case GDNATIVE_INITIALIZATION_EDITOR: + if (editor_init) { + editor_init(); + } + break; + } ClassDB::initialize(p_level); } void GDExtensionBinding::deinitialize_level(void *userdata, GDNativeInitializationLevel p_level) { + ClassDB::current_level = p_level; ClassDB::deinitialize(p_level); + switch (p_level) { + case GDNATIVE_INITIALIZATION_CORE: + if (core_terminate) { + core_terminate(); + } + break; + case GDNATIVE_INITIALIZATION_SERVERS: + if (server_terminate) { + server_terminate(); + } + break; + case GDNATIVE_INITIALIZATION_SCENE: + if (scene_terminate) { + scene_terminate(); + } + break; + case GDNATIVE_INITIALIZATION_EDITOR: + if (editor_terminate) { + editor_terminate(); + } + break; + } } void *GDExtensionBinding::create_instance_callback(void *p_token, void *p_instance) { @@ -80,6 +146,42 @@ void GDExtensionBinding::free_instance_callback(void *p_token, void *p_instance, memdelete((Wrapped *)p_binding); } +void GDExtensionBinding::InitObject::register_core_initializer(Callback p_core_init) const { + GDExtensionBinding::core_init = p_core_init; +} + +void GDExtensionBinding::InitObject::register_server_initializer(Callback p_server_init) const { + GDExtensionBinding::server_init = p_server_init; +} + +void GDExtensionBinding::InitObject::register_scene_initializer(Callback p_scene_init) const { + GDExtensionBinding::scene_init = p_scene_init; +} + +void GDExtensionBinding::InitObject::register_editor_initializer(Callback p_editor_init) const { + GDExtensionBinding::editor_init = p_editor_init; +} + +void GDExtensionBinding::InitObject::register_core_terminator(Callback p_core_terminate) const { + GDExtensionBinding::core_terminate = p_core_terminate; +} + +void GDExtensionBinding::InitObject::register_server_terminator(Callback p_server_terminate) const { + GDExtensionBinding::server_terminate = p_server_terminate; +} + +void GDExtensionBinding::InitObject::register_scene_terminator(Callback p_scene_terminate) const { + GDExtensionBinding::scene_terminate = p_scene_terminate; +} + +void GDExtensionBinding::InitObject::register_editor_terminator(Callback p_editor_terminate) const { + GDExtensionBinding::editor_terminate = p_editor_terminate; +} + +GDNativeBool GDExtensionBinding::InitObject::init() const { + return GDExtensionBinding::init(interface, library, initialization); +} + } // namespace godot extern "C" { diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index f2d8c77..35f2693 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -51,12 +51,11 @@ extern "C" { // Initialization. GDNativeBool GDN_EXPORT example_library_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) { - GDNativeBool result = godot::GDExtensionBinding::init(p_interface, p_library, r_initialization); + godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization); - if (result) { - register_example_types(); - } + init_obj.register_scene_initializer(register_example_types); + init_obj.register_scene_terminator(unregister_example_types); - return result; + return init_obj.init(); } }