Merge pull request #87758 from dsnopek/gdextension-register-virtual-method
Allow GDExtensions to register virtual methods and call them on scripts
This commit is contained in:
commit
306dd5be3f
|
@ -518,6 +518,12 @@ void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_
|
|||
|
||||
ClassDB::bind_method_custom(class_name, method);
|
||||
}
|
||||
|
||||
void GDExtension::_register_extension_class_virtual_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassVirtualMethodInfo *p_method_info) {
|
||||
StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
|
||||
ClassDB::add_extension_class_virtual_method(class_name, p_method_info);
|
||||
}
|
||||
|
||||
void GDExtension::_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) {
|
||||
GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
|
||||
|
||||
|
@ -837,6 +843,7 @@ void GDExtension::initialize_gdextensions() {
|
|||
#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_virtual_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_virtual_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);
|
||||
register_interface_function("classdb_register_extension_class_property_indexed", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_indexed);
|
||||
|
|
|
@ -77,6 +77,7 @@ class GDExtension : public Resource {
|
|||
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_virtual_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassVirtualMethodInfo *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);
|
||||
static void _register_extension_class_property_indexed(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index);
|
||||
|
|
|
@ -1194,6 +1194,33 @@ static GDObjectInstanceID gdextension_object_get_instance_id(GDExtensionConstObj
|
|||
return (GDObjectInstanceID)o->get_instance_id();
|
||||
}
|
||||
|
||||
static GDExtensionBool gdextension_object_has_script_method(GDExtensionConstObjectPtr p_object, GDExtensionConstStringNamePtr p_method) {
|
||||
Object *o = (Object *)p_object;
|
||||
const StringName method = *reinterpret_cast<const StringName *>(p_method);
|
||||
|
||||
ScriptInstance *script_instance = o->get_script_instance();
|
||||
if (script_instance) {
|
||||
return script_instance->has_method(method);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void gdextension_object_call_script_method(GDExtensionObjectPtr p_object, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionUninitializedVariantPtr r_return, GDExtensionCallError *r_error) {
|
||||
Object *o = (Object *)p_object;
|
||||
const StringName method = *reinterpret_cast<const StringName *>(p_method);
|
||||
const Variant **args = (const Variant **)p_args;
|
||||
|
||||
Callable::CallError error;
|
||||
memnew_placement(r_return, Variant);
|
||||
*(Variant *)r_return = o->callp(method, args, p_argument_count, error);
|
||||
|
||||
if (r_error) {
|
||||
r_error->error = (GDExtensionCallErrorType)(error.error);
|
||||
r_error->argument = error.argument;
|
||||
r_error->expected = error.expected;
|
||||
}
|
||||
}
|
||||
|
||||
static GDExtensionObjectPtr gdextension_ref_get_object(GDExtensionConstRefPtr p_ref) {
|
||||
const Ref<RefCounted> *ref = (const Ref<RefCounted> *)p_ref;
|
||||
if (ref == nullptr || ref->is_null()) {
|
||||
|
@ -1515,6 +1542,8 @@ void gdextension_setup_interface() {
|
|||
REGISTER_INTERFACE_FUNC(object_cast_to);
|
||||
REGISTER_INTERFACE_FUNC(object_get_instance_from_id);
|
||||
REGISTER_INTERFACE_FUNC(object_get_instance_id);
|
||||
REGISTER_INTERFACE_FUNC(object_has_script_method);
|
||||
REGISTER_INTERFACE_FUNC(object_call_script_method);
|
||||
REGISTER_INTERFACE_FUNC(ref_get_object);
|
||||
REGISTER_INTERFACE_FUNC(ref_set_object);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
|
|
@ -364,13 +364,18 @@ typedef struct {
|
|||
GDExtensionClassMethodPtrCall ptrcall_func;
|
||||
uint32_t method_flags; // Bitfield of `GDExtensionClassMethodFlags`.
|
||||
|
||||
/* If `has_return_value` is false, `return_value_info` and `return_value_metadata` are ignored. */
|
||||
/* If `has_return_value` is false, `return_value_info` and `return_value_metadata` are ignored.
|
||||
*
|
||||
* @todo Consider dropping `has_return_value` and making the other two properties match `GDExtensionMethodInfo` and `GDExtensionClassVirtualMethod` for consistency in future version of this struct.
|
||||
*/
|
||||
GDExtensionBool has_return_value;
|
||||
GDExtensionPropertyInfo *return_value_info;
|
||||
GDExtensionClassMethodArgumentMetadata return_value_metadata;
|
||||
|
||||
/* Arguments: `arguments_info` and `arguments_metadata` are array of size `argument_count`.
|
||||
* Name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies.
|
||||
*
|
||||
* @todo Consider renaming `arguments_info` to `arguments` for consistency in future version of this struct.
|
||||
*/
|
||||
uint32_t argument_count;
|
||||
GDExtensionPropertyInfo *arguments_info;
|
||||
|
@ -381,6 +386,18 @@ typedef struct {
|
|||
GDExtensionVariantPtr *default_arguments;
|
||||
} GDExtensionClassMethodInfo;
|
||||
|
||||
typedef struct {
|
||||
GDExtensionStringNamePtr name;
|
||||
uint32_t method_flags; // Bitfield of `GDExtensionClassMethodFlags`.
|
||||
|
||||
GDExtensionPropertyInfo return_value;
|
||||
GDExtensionClassMethodArgumentMetadata return_value_metadata;
|
||||
|
||||
uint32_t argument_count;
|
||||
GDExtensionPropertyInfo *arguments;
|
||||
GDExtensionClassMethodArgumentMetadata *arguments_metadata;
|
||||
} GDExtensionClassVirtualMethodInfo;
|
||||
|
||||
typedef void (*GDExtensionCallableCustomCall)(void *callable_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
|
||||
typedef GDExtensionBool (*GDExtensionCallableCustomIsValid)(void *callable_userdata);
|
||||
typedef void (*GDExtensionCallableCustomFree)(void *callable_userdata);
|
||||
|
@ -2268,6 +2285,34 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceObjectGetInstanceFromId)(GDOb
|
|||
*/
|
||||
typedef GDObjectInstanceID (*GDExtensionInterfaceObjectGetInstanceId)(GDExtensionConstObjectPtr p_object);
|
||||
|
||||
/**
|
||||
* @name object_has_script_method
|
||||
* @since 4.3
|
||||
*
|
||||
* Checks if this object has a script with the given method.
|
||||
*
|
||||
* @param p_object A pointer to the Object.
|
||||
* @param p_method A pointer to a StringName identifying the method.
|
||||
*
|
||||
* @returns true if the object has a script and that script has a method with the given name. Returns false if the object has no script.
|
||||
*/
|
||||
typedef GDExtensionBool (*GDExtensionInterfaceObjectHasScriptMethod)(GDExtensionConstObjectPtr p_object, GDExtensionConstStringNamePtr p_method);
|
||||
|
||||
/**
|
||||
* @name object_call_script_method
|
||||
* @since 4.3
|
||||
*
|
||||
* Call the given script method on this object.
|
||||
*
|
||||
* @param p_object A pointer to the Object.
|
||||
* @param p_method A pointer to a StringName identifying the method.
|
||||
* @param p_args A pointer to a C array of Variant.
|
||||
* @param p_argument_count The number of arguments.
|
||||
* @param r_return A pointer a Variant which will be assigned the return value.
|
||||
* @param r_error A pointer the structure which will hold error information.
|
||||
*/
|
||||
typedef void (*GDExtensionInterfaceObjectCallScriptMethod)(GDExtensionObjectPtr p_object, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionUninitializedVariantPtr r_return, GDExtensionCallError *r_error);
|
||||
|
||||
/* INTERFACE: Reference */
|
||||
|
||||
/**
|
||||
|
@ -2483,6 +2528,20 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionCl
|
|||
*/
|
||||
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassMethod)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
|
||||
|
||||
/**
|
||||
* @name classdb_register_extension_class_virtual_method
|
||||
* @since 4.3
|
||||
*
|
||||
* Registers a virtual method on an extension class in ClassDB, that can be implemented by scripts or other extensions.
|
||||
*
|
||||
* 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_method_info A pointer to a GDExtensionClassMethodInfo struct.
|
||||
*/
|
||||
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassVirtualMethodInfo *p_method_info);
|
||||
|
||||
/**
|
||||
* @name classdb_register_extension_class_integer_constant
|
||||
* @since 4.1
|
||||
|
|
|
@ -1615,6 +1615,28 @@ void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p
|
|||
#endif
|
||||
}
|
||||
|
||||
void ClassDB::add_extension_class_virtual_method(const StringName &p_class, const GDExtensionClassVirtualMethodInfo *p_method_info) {
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
PackedStringArray arg_names;
|
||||
|
||||
MethodInfo mi;
|
||||
mi.name = *reinterpret_cast<StringName *>(p_method_info->name);
|
||||
mi.return_val = PropertyInfo(p_method_info->return_value);
|
||||
mi.return_val_metadata = p_method_info->return_value_metadata;
|
||||
mi.flags = p_method_info->method_flags;
|
||||
for (int i = 0; i < (int)p_method_info->argument_count; i++) {
|
||||
PropertyInfo arg(p_method_info->arguments[i]);
|
||||
mi.arguments.push_back(arg);
|
||||
mi.arguments_metadata.push_back(p_method_info->arguments_metadata[i]);
|
||||
arg_names.push_back(arg.name);
|
||||
}
|
||||
|
||||
add_virtual_method(p_class, mi, true, arg_names);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ClassDB::set_class_enabled(const StringName &p_class, bool p_enable) {
|
||||
OBJTYPE_WLOCK;
|
||||
|
||||
|
|
|
@ -410,6 +410,7 @@ public:
|
|||
|
||||
static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true, const Vector<String> &p_arg_names = Vector<String>(), bool p_object_core = false);
|
||||
static void get_virtual_methods(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false);
|
||||
static void add_extension_class_virtual_method(const StringName &p_class, const GDExtensionClassVirtualMethodInfo *p_method_info);
|
||||
|
||||
static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield = false);
|
||||
static void get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance = false);
|
||||
|
|
Loading…
Reference in New Issue