From 321c8d2b30256b4a1e42aa1afcefcb4c446246a7 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 | 42 ++++++++++++++++++++------- include/godot_cpp/core/class_db.hpp | 4 +-- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index f8f921b3..eea161c2 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -42,6 +42,8 @@ namespace godot { class ClassDB; +template +class ClassCreator; typedef void GodotObject; @@ -49,6 +51,8 @@ typedef void GodotObject; class Wrapped { friend class GDExtensionBinding; friend void postinitialize_handler(Wrapped *); + template + friend class ClassCreator; protected: #ifdef HOT_RELOAD_ENABLED @@ -132,16 +136,41 @@ struct EngineClassRegistration { } // namespace godot #ifdef HOT_RELOAD_ENABLED -#define _GDCLASS_RECREATE(m_class, m_inherits) \ +#define _GDCLASS_RECREATE(m_class) \ 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; +#define _GDCLASS_RECREATE(m_class) return nullptr; #endif +namespace godot { + +template +class ClassCreator { +public: + static GDExtensionObjectPtr create(void *data) { + if constexpr (!std::is_abstract_v) { + T *new_object = memnew(T); + return new_object->_owner; + } else { + return nullptr; + } + }; + + static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { + if constexpr (!std::is_abstract_v) { + _GDCLASS_RECREATE(T) + } else { + return nullptr; + } + } +}; + +} // namespace godot + // 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 +255,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()) { \ diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 4196a76b..8a8b7648 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -202,9 +202,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 */ + ClassCreator::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; + ClassCreator::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;