From c4705a590b5eb01d63afb907d6dad5c49d8f6fe1 Mon Sep 17 00:00:00 2001 From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com> Date: Sat, 24 Jun 2023 03:07:22 +0200 Subject: [PATCH] Fix Object::notification order Previously the `p_reversed` parameter didn't influence the order in a correct way. Also script overridden _notification functions were not called in the correct order. To fix this some `notification` functions had to add a `p_reversed` parameter. This made it necessary to adjust cpp-bindings. Co-authored-by: David Snopek --- core/extension/gdextension.cpp | 44 ++++++++++- core/extension/gdextension.h | 10 +++ core/extension/gdextension_interface.cpp | 39 ++++++++++ core/extension/gdextension_interface.h | 99 +++++++++++++++++++++++- core/object/object.cpp | 28 +++++-- core/object/object.h | 3 + core/object/script_language.h | 4 +- core/object/script_language_extension.h | 15 +++- modules/gdscript/gdscript.cpp | 14 +++- modules/gdscript/gdscript.h | 2 +- modules/mono/csharp_script.cpp | 8 +- modules/mono/csharp_script.h | 4 +- scene/main/scene_tree.cpp | 2 +- tests/core/object/test_object.h | 70 ++++++++++++++++- 14 files changed, 314 insertions(+), 28 deletions(-) diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index e39a531d0d7..9674acb8941 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -281,7 +281,40 @@ public: } }; +#ifndef DISABLE_DEPRECATED void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) { + const GDExtensionClassCreationInfo2 class_info2 = { + p_extension_funcs->is_virtual, // GDExtensionBool is_virtual; + p_extension_funcs->is_abstract, // GDExtensionBool is_abstract; + p_extension_funcs->set_func, // GDExtensionClassSet set_func; + p_extension_funcs->get_func, // GDExtensionClassGet get_func; + p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func; + p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func; + p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func; + p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func; + nullptr, // GDExtensionClassNotification2 notification_func; + p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func; + p_extension_funcs->reference_func, // GDExtensionClassReference reference_func; + p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func; + p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ + p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */ + p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func; + p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid; + p_extension_funcs->class_userdata, // void *class_userdata; + }; + + const ClassCreationDeprecatedInfo legacy = { + p_extension_funcs->notification_func, + }; + _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info2, &legacy); +} +#endif // DISABLE_DEPRECATED + +void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs) { + _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, p_extension_funcs); +} + +void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs) { GDExtension *self = reinterpret_cast(p_library); StringName class_name = *reinterpret_cast(p_class_name); @@ -325,7 +358,12 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library extension->gdextension.free_property_list = p_extension_funcs->free_property_list_func; extension->gdextension.property_can_revert = p_extension_funcs->property_can_revert_func; extension->gdextension.property_get_revert = p_extension_funcs->property_get_revert_func; - extension->gdextension.notification = p_extension_funcs->notification_func; +#ifndef DISABLE_DEPRECATED + if (p_deprecated_funcs) { + extension->gdextension.notification = p_deprecated_funcs->notification_func; + } +#endif // DISABLE_DEPRECATED + extension->gdextension.notification2 = p_extension_funcs->notification_func; extension->gdextension.to_string = p_extension_funcs->to_string_func; extension->gdextension.reference = p_extension_funcs->reference_func; extension->gdextension.unreference = p_extension_funcs->unreference_func; @@ -337,6 +375,7 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library ClassDB::register_extension_class(&extension->gdextension); } + void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info) { GDExtension *self = reinterpret_cast(p_library); @@ -548,7 +587,10 @@ GDExtension::~GDExtension() { void GDExtension::initialize_gdextensions() { gdextension_setup_interface(); +#ifndef DISABLE_DEPRECATED register_interface_function("classdb_register_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class); +#endif // DISABLE_DEPRECATED + register_interface_function("classdb_register_extension_class2", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class2); register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method); register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant); register_interface_function("classdb_register_extension_class_property", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property); diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 5a0e39302b5..628cfae8c08 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -53,7 +53,17 @@ class GDExtension : public Resource { HashMap extension_classes; + struct ClassCreationDeprecatedInfo { +#ifndef DISABLE_DEPRECATED + GDExtensionClassNotification notification_func = nullptr; +#endif // DISABLE_DEPRECATED + }; + +#ifndef DISABLE_DEPRECATED static void _register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs); +#endif // DISABLE_DEPRECATED + static void _register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs); + static void _register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs = nullptr); static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info); static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield); static void _register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter); diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index a70ad5262f3..24517d71e46 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -1041,7 +1041,43 @@ static void gdextension_ref_set_object(GDExtensionRefPtr p_ref, GDExtensionObjec ref->reference_ptr(o); } +#ifndef DISABLE_DEPRECATED static GDExtensionScriptInstancePtr gdextension_script_instance_create(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data) { + const GDExtensionScriptInstanceInfo2 info_2 = { + p_info->set_func, + p_info->get_func, + p_info->get_property_list_func, + p_info->free_property_list_func, + p_info->property_can_revert_func, + p_info->property_get_revert_func, + p_info->get_owner_func, + p_info->get_property_state_func, + p_info->get_method_list_func, + p_info->free_method_list_func, + p_info->get_property_type_func, + p_info->has_method_func, + p_info->call_func, + nullptr, // notification_func. + p_info->to_string_func, + p_info->refcount_incremented_func, + p_info->refcount_decremented_func, + p_info->get_script_func, + p_info->is_placeholder_func, + p_info->set_fallback_func, + p_info->get_fallback_func, + p_info->get_language_func, + p_info->free_func, + }; + + ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension); + script_instance_extension->instance = p_instance_data; + script_instance_extension->native_info = &info_2; + script_instance_extension->deprecated_native_info.notification_func = p_info->notification_func; + return reinterpret_cast(script_instance_extension); +} +#endif // DISABLE_DEPRECATED + +static GDExtensionScriptInstancePtr gdextension_script_instance_create2(const GDExtensionScriptInstanceInfo2 *p_info, GDExtensionScriptInstanceDataPtr p_instance_data) { ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension); script_instance_extension->instance = p_instance_data; script_instance_extension->native_info = p_info; @@ -1269,7 +1305,10 @@ void gdextension_setup_interface() { REGISTER_INTERFACE_FUNC(object_get_instance_id); REGISTER_INTERFACE_FUNC(ref_get_object); REGISTER_INTERFACE_FUNC(ref_set_object); +#ifndef DISABLE_DEPRECATED REGISTER_INTERFACE_FUNC(script_instance_create); +#endif // DISABLE_DEPRECATED + REGISTER_INTERFACE_FUNC(script_instance_create2); REGISTER_INTERFACE_FUNC(placeholder_script_instance_create); REGISTER_INTERFACE_FUNC(placeholder_script_instance_update); REGISTER_INTERFACE_FUNC(object_get_script_instance); diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index a86abf2a7e3..e719d7337bf 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -258,7 +258,8 @@ typedef const GDExtensionPropertyInfo *(*GDExtensionClassGetPropertyList)(GDExte typedef void (*GDExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list); typedef GDExtensionBool (*GDExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name); typedef GDExtensionBool (*GDExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret); -typedef void (*GDExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what); +typedef void (*GDExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what); // Deprecated. Use GDExtensionClassNotification2 instead. +typedef void (*GDExtensionClassNotification2)(GDExtensionClassInstancePtr p_instance, int32_t p_what, bool p_reversed); typedef void (*GDExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr p_out); typedef void (*GDExtensionClassReference)(GDExtensionClassInstancePtr p_instance); typedef void (*GDExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance); @@ -285,7 +286,27 @@ 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. -} GDExtensionClassCreationInfo; +} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo2 instead. + +typedef struct { + GDExtensionBool is_virtual; + GDExtensionBool is_abstract; + GDExtensionClassSet set_func; + GDExtensionClassGet get_func; + GDExtensionClassGetPropertyList get_property_list_func; + GDExtensionClassFreePropertyList free_property_list_func; + GDExtensionClassPropertyCanRevert property_can_revert_func; + GDExtensionClassPropertyGetRevert property_get_revert_func; + GDExtensionClassNotification2 notification_func; + GDExtensionClassToString to_string_func; + GDExtensionClassReference reference_func; + GDExtensionClassUnreference unreference_func; + GDExtensionClassCreateInstance create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract. + GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory. + 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. +} GDExtensionClassCreationInfo2; typedef void *GDExtensionClassLibraryPtr; @@ -366,7 +387,8 @@ typedef void (*GDExtensionScriptInstanceFreeMethodList)(GDExtensionScriptInstanc typedef GDExtensionBool (*GDExtensionScriptInstanceHasMethod)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name); typedef void (*GDExtensionScriptInstanceCall)(GDExtensionScriptInstanceDataPtr p_self, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error); -typedef void (*GDExtensionScriptInstanceNotification)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what); +typedef void (*GDExtensionScriptInstanceNotification)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what); // Deprecated. Use GDExtensionScriptInstanceNotification2 instead. +typedef void (*GDExtensionScriptInstanceNotification2)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what, bool p_reversed); typedef void (*GDExtensionScriptInstanceToString)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out); typedef void (*GDExtensionScriptInstanceRefCountIncremented)(GDExtensionScriptInstanceDataPtr p_instance); @@ -420,7 +442,46 @@ typedef struct { GDExtensionScriptInstanceFree free_func; -} GDExtensionScriptInstanceInfo; +} GDExtensionScriptInstanceInfo; // Deprecated. Use GDExtensionScriptInstanceInfo2 instead. + +typedef struct { + GDExtensionScriptInstanceSet set_func; + GDExtensionScriptInstanceGet get_func; + GDExtensionScriptInstanceGetPropertyList get_property_list_func; + GDExtensionScriptInstanceFreePropertyList free_property_list_func; + + GDExtensionScriptInstancePropertyCanRevert property_can_revert_func; + GDExtensionScriptInstancePropertyGetRevert property_get_revert_func; + + GDExtensionScriptInstanceGetOwner get_owner_func; + GDExtensionScriptInstanceGetPropertyState get_property_state_func; + + GDExtensionScriptInstanceGetMethodList get_method_list_func; + GDExtensionScriptInstanceFreeMethodList free_method_list_func; + GDExtensionScriptInstanceGetPropertyType get_property_type_func; + + GDExtensionScriptInstanceHasMethod has_method_func; + + GDExtensionScriptInstanceCall call_func; + GDExtensionScriptInstanceNotification2 notification_func; + + GDExtensionScriptInstanceToString to_string_func; + + GDExtensionScriptInstanceRefCountIncremented refcount_incremented_func; + GDExtensionScriptInstanceRefCountDecremented refcount_decremented_func; + + GDExtensionScriptInstanceGetScript get_script_func; + + GDExtensionScriptInstanceIsPlaceholder is_placeholder_func; + + GDExtensionScriptInstanceSet set_fallback_func; + GDExtensionScriptInstanceGet get_fallback_func; + + GDExtensionScriptInstanceGetLanguage get_language_func; + + GDExtensionScriptInstanceFree free_func; + +} GDExtensionScriptInstanceInfo2; /* INITIALIZATION */ @@ -2116,6 +2177,7 @@ typedef void (*GDExtensionInterfaceRefSetObject)(GDExtensionRefPtr p_ref, GDExte /** * @name script_instance_create * @since 4.1 + * @deprecated in Godot 4.2. Use `script_instance_create2` instead. * * Creates a script instance that contains the given info and instance data. * @@ -2126,6 +2188,19 @@ typedef void (*GDExtensionInterfaceRefSetObject)(GDExtensionRefPtr p_ref, GDExte */ typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate)(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data); +/** + * @name script_instance_create2 + * @since 4.2 + * + * Creates a script instance that contains the given info and instance data. + * + * @param p_info A pointer to a GDExtensionScriptInstanceInfo2 struct. + * @param p_instance_data A pointer to a data representing the script instance in the GDExtension. This will be passed to all the function pointers on p_info. + * + * @return A pointer to a ScriptInstanceExtension object. + */ +typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate2)(const GDExtensionScriptInstanceInfo2 *p_info, GDExtensionScriptInstanceDataPtr p_instance_data); + /** * @name placeholder_script_instance_create * @since 4.2 @@ -2217,6 +2292,7 @@ typedef void *(*GDExtensionInterfaceClassdbGetClassTag)(GDExtensionConstStringNa /** * @name classdb_register_extension_class * @since 4.1 + * @deprecated in Godot 4.2. Use `classdb_register_extension_class2` instead. * * Registers an extension class in the ClassDB. * @@ -2229,6 +2305,21 @@ typedef void *(*GDExtensionInterfaceClassdbGetClassTag)(GDExtensionConstStringNa */ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs); +/** + * @name classdb_register_extension_class2 + * @since 4.2 + * + * 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 (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs); + /** * @name classdb_register_extension_class_method * @since 4.1 diff --git a/core/object/object.cpp b/core/object/object.cpp index b803d57cd9d..39f20a212f8 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -799,14 +799,30 @@ Variant Object::call_const(const StringName &p_method, const Variant **p_args, i } void Object::notification(int p_notification, bool p_reversed) { - _notificationv(p_notification, p_reversed); - - if (script_instance) { - script_instance->notification(p_notification); + if (p_reversed) { + if (script_instance) { + script_instance->notification(p_notification, p_reversed); + } + } else { + _notificationv(p_notification, p_reversed); } - if (_extension && _extension->notification) { - _extension->notification(_extension_instance, p_notification); + if (_extension) { + if (_extension->notification2) { + _extension->notification2(_extension_instance, p_notification, p_reversed); +#ifndef DISABLE_DEPRECATED + } else if (_extension->notification) { + _extension->notification(_extension_instance, p_notification); +#endif // DISABLE_DEPRECATED + } + } + + if (p_reversed) { + _notificationv(p_notification, p_reversed); + } else { + if (script_instance) { + script_instance->notification(p_notification, p_reversed); + } } } diff --git a/core/object/object.h b/core/object/object.h index 561e5b8fe3f..675b6cc1d81 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -321,7 +321,10 @@ struct ObjectGDExtension { GDExtensionClassFreePropertyList free_property_list; GDExtensionClassPropertyCanRevert property_can_revert; GDExtensionClassPropertyGetRevert property_get_revert; +#ifndef DISABLE_DEPRECATED GDExtensionClassNotification notification; +#endif // DISABLE_DEPRECATED + GDExtensionClassNotification2 notification2; GDExtensionClassToString to_string; GDExtensionClassReference reference; GDExtensionClassReference unreference; diff --git a/core/object/script_language.h b/core/object/script_language.h index 9d83a12bbdf..ad88c3a7d49 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -205,7 +205,7 @@ public: } virtual Variant call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); // implement if language supports const functions - virtual void notification(int p_notification) = 0; + virtual void notification(int p_notification, bool p_reversed = false) = 0; virtual String to_string(bool *r_valid) { if (r_valid) { *r_valid = false; @@ -476,7 +476,7 @@ public: r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } - virtual void notification(int p_notification) override {} + virtual void notification(int p_notification, bool p_reversed = false) override {} virtual Ref