瀏覽代碼

Change initialization to allow custom level callbacks

Now it needs a callback for each level so custom logic (like loading
singletons) can be performed.
George Marques 3 年之前
父節點
當前提交
aef0f1e248
共有 5 個文件被更改,包括 153 次插入12 次删除
  1. 7 3
      include/godot_cpp/core/class_db.hpp
  2. 35 0
      include/godot_cpp/godot.hpp
  3. 1 0
      src/core/class_db.cpp
  4. 106 4
      src/godot.cpp
  5. 4 5
      test/src/register_types.cpp

+ 7 - 3
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 <class T>
-	static void register_class(GDNativeInitializationLevel p_level = GDNATIVE_INITIALIZATION_SCENE);
+	static void register_class();
 
 	template <class N, class M>
 	static MethodBind *bind_method(N p_method_name, M p_method);
@@ -132,11 +136,11 @@ public:
 	}
 
 template <class T>
-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;

+ 35 - 0
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

+ 1 - 0
src/core/class_db.cpp

@@ -40,6 +40,7 @@
 namespace godot {
 
 std::unordered_map<std::string, ClassDB::ClassInfo> ClassDB::classes;
+GDNativeInitializationLevel ClassDB::current_level = GDNATIVE_INITIALIZATION_CORE;
 
 MethodDefinition D_METHOD(const char *p_name) {
 	return MethodDefinition(p_name);

+ 106 - 4
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" {

+ 4 - 5
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();
 }
 }