diff --git a/SConstruct b/SConstruct index 2ccfbbb3..d56d0495 100644 --- a/SConstruct +++ b/SConstruct @@ -458,6 +458,7 @@ if should_generate_bindings: # Sources to compile sources = [] add_sources(sources, "src", "cpp") +add_sources(sources, "src/classes", "cpp") add_sources(sources, "src/core", "cpp") add_sources(sources, "src/variant", "cpp") add_sources(sources, "gen/src/variant", "cpp") diff --git a/binding_generator.py b/binding_generator.py index 6d50292f..753d6799 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -914,9 +914,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append("") result.append("public:") - - # Constructor override, since parent Wrapped has protected constructor. - result.append(f"\t{class_name}() = default;") result.append("") if "enums" in class_api: diff --git a/godot-headers b/godot-headers index cfc1909e..68e989fc 160000 --- a/godot-headers +++ b/godot-headers @@ -1 +1 @@ -Subproject commit cfc1909edf55f21a8822dd088172dcf6c349a1d0 +Subproject commit 68e989fce33a14fdd9e10c8adc88ae3c9b3aae85 diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index c131f7bf..80a9ef19 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -34,6 +34,7 @@ #include #include + namespace godot { typedef void GodotObject; @@ -41,46 +42,22 @@ typedef void GodotObject; // Base for all engine classes, to contain the pointer to the engine instance. class Wrapped { friend class GDExtensionBinding; - - // Private constructor, this should not be created directly by users. - Wrapped(GodotObject *p_owner) : - _owner(p_owner) {} + friend void postinitialize_handler(Wrapped *); protected: - Wrapped() = default; + virtual const char *_get_class() const = 0; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned. + virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const = 0; + + void _postinitialize(); + + Wrapped(const char *p_godot_class); + Wrapped(GodotObject *p_godot_object); public: // Must be public but you should not touch this. GodotObject *_owner = nullptr; - - static Wrapped *_new() { - return nullptr; - } }; -namespace internal { - -template -struct Creator { - static T *_new() { return nullptr; } -}; - -template -struct Creator>::type> { - static T *_new() { return T::_new(); } -}; - -// template -// struct Creator { -// }; - -// template -// struct Creator, bool>> { -// static T *_new() { return T::_new(); } -// }; - -}; // namespace internal - } // namespace godot #ifdef DEBUG_ENABLED @@ -94,126 +71,126 @@ struct Creator>: #define CHECK_CLASS_CONSTRUCTOR(m_constructor, m_class) #endif -#define GDCLASS(m_class, m_inherits) \ -private: \ - friend class ClassDB; \ - \ - using SelfType = m_class; \ - \ -protected: \ - static void (*_get_bind_methods())() { \ - return &m_class::_bind_methods; \ - } \ - \ - template \ - static void register_virtuals() { \ - m_inherits::register_virtuals(); \ - } \ - \ -public: \ - static void initialize_class() { \ - static bool initialized = false; \ - if (initialized) { \ - return; \ - } \ - m_inherits::initialize_class(); \ - if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ - _bind_methods(); \ - m_inherits::register_virtuals(); \ - } \ - initialized = true; \ - } \ - \ - static const char *get_class_static() { \ - return #m_class; \ - } \ - \ - static const char *get_parent_class_static() { \ - return #m_inherits; \ - } \ - \ - static GDExtensionClassInstancePtr create(void *data) { \ - return reinterpret_cast(new ("") m_class); \ - } \ - \ - static void free(void *data, GDExtensionClassInstancePtr ptr) { \ - if (ptr) { \ - m_class *cls = reinterpret_cast(ptr); \ - cls->~m_class(); \ - ::godot::Memory::free_static(cls); \ - } \ - } \ - \ - static void set_object_instance(GDExtensionClassInstancePtr p_instance, GDNativeObjectPtr p_object_instance) { \ - godot::internal::gdn_interface->object_set_instance_binding(p_object_instance, godot::internal::token, p_instance, &m_class::___binding_callbacks); \ - reinterpret_cast(p_instance)->_owner = reinterpret_cast(p_object_instance); \ - } \ - \ - static void *___binding_create_callback(void *p_token, void *p_instance) { \ - return nullptr; \ - } \ - static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ - } \ - static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ - return true; \ - } \ - static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ - ___binding_create_callback, \ - ___binding_free_callback, \ - ___binding_reference_callback, \ - }; \ - \ - static m_class *_new() { \ - static GDNativeExtensionPtr ___extension = nullptr; \ - static GDNativeClassConstructor ___constructor = godot::internal::gdn_interface->classdb_get_constructor(#m_class, &___extension); \ - CHECK_CLASS_CONSTRUCTOR(___constructor, m_class); \ - GDNativeObjectPtr obj = godot::internal::gdn_interface->classdb_construct_object(___constructor, ___extension); \ - return reinterpret_cast(godot::internal::gdn_interface->object_get_instance_binding(obj, godot::internal::token, &m_class::___binding_callbacks)); \ - } \ - \ -private: +#define GDCLASS(m_class, m_inherits) \ +private: \ + void operator=(const m_class &p_rval) {} \ + friend class ClassDB; \ + \ + using SelfType = m_class; \ + \ +protected: \ + virtual const char *_get_class() const override { \ + return get_class_static(); \ + } \ + \ + virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const override { \ + return &___binding_callbacks; \ + } \ + \ + static void (*_get_bind_methods())() { \ + return &m_class::_bind_methods; \ + } \ + \ + template \ + static void register_virtuals() { \ + m_inherits::register_virtuals(); \ + } \ + \ +public: \ + static void initialize_class() { \ + static bool initialized = false; \ + if (initialized) { \ + return; \ + } \ + m_inherits::initialize_class(); \ + if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ + _bind_methods(); \ + m_inherits::register_virtuals(); \ + } \ + initialized = true; \ + } \ + \ + static const char *get_class_static() { \ + return #m_class; \ + } \ + \ + static const char *get_parent_class_static() { \ + return #m_inherits; \ + } \ + \ + static GDNativeObjectPtr create(void *data) { \ + m_class *new_object = memnew(m_class); \ + return new_object->_owner; \ + } \ + \ + static void free(void *data, GDExtensionClassInstancePtr ptr) { \ + if (ptr) { \ + m_class *cls = reinterpret_cast(ptr); \ + cls->~m_class(); \ + ::godot::Memory::free_static(cls); \ + } \ + } \ + \ + static void *___binding_create_callback(void *p_token, void *p_instance) { \ + return nullptr; \ + } \ + static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ + } \ + static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ + return true; \ + } \ + static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ + ___binding_create_callback, \ + ___binding_free_callback, \ + ___binding_reference_callback, \ + }; // Don't use this for your classes, use GDCLASS() instead. -#define GDNATIVE_CLASS(m_class, m_inherits) \ -protected: \ - static void (*_get_bind_methods())() { \ - return nullptr; \ - } \ - \ -public: \ - static void initialize_class() {} \ - \ - static const char *get_class_static() { \ - return #m_class; \ - } \ - \ - static const char *get_parent_class_static() { \ - return #m_inherits; \ - } \ - \ - static void *___binding_create_callback(void *p_token, void *p_instance) { \ - m_class *obj = new ("") m_class; \ - obj->_owner = (godot::GodotObject *)p_instance; \ - return obj; \ - } \ - static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ - Memory::free_static(reinterpret_cast(p_binding)); \ - } \ - static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ - return true; \ - } \ - static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ - ___binding_create_callback, \ - ___binding_free_callback, \ - ___binding_reference_callback, \ - }; \ - static m_class *_new() { \ - static GDNativeClassConstructor ___constructor = godot::internal::gdn_interface->classdb_get_constructor(#m_class, nullptr); \ - CHECK_CLASS_CONSTRUCTOR(___constructor, m_class); \ - GDNativeObjectPtr obj = ___constructor(); \ - return reinterpret_cast(godot::internal::gdn_interface->object_get_instance_binding(obj, godot::internal::token, &m_class::___binding_callbacks)); \ - } \ - \ -private: +#define GDNATIVE_CLASS(m_class, m_inherits) \ +private: \ + void operator=(const m_class &p_rval) {} \ + \ +protected: \ + virtual const char *_get_class() const override { \ + return get_class_static(); \ + } \ + \ + virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const override { \ + return &___binding_callbacks; \ + } \ + \ + m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \ + m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \ + \ + static void (*_get_bind_methods())() { \ + return nullptr; \ + } \ + \ +public: \ + static void initialize_class() {} \ + \ + static const char *get_class_static() { \ + return #m_class; \ + } \ + \ + static const char *get_parent_class_static() { \ + return #m_inherits; \ + } \ + \ + static void *___binding_create_callback(void *p_token, void *p_instance) { \ + return memnew(m_class((GodotObject *)p_instance)); \ + } \ + static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ + Memory::free_static(reinterpret_cast(p_binding)); \ + } \ + static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ + return true; \ + } \ + static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ + ___binding_create_callback, \ + ___binding_free_callback, \ + ___binding_reference_callback, \ + }; \ + m_class() : m_class(#m_class) {} #endif // ! GODOT_CPP_WRAPPED_HPP diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index f7233f3e..37bc1425 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -158,9 +158,8 @@ void ClassDB::register_class() { nullptr, // GDNativeExtensionClassUnreference T::create, // GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ T::free, // GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */ - T::set_object_instance, // GDNativeExtensionClassObjectInstance object_instance_func; /* this one is mandatory */ &ClassDB::get_virtual_func, // GDNativeExtensionClassGetVirtual get_virtual_func; - (void *)cl.name, //void *class_userdata; + (void *)cl.name, // void *class_userdata; }; internal::gdn_interface->classdb_register_extension_class(internal::library, cl.name, cl.parent_name, &class_info); diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp index 73af71f9..9431d4d2 100644 --- a/include/godot_cpp/core/memory.hpp +++ b/include/godot_cpp/core/memory.hpp @@ -68,16 +68,17 @@ public: static void free_static(void *p_ptr); }; -#define memnew(m_v) \ - ([&]() { \ - if constexpr (std::is_base_of::value) { \ - return godot::internal::Creator::_new(); \ - } else { \ - return new ("") m_v; \ - } \ - }()) +_ALWAYS_INLINE_ void postinitialize_handler(void *) {} -#define memnew_placement(m_placement, m_class) (new (m_placement, sizeof(m_class), "") m_class) +template +_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) { + postinitialize_handler(p_obj); + return p_obj; +} + +#define memnew(m_class) _post_initialize(new ("") m_class) + +#define memnew_placement(m_placement, m_class) _post_initialize(new (m_placement, sizeof(m_class), "") m_class) template void memdelete(T *p_class, typename std::enable_if>::type * = 0) { diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index 733892d7..5ece787d 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -55,9 +55,6 @@ 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 *gdn_interface; const GDNativeExtensionClassLibraryPtr library; diff --git a/src/classes/wrapped.cpp b/src/classes/wrapped.cpp new file mode 100644 index 00000000..527ee50f --- /dev/null +++ b/src/classes/wrapped.cpp @@ -0,0 +1,56 @@ +/*************************************************************************/ +/* wrapped.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include + +#include + +#include + +namespace godot { + +void Wrapped::_postinitialize() { + godot::internal::gdn_interface->object_set_instance(_owner, _get_class(), this); + godot::internal::gdn_interface->object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks()); +} + +Wrapped::Wrapped(const char *p_godot_class) { + _owner = godot::internal::gdn_interface->classdb_construct_object(p_godot_class); +} + +Wrapped::Wrapped(GodotObject *p_godot_object) { + _owner = p_godot_object; +} + +void postinitialize_handler(Wrapped *p_wrapped) { + p_wrapped->_postinitialize(); +} + +} // namespace godot diff --git a/src/godot.cpp b/src/godot.cpp index 542fed48..74906f39 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -91,17 +91,6 @@ void GDExtensionBinding::deinitialize_level(void *userdata, GDNativeInitializati } } -void *GDExtensionBinding::create_instance_callback(void *p_token, void *p_instance) { - ERR_FAIL_COND_V_MSG(p_token != internal::library, nullptr, "Asking for creating instance with invalid token."); - Wrapped *wrapped = memnew(Wrapped(p_instance)); - return wrapped; -} - -void GDExtensionBinding::free_instance_callback(void *p_token, void *p_instance, void *p_binding) { - ERR_FAIL_COND_MSG(p_token != internal::library, "Asking for freeing instance with invalid token."); - memdelete((Wrapped *)p_binding); -} - void GDExtensionBinding::InitObject::register_core_initializer(Callback p_core_init) const { GDExtensionBinding::init_callbacks[GDNATIVE_INITIALIZATION_CORE] = p_core_init; }