Merge pull request #100674 from dsnopek/gdextension-virtual-method-compat
GDExtension: Add compatibility system for virtual methods
This commit is contained in:
@ -1020,7 +1020,19 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
|
||||
d2["is_required"] = (F.flags & METHOD_FLAG_VIRTUAL_REQUIRED) ? true : false;
|
||||
d2["is_vararg"] = false;
|
||||
d2["is_virtual"] = true;
|
||||
// virtual functions have no hash since no MethodBind is involved
|
||||
d2["hash"] = mi.get_compatibility_hash();
|
||||
|
||||
Vector<uint32_t> compat_hashes = ClassDB::get_virtual_method_compatibility_hashes(class_name, method_name);
|
||||
Array compatibility;
|
||||
if (compat_hashes.size()) {
|
||||
for (int i = 0; i < compat_hashes.size(); i++) {
|
||||
compatibility.push_back(compat_hashes[i]);
|
||||
}
|
||||
}
|
||||
if (compatibility.size() > 0) {
|
||||
d2["hash_compatibility"] = compatibility;
|
||||
}
|
||||
|
||||
bool has_return = mi.return_val.type != Variant::NIL || (mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
if (has_return) {
|
||||
PropertyInfo pinfo = mi.return_val;
|
||||
@ -1473,8 +1485,8 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_
|
||||
|
||||
if (p_compare_hashes) {
|
||||
if (!old_elem.has("hash")) {
|
||||
if (old_elem.has("is_virtual") && bool(old_elem["is_virtual"]) && !new_elem.has("hash")) {
|
||||
continue; // No hash for virtual methods, go on.
|
||||
if (old_elem.has("is_virtual") && bool(old_elem["is_virtual"]) && !old_elem.has("hash")) {
|
||||
continue; // Virtual methods didn't use to have hashes, so skip check if it's missing in the old file.
|
||||
}
|
||||
|
||||
failed = true;
|
||||
|
||||
@ -260,7 +260,7 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
nullptr, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
@ -271,6 +271,8 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr,
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info4, &legacy);
|
||||
}
|
||||
@ -296,8 +298,8 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
};
|
||||
@ -307,6 +309,8 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar
|
||||
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info4, &legacy);
|
||||
}
|
||||
@ -332,8 +336,8 @@ void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_librar
|
||||
nullptr, // GDExtensionClassCreateInstance2 create_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
p_extension_funcs->recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
nullptr, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
p_extension_funcs->call_virtual_with_data_func, // GDExtensionClassCallVirtualWithData call_virtual_func;
|
||||
p_extension_funcs->class_userdata, // void *class_userdata;
|
||||
};
|
||||
@ -343,6 +347,8 @@ void GDExtension::_register_extension_class3(GDExtensionClassLibraryPtr p_librar
|
||||
nullptr, // GDExtensionClassFreePropertyList free_property_list_func;
|
||||
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance2 create_instance_func;
|
||||
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
|
||||
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
p_extension_funcs->get_virtual_call_data_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
};
|
||||
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info4, &legacy);
|
||||
}
|
||||
@ -431,6 +437,8 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
|
||||
extension->gdextension.free_property_list = p_deprecated_funcs->free_property_list_func;
|
||||
extension->gdextension.create_instance = p_deprecated_funcs->create_instance_func;
|
||||
extension->gdextension.get_rid = p_deprecated_funcs->get_rid_func;
|
||||
extension->gdextension.get_virtual = p_deprecated_funcs->get_virtual_func;
|
||||
extension->gdextension.get_virtual_call_data = p_deprecated_funcs->get_virtual_call_data_func;
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
extension->gdextension.notification2 = p_extension_funcs->notification_func;
|
||||
@ -441,8 +449,8 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
|
||||
extension->gdextension.create_instance2 = p_extension_funcs->create_instance_func;
|
||||
extension->gdextension.free_instance = p_extension_funcs->free_instance_func;
|
||||
extension->gdextension.recreate_instance = p_extension_funcs->recreate_instance_func;
|
||||
extension->gdextension.get_virtual = p_extension_funcs->get_virtual_func;
|
||||
extension->gdextension.get_virtual_call_data = p_extension_funcs->get_virtual_call_data_func;
|
||||
extension->gdextension.get_virtual2 = p_extension_funcs->get_virtual_func;
|
||||
extension->gdextension.get_virtual_call_data2 = p_extension_funcs->get_virtual_call_data_func;
|
||||
extension->gdextension.call_virtual_with_data = p_extension_funcs->call_virtual_with_data_func;
|
||||
|
||||
extension->gdextension.reloadable = self->reloadable;
|
||||
|
||||
@ -72,6 +72,8 @@ class GDExtension : public Resource {
|
||||
GDExtensionClassFreePropertyList free_property_list_func = nullptr;
|
||||
GDExtensionClassCreateInstance create_instance_func = nullptr;
|
||||
GDExtensionClassGetRID get_rid_func = nullptr;
|
||||
GDExtensionClassGetVirtual get_virtual_func = nullptr;
|
||||
GDExtensionClassGetVirtualCallData get_virtual_call_data_func = nullptr;
|
||||
#endif // DISABLE_DEPRECATED
|
||||
};
|
||||
|
||||
|
||||
@ -273,7 +273,9 @@ typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance2)(void *p_class_us
|
||||
typedef void (*GDExtensionClassFreeInstance)(void *p_class_userdata, GDExtensionClassInstancePtr p_instance);
|
||||
typedef GDExtensionClassInstancePtr (*GDExtensionClassRecreateInstance)(void *p_class_userdata, GDExtensionObjectPtr p_object);
|
||||
typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
|
||||
typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual2)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
|
||||
typedef void *(*GDExtensionClassGetVirtualCallData)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
|
||||
typedef void *(*GDExtensionClassGetVirtualCallData2)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
|
||||
typedef void (*GDExtensionClassCallVirtualWithData)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, void *p_virtual_call_userdata, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
|
||||
|
||||
typedef struct {
|
||||
@ -384,14 +386,14 @@ typedef struct {
|
||||
GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
|
||||
GDExtensionClassRecreateInstance recreate_instance_func;
|
||||
// Queries a virtual function by name and returns a callback to invoke the requested virtual function.
|
||||
GDExtensionClassGetVirtual get_virtual_func;
|
||||
GDExtensionClassGetVirtual2 get_virtual_func;
|
||||
// Paired with `call_virtual_with_data_func`, this is an alternative to `get_virtual_func` for extensions that
|
||||
// need or benefit from extra data when calling virtual functions.
|
||||
// Returns user data that will be passed to `call_virtual_with_data_func`.
|
||||
// Returning `NULL` from this function signals to Godot that the virtual function is not overridden.
|
||||
// Data returned from this function should be managed by the extension and must be valid until the extension is deinitialized.
|
||||
// You should supply either `get_virtual_func`, or `get_virtual_call_data_func` with `call_virtual_with_data_func`.
|
||||
GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
|
||||
GDExtensionClassGetVirtualCallData2 get_virtual_call_data_func;
|
||||
// Used to call virtual functions when `get_virtual_call_data_func` is not null.
|
||||
GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
|
||||
void *class_userdata; // Per-class user data, later accessible in instance bindings.
|
||||
|
||||
Reference in New Issue
Block a user