Skip to content

Implement compatibility bindings system for Variant methods #10337

@monxa

Description

@monxa

Describe the project you are working on

There have been quite a few proposals that are held back by the lack of this, example:

Describe the problem or limitation you are having in your project

All examples fail because of compatibility breakage when changing signatures of godots utilitiy methods, builtin methods or template methods because we have no streamlined way to register backward compatibility for gdextension for these methods.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Implement a system for registering backward compatibility bindings for GDExtension methods, similar to ClassDB::bind_compatibility_method.

Enhancement:
Faster iteration of engine builtin/variant_call methods that stay backwards compatible. This would allow us not to wait for the next breaking, major engine version, if the signature of a method changes. Signatures change if the number/type/argument count/constness/name/return type of variant_call or builin method change. System could later potentially be extended to operators and properties.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

From what I have gathered, to provide backwards compatibility for builtin/utility methods, you need a couple of components:

  • static class where compatibility methods can be registered, maintained and converted to ptrcalls
  • api generation extension
  • 0 overhead fallback in
    • gdextension_variant_get_ptr_utility_function
    • gdextension_variant_get_ptr_builtin_method
    • (later more such as for operators etc).

Example for gdextension_variant_get_ptr_utility_function:

diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 85f83eecfd..a97baaae0c 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -40,6 +40,7 @@
 #include "core/object/worker_thread_pool.h"
 #include "core/os/memory.h"
 #include "core/variant/variant.h"
+#include "core/variant/variant_compat_bindings.h"
 #include "core/version.h"
 
 #include <string.h>
@@ -754,10 +755,20 @@ static void gdextension_variant_get_constant_value(GDExtensionVariantType p_type
 static GDExtensionPtrUtilityFunction gdextension_variant_get_ptr_utility_function(GDExtensionConstStringNamePtr p_function, GDExtensionInt p_hash) {
        StringName function = *reinterpret_cast<const StringName *>(p_function);
        uint32_t hash = Variant::get_utility_function_hash(function);
+#ifndef DISABLE_DEPRECATED
+       if (hash != p_hash) {
+               Variant::PTRUtilityFunction ptr = VariantCompatBindings::get_utility_binding(p_hash);
+               if (ptr == nullptr) {
+                       ERR_PRINT_ONCE("Error getting utility function " + function + ", hash mismatch.");
+                       return nullptr;
+               }
+               return (GDExtensionPtrUtilityFunction)ptr;
+       }
+#else
        if (hash != p_hash) {
                ERR_PRINT_ONCE("Error getting utility function " + function + ", hash mismatch.");
                return nullptr;
        }
+#endif // DISABLE_DEPRECATED
        return (GDExtensionPtrUtilityFunction)Variant::get_ptr_utility_function(function);
 }

This demonstrates how the system would fall back to compatibility bindings when a hash mismatch occurs, allowing for backward compatibility while maintaining performance for current versions.

If this enhancement will not be used often, can it be worked around with a few lines of script?

This runs scripts.

Is there a reason why this should be core and not an add-on in the asset library?

This is core.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions