diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 43931cc8cd..06d733bbf1 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -264,6 +264,7 @@ typedef void (*GDExtensionClassReference)(GDExtensionClassInstancePtr p_instance typedef void (*GDExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance); typedef void (*GDExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret); typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_userdata); +typedef GDExtensionClassInstancePtr (*GDExtensionClassRecreateInstance)(void *p_userdata, GDExtensionObjectPtr p_object); typedef void (*GDExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance); typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_userdata, GDExtensionConstStringNamePtr p_name); @@ -285,6 +286,7 @@ typedef struct { GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function. GDExtensionClassGetRID get_rid_func; void *class_userdata; // Per-class user data, later accessible in instance bindings. + GDExtensionClassRecreateInstance recreate_instance_func; } GDExtensionClassCreationInfo; typedef void *GDExtensionClassLibraryPtr; diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index f2efbd091e..a06e55bc09 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -113,6 +113,8 @@ private: friend class ::godot::ClassDB; \ \ protected: \ + m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \ + \ virtual const ::godot::StringName *_get_extension_class_name() const override { \ static ::godot::StringName string_name = get_class_static(); \ return &string_name; \ @@ -187,6 +189,11 @@ public: return new_object->_owner; \ } \ \ + static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { \ + m_class *new_instance = memnew(m_class((GodotObject *)obj)); \ + return new_instance; \ + } \ + \ static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \ 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 0802a45dcb..c1946e3474 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -192,6 +192,7 @@ void ClassDB::_register_class(bool p_virtual) { &ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func; nullptr, // GDExtensionClassGetRID get_rid; (void *)&T::get_class_static(), // void *class_userdata; + T::recreate, }; internal::gdextension_interface_classdb_register_extension_class(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info); diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp index 159c03142d..908404a17c 100644 --- a/src/core/class_db.cpp +++ b/src/core/class_db.cpp @@ -354,6 +354,9 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) { for (auto method : cl.method_map) { memdelete(method.second); } + + classes.erase(*i); + class_register_order.erase((i+1).base()); } } diff --git a/tools/linux.py b/tools/linux.py index 099a04847a..0219374ab5 100644 --- a/tools/linux.py +++ b/tools/linux.py @@ -14,6 +14,9 @@ def generate(env): if env["use_llvm"]: clang.generate(env) clangxx.generate(env) + else: + # Required for extensions to truly unload (for hot reloading). + env.Append(CXXFLAGS=["-fno-gnu-unique"]) env.Append(CCFLAGS=["-fPIC", "-Wwrite-strings"]) env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"])