diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 34849a671..0273c80a4 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -399,6 +399,8 @@ typedef struct { void *class_userdata; // Per-class user data, later accessible in instance bindings. } GDExtensionClassCreationInfo4; +typedef GDExtensionClassCreationInfo4 GDExtensionClassCreationInfo5; + typedef void *GDExtensionClassLibraryPtr; /* Passed a pointer to a PackedStringArray that should be filled with the classes that may be used by the GDExtension. */ @@ -2943,6 +2945,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionCl /** * @name classdb_register_extension_class4 * @since 4.4 + * @deprecated in Godot 4.5. Use `classdb_register_extension_class5` instead. * * Registers an extension class in the ClassDB. * @@ -2955,6 +2958,21 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionCl */ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass4)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo4 *p_extension_funcs); +/** + * @name classdb_register_extension_class5 + * @since 4.5 + * + * Registers an extension class in the ClassDB. + * + * Provided struct can be safely freed once the function returns. + * + * @param p_library A pointer the library received by the GDExtension's entry point function. + * @param p_class_name A pointer to a StringName with the class name. + * @param p_parent_class_name A pointer to a StringName with the parent class name. + * @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct. + */ +typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass5)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo5 *p_extension_funcs); + /** * @name classdb_register_extension_class_method * @since 4.1 diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 8092c0328..262dbecc1 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -252,7 +252,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) { class_register_order.push_back(cl.name); // Register this class with Godot - GDExtensionClassCreationInfo4 class_info = { + GDExtensionClassCreationInfo5 class_info = { p_virtual, // GDExtensionBool is_virtual; is_abstract, // GDExtensionBool is_abstract; p_exposed, // GDExtensionBool is_exposed; @@ -278,7 +278,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) { (void *)&T::get_class_static(), // void *class_userdata; }; - internal::gdextension_interface_classdb_register_extension_class4(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info); + internal::gdextension_interface_classdb_register_extension_class5(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info); // call bind_methods etc. to register all members of the class T::initialize_class(); diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index cf64b7e7d..e4b4337c1 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -185,7 +185,7 @@ extern "C" GDExtensionInterfaceObjectSetScriptInstance gdextension_interface_obj extern "C" GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2; extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind; extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag; -extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass4 gdextension_interface_classdb_register_extension_class4; +extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass5 gdextension_interface_classdb_register_extension_class5; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant; diff --git a/src/godot.cpp b/src/godot.cpp index dec614222..19a2a3b6f 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -192,7 +192,7 @@ GDExtensionInterfaceObjectSetScriptInstance gdextension_interface_object_set_scr GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2 = nullptr; GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr; GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr; -GDExtensionInterfaceClassdbRegisterExtensionClass4 gdextension_interface_classdb_register_extension_class4 = nullptr; +GDExtensionInterfaceClassdbRegisterExtensionClass5 gdextension_interface_classdb_register_extension_class5 = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr; @@ -477,7 +477,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(classdb_construct_object2, GDExtensionInterfaceClassdbConstructObject2); LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind); LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag); - LOAD_PROC_ADDRESS(classdb_register_extension_class4, GDExtensionInterfaceClassdbRegisterExtensionClass4); + LOAD_PROC_ADDRESS(classdb_register_extension_class5, GDExtensionInterfaceClassdbRegisterExtensionClass5); LOAD_PROC_ADDRESS(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod); LOAD_PROC_ADDRESS(classdb_register_extension_class_virtual_method, GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod); LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant); diff --git a/test/project/main.gd b/test/project/main.gd index 5ade71719..3d9ca7f34 100644 --- a/test/project/main.gd +++ b/test/project/main.gd @@ -287,6 +287,13 @@ func _ready(): assert_equal(library_path, ProjectSettings.globalize_path(library_path)) assert_equal(FileAccess.file_exists(library_path), true) + # Test that internal classes work as expected (at least for Godot 4.5+). + assert_equal(ClassDB.can_instantiate("ExampleInternal"), false) + assert_equal(ClassDB.instantiate("ExampleInternal"), null) + var internal_class = example.test_get_internal_class() + assert_equal(internal_class.get_the_answer(), 42) + assert_equal(internal_class.get_class(), "ExampleInternal") + # Test a class with a unicode name. var przykład = ExamplePrzykład.new() assert_equal(przykład.get_the_word(), "słowo to przykład") diff --git a/test/src/example.cpp b/test/src/example.cpp index 97915a0fd..9d3e62b91 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -252,6 +252,8 @@ void Example::_bind_methods() { ClassDB::bind_method(D_METHOD("test_use_engine_singleton"), &Example::test_use_engine_singleton); + ClassDB::bind_method(D_METHOD("test_get_internal_class"), &Example::test_get_internal_class); + ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static); ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2); @@ -744,6 +746,12 @@ String Example::test_library_path() { return library_path; } +Ref Example::test_get_internal_class() const { + Ref it; + it.instantiate(); + return it; +} + int64_t Example::test_get_internal(const Variant &p_input) const { if (p_input.get_type() != Variant::INT) { return -1; @@ -779,3 +787,11 @@ void ExamplePrzykład::_bind_methods() { String ExamplePrzykład::get_the_word() const { return U"słowo to przykład"; } + +void ExampleInternal::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_the_answer"), &ExampleInternal::get_the_answer); +} + +int ExampleInternal::get_the_answer() const { + return 42; +} diff --git a/test/src/example.h b/test/src/example.h index 22e9382bd..403d59f79 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -29,6 +29,8 @@ using namespace godot; +class ExampleInternal; + class ExampleRef : public RefCounted { GDCLASS(ExampleRef, RefCounted); @@ -203,6 +205,8 @@ class Example : public Control { String test_use_engine_singleton() const; static String test_library_path(); + + Ref test_get_internal_class() const; }; VARIANT_ENUM_CAST(Example::Constants); @@ -288,3 +292,13 @@ class ExamplePrzykład : public RefCounted { public: String get_the_word() const; }; + +class ExampleInternal : public RefCounted { + GDCLASS(ExampleInternal, RefCounted); + +protected: + static void _bind_methods(); + +public: + int get_the_answer() const; +}; diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index d9290c805..c68176d92 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -31,6 +31,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(ExampleChild); GDREGISTER_RUNTIME_CLASS(ExampleRuntime); GDREGISTER_CLASS(ExamplePrzykład); + GDREGISTER_INTERNAL_CLASS(ExampleInternal); } void uninitialize_example_module(ModuleInitializationLevel p_level) {