Chris Cranford 2024-01-15 23:41:37 +00:00 committed by GitHub
commit 04c46ac573
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 13 deletions

View File

@ -42,6 +42,8 @@
namespace godot { namespace godot {
class ClassDB; class ClassDB;
template <class T>
class ClassCreator;
typedef void GodotObject; typedef void GodotObject;
@ -49,6 +51,8 @@ typedef void GodotObject;
class Wrapped { class Wrapped {
friend class GDExtensionBinding; friend class GDExtensionBinding;
friend void postinitialize_handler(Wrapped *); friend void postinitialize_handler(Wrapped *);
template <class T>
friend class ClassCreator;
protected: protected:
#ifdef HOT_RELOAD_ENABLED #ifdef HOT_RELOAD_ENABLED
@ -132,16 +136,41 @@ struct EngineClassRegistration {
} // namespace godot } // namespace godot
#ifdef HOT_RELOAD_ENABLED #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)); \ m_class *new_instance = (m_class *)memalloc(sizeof(m_class)); \
Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; \ Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; \
Wrapped::recreate_instance = &recreate_data; \ Wrapped::recreate_instance = &recreate_data; \
memnew_placement(new_instance, m_class); \ memnew_placement(new_instance, m_class); \
return new_instance; return new_instance;
#else #else
#define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr; #define _GDCLASS_RECREATE(m_class) return nullptr;
#endif #endif
namespace godot {
template <class T>
class ClassCreator {
public:
static GDExtensionObjectPtr create(void *data) {
if constexpr (!std::is_abstract_v<T>) {
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<T>) {
_GDCLASS_RECREATE(T)
} else {
return nullptr;
}
}
};
} // namespace godot
// Use this on top of your own classes. // 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 // 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 // every line of the macro different
@ -226,15 +255,6 @@ public:
return m_inherits::get_class_static(); \ 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) { \ static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
if (p_instance && m_class::_get_notification()) { \ if (p_instance && m_class::_get_notification()) { \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \ if (m_class::_get_notification() != m_inherits::_get_notification()) { \

View File

@ -202,9 +202,9 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
T::to_string_bind, // GDExtensionClassToString to_string_func; T::to_string_bind, // GDExtensionClassToString to_string_func;
nullptr, // GDExtensionClassReference reference_func; nullptr, // GDExtensionClassReference reference_func;
nullptr, // GDExtensionClassUnreference unreference_func; nullptr, // GDExtensionClassUnreference unreference_func;
T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ ClassCreator<T>::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */ T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
T::recreate, // GDExtensionClassRecreateInstance recreate_instance_func; ClassCreator<T>::recreate, // GDExtensionClassRecreateInstance recreate_instance_func;
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func; &ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func; nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func; nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;

View File

@ -205,4 +205,22 @@ protected:
static void _bind_methods() {} static void _bind_methods() {}
}; };
class ExamplePureVirtualBase : public Object {
GDCLASS(ExamplePureVirtualBase, Object);
protected:
static void _bind_methods() {}
virtual int test_function() = 0;
};
class ExamplePureVirtual : public ExamplePureVirtualBase {
GDCLASS(ExamplePureVirtual, ExamplePureVirtualBase);
protected:
static void _bind_methods() {}
int test_function() override { return 25; }
};
#endif // EXAMPLE_CLASS_H #endif // EXAMPLE_CLASS_H

View File

@ -26,6 +26,9 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<Example>(); ClassDB::register_class<Example>();
ClassDB::register_class<ExampleVirtual>(true); ClassDB::register_class<ExampleVirtual>(true);
ClassDB::register_abstract_class<ExampleAbstract>(); ClassDB::register_abstract_class<ExampleAbstract>();
GDREGISTER_VIRTUAL_CLASS(ExamplePureVirtualBase);
GDREGISTER_CLASS(ExamplePureVirtual);
} }
void uninitialize_example_module(ModuleInitializationLevel p_level) { void uninitialize_example_module(ModuleInitializationLevel p_level) {