From 097f698ff2140de6b84d020f95813f8f0dd4f64a Mon Sep 17 00:00:00 2001 From: Chris Cranford Date: Fri, 12 Jan 2024 15:25:56 -0500 Subject: [PATCH] Rework GDCLASS macro to allow pure virtual functions --- include/godot_cpp/classes/wrapped.hpp | 29 +------------------------ include/godot_cpp/core/class_db.hpp | 31 +++++++++++++++++++++++++-- test/src/example.h | 15 +++++++++++-- test/src/register_types.cpp | 3 ++- 4 files changed, 45 insertions(+), 33 deletions(-) diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index f8f921b3..32caf39b 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/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) { \ } \ \ diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 4196a76b..6a3b9ac0 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -112,6 +112,33 @@ private: template static void _register_class(bool p_virtual = false, bool p_exposed = true); + template + static GDExtensionObjectPtr create(void *data) { + if constexpr (!std::is_abstract_v) { + T *new_object = memnew(T); + return new_object->_owner; + } else { + return nullptr; + } + } + + template + static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { + if constexpr (!std::is_abstract_v) { +#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 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, // 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, // GDExtensionClassRecreateInstance recreate_instance_func; &ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func; nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func; nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func; diff --git a/test/src/example.h b/test/src/example.h index 72f6783d..c86a51fd 100644 --- a/test/src/example.h +++ b/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 diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index dbb37d90..58080d20 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -25,7 +25,8 @@ void initialize_example_module(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(true); - ClassDB::register_abstract_class(); + ClassDB::register_abstract_class(); + ClassDB::register_class(); } void uninitialize_example_module(ModuleInitializationLevel p_level) {