Browse Source

Rework GDCLASS macro to allow pure virtual functions

(cherry picked from commit 5f350e257214c490639682d0b601be859a3b4332)
Chris Cranford 1 year ago
parent
commit
dc76664cea

+ 1 - 28
include/godot_cpp/classes/wrapped.hpp

@@ -48,6 +48,7 @@ typedef void GodotObject;
 // Base for all engine classes, to contain the pointer to the engine instance.
 class Wrapped {
 	friend class GDExtensionBinding;
+	friend class ClassDB;
 	friend void postinitialize_handler(Wrapped *);
 
 protected:
@@ -131,17 +132,6 @@ struct EngineClassRegistration {
 
 } // namespace godot
 
-#ifdef HOT_RELOAD_ENABLED
-#define _GDCLASS_RECREATE(m_class, m_inherits)                                                   \
-	m_class *new_instance = (m_class *)memalloc(sizeof(m_class));                                \
-	Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; \
-	Wrapped::recreate_instance = &recreate_data;                                                 \
-	memnew_placement(new_instance, m_class);                                                     \
-	return new_instance;
-#else
-#define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr;
-#endif
-
 // Use this on top of your own classes.
 // Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
 // every line of the macro different
@@ -226,15 +216,6 @@ public:
 		return m_inherits::get_class_static();                                                                                                                                         \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \
-	static GDExtensionObjectPtr create(void *data) {                                                                                                                                   \
-		m_class *new_object = memnew(m_class);                                                                                                                                         \
-		return new_object->_owner;                                                                                                                                                     \
-	}                                                                                                                                                                                  \
-                                                                                                                                                                                       \
-	static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) {                                                                                                \
-		_GDCLASS_RECREATE(m_class, m_inherits);                                                                                                                                        \
-	}                                                                                                                                                                                  \
-                                                                                                                                                                                       \
 	static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {                                                                \
 		if (p_instance && m_class::_get_notification()) {                                                                                                                              \
 			if (m_class::_get_notification() != m_inherits::_get_notification()) {                                                                                                     \
@@ -437,14 +418,6 @@ public:
 		return m_inherits::get_class_static();                                                                                                                                         \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \
-	static GDExtensionObjectPtr create(void *data) {                                                                                                                                   \
-		return nullptr;                                                                                                                                                                \
-	}                                                                                                                                                                                  \
-                                                                                                                                                                                       \
-	static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) {                                                                                                \
-		return nullptr;                                                                                                                                                                \
-	}                                                                                                                                                                                  \
-                                                                                                                                                                                       \
 	static void free(void *data, GDExtensionClassInstancePtr ptr) {                                                                                                                    \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \

+ 29 - 2
include/godot_cpp/core/class_db.hpp

@@ -112,6 +112,33 @@ private:
 	template <class T, bool is_abstract>
 	static void _register_class(bool p_virtual = false, bool p_exposed = true);
 
+	template <class T>
+	static GDExtensionObjectPtr _create_instance_func(void *data) {
+		if constexpr (!std::is_abstract_v<T>) {
+			T *new_object = memnew(T);
+			return new_object->_owner;
+		} else {
+			return nullptr;
+		}
+	}
+
+	template <class T>
+	static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
+		if constexpr (!std::is_abstract_v<T>) {
+#ifdef HOT_RELOAD_ENABLED
+			T *new_instance = (T *)memalloc(sizeof(T));
+			Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance };
+			Wrapped::recreate_instance = &recreate_data;
+			memnew_placement(new_instance, T);
+			return new_instance;
+#else
+			return nullptr;
+#endif
+		} else {
+			return nullptr;
+		}
+	}
+
 public:
 	template <class T>
 	static void register_class(bool p_virtual = false);
@@ -202,9 +229,9 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
 		T::to_string_bind, // GDExtensionClassToString to_string_func;
 		nullptr, // GDExtensionClassReference reference_func;
 		nullptr, // GDExtensionClassUnreference unreference_func;
-		T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
+		&_create_instance_func<T>, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
 		T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
-		T::recreate, // GDExtensionClassRecreateInstance recreate_instance_func;
+		&_recreate_instance_func<T>, // GDExtensionClassRecreateInstance recreate_instance_func;
 		&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
 		nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
 		nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;

+ 13 - 2
test/src/example.h

@@ -198,11 +198,22 @@ protected:
 	static void _bind_methods() {}
 };
 
-class ExampleAbstract : public Object {
-	GDCLASS(ExampleAbstract, Object);
+class ExampleAbstractBase : public Object {
+	GDCLASS(ExampleAbstractBase, Object);
 
 protected:
 	static void _bind_methods() {}
+
+	virtual int test_function() = 0;
+};
+
+class ExampleConcrete : public ExampleAbstractBase {
+	GDCLASS(ExampleConcrete, ExampleAbstractBase);
+
+protected:
+	static void _bind_methods() {}
+
+	virtual int test_function() override { return 25; }
 };
 
 #endif // EXAMPLE_CLASS_H

+ 2 - 1
test/src/register_types.cpp

@@ -25,7 +25,8 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
 	ClassDB::register_class<ExampleMin>();
 	ClassDB::register_class<Example>();
 	ClassDB::register_class<ExampleVirtual>(true);
-	ClassDB::register_abstract_class<ExampleAbstract>();
+	ClassDB::register_abstract_class<ExampleAbstractBase>();
+	ClassDB::register_class<ExampleConcrete>();
 }
 
 void uninitialize_example_module(ModuleInitializationLevel p_level) {