浏览代码

Test that internal classes work as expected

David Snopek 1 月之前
父节点
当前提交
309b17b6eb

+ 18 - 0
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

+ 2 - 2
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();

+ 1 - 1
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;

+ 2 - 2
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);

+ 7 - 0
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")

+ 16 - 0
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<RefCounted> Example::test_get_internal_class() const {
+	Ref<ExampleInternal> 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;
+}

+ 14 - 0
test/src/example.h

@@ -29,6 +29,8 @@
 
 using namespace godot;
 
+class ExampleInternal;
+
 class ExampleRef : public RefCounted {
 	GDCLASS(ExampleRef, RefCounted);
 
@@ -203,6 +205,8 @@ public:
 	String test_use_engine_singleton() const;
 
 	static String test_library_path();
+
+	Ref<RefCounted> test_get_internal_class() const;
 };
 
 VARIANT_ENUM_CAST(Example::Constants);
@@ -288,3 +292,13 @@ protected:
 public:
 	String get_the_word() const;
 };
+
+class ExampleInternal : public RefCounted {
+	GDCLASS(ExampleInternal, RefCounted);
+
+protected:
+	static void _bind_methods();
+
+public:
+	int get_the_answer() const;
+};

+ 1 - 0
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) {