Compare commits

...

10 Commits

Author SHA1 Message Date
A Thousand Ships 260c1a6770
Merge 134450c0ed into 5fcc43e54d 2024-02-13 11:12:30 +00:00
A Thousand Ships 134450c0ed
[Temporary] Redirected artifact checkout to allow testing 2024-02-13 12:12:21 +01:00
A Thousand Ships feb80565ec
Optional ScriptInstance extension 2024-02-13 12:12:20 +01:00
A Thousand Ships 34349b4ce0
Add support for getting argument count from `Callable`s 2024-02-13 12:12:19 +01:00
David Snopek 5fcc43e54d
Merge pull request #1377 from dsnopek/gdextension-register-virtual-method
Allow GDExtensions to register virtual methods and call them on scripts (godot-cpp support)
2024-02-12 18:43:12 -06:00
David Snopek 9a13efa0e3
Merge pull request #1363 from Daylily-Zeleen/daylily-zeleen/fix_object_return_value_of_builtin_types_methods
Fix object return value of builtin types' methods.
2024-02-12 14:33:20 -06:00
David Snopek 8fbb7cf795 Allow GDExtensions to register virtual methods and call them on scripts 2024-02-12 13:30:07 -06:00
DaylilyZeleen 6a3753c076 Fix object return value of builtin types' methods. 2024-02-13 03:20:02 +08:00
David Snopek 7c547c6c6b
Merge pull request #1384 from allenwp/godot-87991-typed-array-additions
Added newer Variant types to `typed_array.hpp`
2024-02-12 10:07:32 -06:00
Allen Pestaluky 349b5a3146 Added newer Variant types to `typed_array.hpp`
This is a companion commit to the godot PR https://github.com/godotengine/godot/pull/87992 which fixes https://github.com/godotengine/godot/issues/87991
Also undefines typed array templates after use to match Godot's typed_array.h
2024-02-06 13:53:38 -05:00
22 changed files with 542 additions and 19 deletions

View File

@ -155,8 +155,8 @@ jobs:
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9 uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: ${{ matrix.run-tests }} if: ${{ matrix.run-tests }}
with: with:
repo: godotengine/godot repo: AThousandShips/godot
branch: master branch: the_angry_count
event: push event: push
workflow: linux_builds.yml workflow: linux_builds.yml
workflow_conclusion: success workflow_conclusion: success

View File

@ -70,6 +70,136 @@ def generate_wrappers(target):
f.write(txt) f.write(txt)
def generate_virtual_version(argcount, const=False, returns=False):
s = """#define GDVIRTUAL$VER($RET m_name $ARG)\\
StringName _gdvirtual_##m_name##_sn = #m_name;\\
template <bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST {\\
if (::godot::internal::gdextension_interface_object_has_script_method(_owner, &_gdvirtual_##m_name##_sn)) { \\
GDExtensionCallError ce;\\
$CALLSIARGS\\
$CALLSIBEGIN::godot::internal::gdextension_interface_object_call_script_method(_owner, &_gdvirtual_##m_name##_sn, $CALLSIARGPASS, $CALLSIRETPASS, &ce);\\
if (ce.error == GDEXTENSION_CALL_OK) {\\
$CALLSIRET\\
return true;\\
}\\
}\\
if (required) {\\
ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");\\
$RVOID\\
}\\
return false;\\
}\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const {\\
return godot::internal::gdextension_interface_object_has_script_method(_owner, &_gdvirtual_##m_name##_sn); \\
}\\
_FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() {\\
MethodInfo method_info;\\
method_info.name = #m_name;\\
method_info.flags = $METHOD_FLAGS;\\
$FILL_METHOD_INFO\\
return method_info;\\
}
"""
sproto = str(argcount)
method_info = ""
if returns:
sproto += "R"
s = s.replace("$RET", "m_ret,")
s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors
method_info += "method_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
method_info += "\t\tmethod_info.return_val_metadata = GetTypeInfo<m_ret>::METADATA;"
else:
s = s.replace("$RET ", "")
s = s.replace("\t\t\t$RVOID\\\n", "")
if const:
sproto += "C"
s = s.replace("$CONST", "const")
s = s.replace("$METHOD_FLAGS", "METHOD_FLAG_VIRTUAL | METHOD_FLAG_CONST")
else:
s = s.replace("$CONST ", "")
s = s.replace("$METHOD_FLAGS", "METHOD_FLAG_VIRTUAL")
s = s.replace("$VER", sproto)
argtext = ""
callargtext = ""
callsiargs = ""
callsiargptrs = ""
if argcount > 0:
argtext += ", "
callsiargs = f"Variant vargs[{argcount}] = {{ "
callsiargptrs = f"\t\t\tconst Variant *vargptrs[{argcount}] = {{ "
for i in range(argcount):
if i > 0:
argtext += ", "
callargtext += ", "
callsiargs += ", "
callsiargptrs += ", "
argtext += f"m_type{i + 1}"
callargtext += f"m_type{i + 1} arg{i + 1}"
callsiargs += f"Variant(arg{i + 1})"
callsiargptrs += f"&vargs[{i}]"
if method_info:
method_info += "\\\n\t\t"
method_info += f"method_info.arguments.push_back(GetTypeInfo<m_type{i + 1}>::get_class_info());\\\n"
method_info += f"\t\tmethod_info.arguments_metadata.push_back(GetTypeInfo<m_type{i + 1}>::METADATA);"
if argcount:
callsiargs += " };\\\n"
callsiargptrs += " };"
s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs)
s = s.replace("$CALLSIARGPASS", f"(const GDExtensionConstVariantPtr *)vargptrs, {argcount}")
else:
s = s.replace("\t\t\t$CALLSIARGS\\\n", "")
s = s.replace("$CALLSIARGPASS", "nullptr, 0")
if returns:
if argcount > 0:
callargtext += ", "
callargtext += "m_ret &r_ret"
s = s.replace("$CALLSIBEGIN", "Variant ret;\\\n\t\t\t")
s = s.replace("$CALLSIRETPASS", "&ret")
s = s.replace("$CALLSIRET", "r_ret = VariantCaster<m_ret>::cast(ret);")
else:
s = s.replace("$CALLSIBEGIN", "")
s = s.replace("$CALLSIRETPASS", "nullptr")
s = s.replace("\t\t\t\t$CALLSIRET\\\n", "")
s = s.replace(" $ARG", argtext)
s = s.replace("$CALLARGS", callargtext)
if method_info:
s = s.replace("$FILL_METHOD_INFO", method_info)
else:
s = s.replace("\t\t$FILL_METHOD_INFO\\\n", method_info)
return s
def generate_virtuals(target):
max_versions = 12
txt = """/* THIS FILE IS GENERATED DO NOT EDIT */
#ifndef GDEXTENSION_GDVIRTUAL_GEN_H
#define GDEXTENSION_GDVIRTUAL_GEN_H
"""
for i in range(max_versions + 1):
txt += f"/* {i} Arguments */\n\n"
txt += generate_virtual_version(i, False, False)
txt += generate_virtual_version(i, False, True)
txt += generate_virtual_version(i, True, False)
txt += generate_virtual_version(i, True, True)
txt += "#endif // GDEXTENSION_GDVIRTUAL_GEN_H\n"
with open(target, "w", encoding="utf-8") as f:
f.write(txt)
def get_file_list(api_filepath, output_dir, headers=False, sources=False): def get_file_list(api_filepath, output_dir, headers=False, sources=False):
api = {} api = {}
files = [] files = []
@ -81,6 +211,7 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
source_gen_folder = Path(output_dir) / "gen" / "src" source_gen_folder = Path(output_dir) / "gen" / "src"
files.append(str((core_gen_folder / "ext_wrappers.gen.inc").as_posix())) files.append(str((core_gen_folder / "ext_wrappers.gen.inc").as_posix()))
files.append(str((core_gen_folder / "gdvirtual.gen.inc").as_posix()))
for builtin_class in api["builtin_classes"]: for builtin_class in api["builtin_classes"]:
if is_pod_type(builtin_class["name"]): if is_pod_type(builtin_class["name"]):
@ -204,6 +335,7 @@ def generate_builtin_bindings(api, output_dir, build_config):
source_gen_folder.mkdir(parents=True, exist_ok=True) source_gen_folder.mkdir(parents=True, exist_ok=True)
generate_wrappers(core_gen_folder / "ext_wrappers.gen.inc") generate_wrappers(core_gen_folder / "ext_wrappers.gen.inc")
generate_virtuals(core_gen_folder / "gdvirtual.gen.inc")
# Store types beforehand. # Store types beforehand.
for builtin_api in api["builtin_classes"]: for builtin_api in api["builtin_classes"]:
@ -964,8 +1096,19 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result.append(method_signature + "{") result.append(method_signature + "{")
method_call = "\t" method_call = "\t"
is_ref = False
if "return_type" in method: if "return_type" in method:
method_call += f'return internal::_call_builtin_method_ptr_ret<{correct_type(method["return_type"])}>(' return_type = method["return_type"]
if is_enum(return_type):
method_call += f"return ({get_gdextension_type(correct_type(return_type))})internal::_call_builtin_method_ptr_ret<int64_t>("
elif is_pod_type(return_type) or is_variant(return_type):
method_call += f"return internal::_call_builtin_method_ptr_ret<{get_gdextension_type(correct_type(return_type))}>("
elif is_refcounted(return_type):
method_call += f"return Ref<{return_type}>::_gde_internal_constructor(internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
is_ref = True
else:
method_call += f"return internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
else: else:
method_call += "internal::_call_builtin_method_ptr_no_ret(" method_call += "internal::_call_builtin_method_ptr_no_ret("
method_call += f'_method_bindings.method_{method["name"]}, ' method_call += f'_method_bindings.method_{method["name"]}, '
@ -986,6 +1129,9 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result += encode result += encode
arguments.append(arg_name) arguments.append(arg_name)
method_call += ", ".join(arguments) method_call += ", ".join(arguments)
if is_ref:
method_call += ")" # Close Ref<> constructor.
method_call += ");" method_call += ");"
result.append(method_call) result.append(method_call)

View File

@ -364,13 +364,18 @@ typedef struct {
GDExtensionClassMethodPtrCall ptrcall_func; GDExtensionClassMethodPtrCall ptrcall_func;
uint32_t method_flags; // Bitfield of `GDExtensionClassMethodFlags`. 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; GDExtensionBool has_return_value;
GDExtensionPropertyInfo *return_value_info; GDExtensionPropertyInfo *return_value_info;
GDExtensionClassMethodArgumentMetadata return_value_metadata; GDExtensionClassMethodArgumentMetadata return_value_metadata;
/* Arguments: `arguments_info` and `arguments_metadata` are array of size `argument_count`. /* 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. * 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; uint32_t argument_count;
GDExtensionPropertyInfo *arguments_info; GDExtensionPropertyInfo *arguments_info;
@ -381,6 +386,18 @@ typedef struct {
GDExtensionVariantPtr *default_arguments; GDExtensionVariantPtr *default_arguments;
} GDExtensionClassMethodInfo; } 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 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 GDExtensionBool (*GDExtensionCallableCustomIsValid)(void *callable_userdata);
typedef void (*GDExtensionCallableCustomFree)(void *callable_userdata); typedef void (*GDExtensionCallableCustomFree)(void *callable_userdata);
@ -391,6 +408,8 @@ typedef GDExtensionBool (*GDExtensionCallableCustomLessThan)(void *callable_user
typedef void (*GDExtensionCallableCustomToString)(void *callable_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out); typedef void (*GDExtensionCallableCustomToString)(void *callable_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out);
typedef GDExtensionInt (*GDExtensionCallableCustomGetArgumentCount)(void *callable_userdata, GDExtensionBool *r_is_valid);
typedef struct { typedef struct {
/* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method. /* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method.
* *
@ -420,7 +439,40 @@ typedef struct {
GDExtensionCallableCustomLessThan less_than_func; GDExtensionCallableCustomLessThan less_than_func;
GDExtensionCallableCustomToString to_string_func; GDExtensionCallableCustomToString to_string_func;
} GDExtensionCallableCustomInfo; } GDExtensionCallableCustomInfo; // Deprecated. Use GDExtensionCallableCustomInfo2 instead.
typedef struct {
/* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method.
*
* `token` should point to an address that uniquely identifies the GDExtension (for example, the
* `GDExtensionClassLibraryPtr` passed to the entry symbol function.
*
* `hash_func`, `equal_func`, and `less_than_func` are optional. If not provided both `call_func` and
* `callable_userdata` together are used as the identity of the callable for hashing and comparison purposes.
*
* The hash returned by `hash_func` is cached, `hash_func` will not be called more than once per callable.
*
* `is_valid_func` is necessary if the validity of the callable can change before destruction.
*
* `free_func` is necessary if `callable_userdata` needs to be cleaned up when the callable is freed.
*/
void *callable_userdata;
void *token;
GDObjectInstanceID object_id;
GDExtensionCallableCustomCall call_func;
GDExtensionCallableCustomIsValid is_valid_func;
GDExtensionCallableCustomFree free_func;
GDExtensionCallableCustomHash hash_func;
GDExtensionCallableCustomEqual equal_func;
GDExtensionCallableCustomLessThan less_than_func;
GDExtensionCallableCustomToString to_string_func;
GDExtensionCallableCustomGetArgumentCount get_argument_count_func;
} GDExtensionCallableCustomInfo2;
/* SCRIPT INSTANCE EXTENSION */ /* SCRIPT INSTANCE EXTENSION */
@ -447,6 +499,8 @@ typedef void (*GDExtensionScriptInstanceFreeMethodList)(GDExtensionScriptInstanc
typedef GDExtensionBool (*GDExtensionScriptInstanceHasMethod)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name); typedef GDExtensionBool (*GDExtensionScriptInstanceHasMethod)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name);
typedef GDExtensionInt (*GDExtensionScriptInstanceGetMethodArgumentCount)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionBool *r_is_valid);
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 (*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); // Deprecated. Use GDExtensionScriptInstanceNotification2 instead. typedef void (*GDExtensionScriptInstanceNotification)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what); // Deprecated. Use GDExtensionScriptInstanceNotification2 instead.
typedef void (*GDExtensionScriptInstanceNotification2)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what, GDExtensionBool p_reversed); typedef void (*GDExtensionScriptInstanceNotification2)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what, GDExtensionBool p_reversed);
@ -503,7 +557,7 @@ typedef struct {
GDExtensionScriptInstanceFree free_func; GDExtensionScriptInstanceFree free_func;
} GDExtensionScriptInstanceInfo; // Deprecated. Use GDExtensionScriptInstanceInfo2 instead. } GDExtensionScriptInstanceInfo; // Deprecated. Use GDExtensionScriptInstanceInfo3 instead.
typedef struct { typedef struct {
GDExtensionScriptInstanceSet set_func; GDExtensionScriptInstanceSet set_func;
@ -544,7 +598,50 @@ typedef struct {
GDExtensionScriptInstanceFree free_func; GDExtensionScriptInstanceFree free_func;
} GDExtensionScriptInstanceInfo2; } GDExtensionScriptInstanceInfo2; // Deprecated. Use GDExtensionScriptInstanceInfo3 instead.
typedef struct {
GDExtensionScriptInstanceSet set_func;
GDExtensionScriptInstanceGet get_func;
GDExtensionScriptInstanceGetPropertyList get_property_list_func;
GDExtensionScriptInstanceFreePropertyList free_property_list_func;
GDExtensionScriptInstanceGetClassCategory get_class_category_func; // Optional. Set to NULL for the default behavior.
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;
GDExtensionScriptInstanceValidateProperty validate_property_func;
GDExtensionScriptInstanceHasMethod has_method_func;
GDExtensionScriptInstanceGetMethodArgumentCount get_method_argument_count_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;
} GDExtensionScriptInstanceInfo3;
/* INITIALIZATION */ /* INITIALIZATION */
@ -2268,6 +2365,34 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceObjectGetInstanceFromId)(GDOb
*/ */
typedef GDObjectInstanceID (*GDExtensionInterfaceObjectGetInstanceId)(GDExtensionConstObjectPtr p_object); 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 */ /* INTERFACE: Reference */
/** /**
@ -2298,7 +2423,7 @@ typedef void (*GDExtensionInterfaceRefSetObject)(GDExtensionRefPtr p_ref, GDExte
/** /**
* @name script_instance_create * @name script_instance_create
* @since 4.1 * @since 4.1
* @deprecated in Godot 4.2. Use `script_instance_create2` instead. * @deprecated in Godot 4.2. Use `script_instance_create3` instead.
* *
* Creates a script instance that contains the given info and instance data. * Creates a script instance that contains the given info and instance data.
* *
@ -2312,6 +2437,7 @@ typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate)
/** /**
* @name script_instance_create2 * @name script_instance_create2
* @since 4.2 * @since 4.2
* @deprecated in Godot 4.3. Use `script_instance_create3` instead.
* *
* Creates a script instance that contains the given info and instance data. * Creates a script instance that contains the given info and instance data.
* *
@ -2322,6 +2448,19 @@ typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate)
*/ */
typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate2)(const GDExtensionScriptInstanceInfo2 *p_info, GDExtensionScriptInstanceDataPtr p_instance_data); typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate2)(const GDExtensionScriptInstanceInfo2 *p_info, GDExtensionScriptInstanceDataPtr p_instance_data);
/**
* @name script_instance_create3
* @since 4.3
*
* Creates a script instance that contains the given info and instance data.
*
* @param p_info A pointer to a GDExtensionScriptInstanceInfo3 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 (*GDExtensionInterfaceScriptInstanceCreate3)(const GDExtensionScriptInstanceInfo3 *p_info, GDExtensionScriptInstanceDataPtr p_instance_data);
/** /**
* @name placeholder_script_instance_create * @name placeholder_script_instance_create
* @since 4.2 * @since 4.2
@ -2371,6 +2510,7 @@ typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptIn
/** /**
* @name callable_custom_create * @name callable_custom_create
* @since 4.2 * @since 4.2
* @deprecated in Godot 4.3. Use `callable_custom_create2` instead.
* *
* Creates a custom Callable object from a function pointer. * Creates a custom Callable object from a function pointer.
* *
@ -2381,6 +2521,19 @@ typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptIn
*/ */
typedef void (*GDExtensionInterfaceCallableCustomCreate)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_callable_custom_info); typedef void (*GDExtensionInterfaceCallableCustomCreate)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_callable_custom_info);
/**
* @name callable_custom_create2
* @since 4.3
*
* Creates a custom Callable object from a function pointer.
*
* Provided struct can be safely freed once the function returns.
*
* @param r_callable A pointer that will receive the new Callable.
* @param p_callable_custom_info The info required to construct a Callable.
*/
typedef void (*GDExtensionInterfaceCallableCustomCreate2)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo2 *p_callable_custom_info);
/** /**
* @name callable_custom_get_userdata * @name callable_custom_get_userdata
* @since 4.2 * @since 4.2
@ -2483,6 +2636,20 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionCl
*/ */
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassMethod)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info); 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 * @name classdb_register_extension_class_integer_constant
* @since 4.1 * @since 4.1

View File

@ -36,6 +36,7 @@
#include <godot_cpp/core/property_info.hpp> #include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/templates/list.hpp> #include <godot_cpp/templates/list.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/godot.hpp> #include <godot_cpp/godot.hpp>
@ -107,6 +108,26 @@ public:
GodotObject *_owner = nullptr; GodotObject *_owner = nullptr;
}; };
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
}
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str) {
arr.push_back(p_str);
}
template <class... P>
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str, P... p_args) {
arr.push_back(p_str);
snarray_add_str(arr, p_args...);
}
template <class... P>
_FORCE_INLINE_ Vector<StringName> snarray(P... p_args) {
Vector<StringName> arr;
snarray_add_str(arr, p_args...);
return arr;
}
namespace internal { namespace internal {
GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size); GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size);
@ -445,4 +466,14 @@ private:
// Don't use this for your classes, use GDCLASS() instead. // Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits) #define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits)
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<false>(__VA_ARGS__)
#define GDVIRTUAL_REQUIRED_CALL(m_name, ...) _gdvirtual_##m_name##_call<true>(__VA_ARGS__)
#define GDVIRTUAL_REQUIRED_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<true>(__VA_ARGS__)
#define GDVIRTUAL_BIND(m_name, ...) ::godot::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), ::godot::snarray(__VA_ARGS__));
#define GDVIRTUAL_IS_OVERRIDDEN(m_name) _gdvirtual_##m_name##_overridden()
#define GDVIRTUAL_IS_OVERRIDDEN_PTR(m_obj, m_name) m_obj->_gdvirtual_##m_name##_overridden()
#endif // GODOT_WRAPPED_HPP #endif // GODOT_WRAPPED_HPP

View File

@ -32,6 +32,7 @@
#define GODOT_BUILTIN_PTRCALL_HPP #define GODOT_BUILTIN_PTRCALL_HPP
#include <gdextension_interface.h> #include <gdextension_interface.h>
#include <godot_cpp/core/object.hpp>
#include <array> #include <array>
@ -39,6 +40,17 @@ namespace godot {
namespace internal { namespace internal {
template <class O, class... Args>
O *_call_builtin_method_ptr_ret_obj(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), &ret, sizeof...(Args));
if (ret == nullptr) {
return nullptr;
}
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
}
template <class... Args> template <class... Args>
void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) { void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };

View File

@ -165,7 +165,10 @@ public:
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1); static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
static void add_signal(const StringName &p_class, const MethodInfo &p_signal); static void add_signal(const StringName &p_class, const MethodInfo &p_signal);
static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false); static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false);
// Binds an implementation of a virtual method defined in Godot.
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call); static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
// Add a new virtual method that can be implemented by scripts.
static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names = Vector<StringName>());
static MethodBind *get_method(const StringName &p_class, const StringName &p_method); static MethodBind *get_method(const StringName &p_class, const StringName &p_method);

View File

@ -68,6 +68,8 @@ struct MethodInfo {
int id = 0; int id = 0;
std::vector<PropertyInfo> arguments; std::vector<PropertyInfo> arguments;
std::vector<Variant> default_arguments; std::vector<Variant> default_arguments;
GDExtensionClassMethodArgumentMetadata return_val_metadata;
std::vector<GDExtensionClassMethodArgumentMetadata> arguments_metadata;
inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; } inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; }
inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); } inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); }

View File

@ -80,6 +80,17 @@ struct PropertyInfo {
p_info->usage = usage; p_info->usage = usage;
*(reinterpret_cast<StringName *>(p_info->class_name)) = class_name; *(reinterpret_cast<StringName *>(p_info->class_name)) = class_name;
} }
GDExtensionPropertyInfo _to_gdextension() const {
return {
(GDExtensionVariantType)type,
name._native_ptr(),
class_name._native_ptr(),
hint,
hint_string._native_ptr(),
usage,
};
}
}; };
} // namespace godot } // namespace godot

View File

@ -370,11 +370,14 @@ MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY_INFO(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY_INFO(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE) MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB) MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS) MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY_INFO(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR) MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH) MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
@ -393,8 +396,11 @@ MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY) MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY) MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY) MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
*/ */
#undef MAKE_TYPED_ARRAY_INFO
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info()) #define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
} // namespace godot } // namespace godot

View File

@ -165,11 +165,13 @@ extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_g
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to; extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id; extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id; extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
extern "C" GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create; extern "C" GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method;
extern "C" GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method;
extern "C" GDExtensionInterfaceCallableCustomCreate2 gdextension_interface_callable_custom_create2;
extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata; extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object; extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object; extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
extern "C" GDExtensionInterfaceScriptInstanceCreate2 gdextension_interface_script_instance_create2; extern "C" GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create; extern "C" GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update; extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update;
extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object; extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object;
@ -177,6 +179,7 @@ extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classd
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag; extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method; 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; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed;

View File

@ -41,6 +41,7 @@ class Object;
class CallableCustomBase { class CallableCustomBase {
public: public:
virtual ObjectID get_object() const = 0; virtual ObjectID get_object() const = 0;
virtual int get_argument_count(bool &r_is_valid) const;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0; virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
virtual ~CallableCustomBase() {} virtual ~CallableCustomBase() {}
}; };

View File

@ -73,6 +73,11 @@ public:
return ObjectID(data.instance->get_instance_id()); return ObjectID(data.instance->get_instance_id());
} }
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error); call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
} }
@ -110,6 +115,11 @@ public:
return ObjectID(data.instance->get_instance_id()); return ObjectID(data.instance->get_instance_id());
} }
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
} }
@ -147,6 +157,11 @@ public:
return ObjectID(data.instance->get_instance_id()); return ObjectID(data.instance->get_instance_id());
} }
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
} }
@ -182,6 +197,11 @@ public:
return ObjectID(); return ObjectID();
} }
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error); call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
r_return_value = Variant(); r_return_value = Variant();
@ -218,6 +238,11 @@ public:
return ObjectID(); return ObjectID();
} }
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error); call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
} }

View File

@ -75,6 +75,8 @@ public:
} \ } \
}; };
// All Variant::OBJECT types are intentionally omitted from this list because they are handled by
// the unspecialized TypedArray definition.
MAKE_TYPED_ARRAY(bool, Variant::BOOL) MAKE_TYPED_ARRAY(bool, Variant::BOOL)
MAKE_TYPED_ARRAY(uint8_t, Variant::INT) MAKE_TYPED_ARRAY(uint8_t, Variant::INT)
MAKE_TYPED_ARRAY(int8_t, Variant::INT) MAKE_TYPED_ARRAY(int8_t, Variant::INT)
@ -94,11 +96,14 @@ MAKE_TYPED_ARRAY(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY(Plane, Variant::PLANE) MAKE_TYPED_ARRAY(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY(AABB, Variant::AABB) MAKE_TYPED_ARRAY(AABB, Variant::AABB)
MAKE_TYPED_ARRAY(Basis, Variant::BASIS) MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY(Color, Variant::COLOR) MAKE_TYPED_ARRAY(Color, Variant::COLOR)
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH) MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
@ -116,6 +121,10 @@ MAKE_TYPED_ARRAY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) MAKE_TYPED_ARRAY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) MAKE_TYPED_ARRAY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY) MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
// If the IPAddress struct is added to godot-cpp, the following could also be added:
//MAKE_TYPED_ARRAY(IPAddress, Variant::STRING)
#undef MAKE_TYPED_ARRAY
} // namespace godot } // namespace godot

View File

@ -32,6 +32,7 @@
#include <godot_cpp/core/error_macros.hpp> #include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/godot.hpp> #include <godot_cpp/godot.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/core/memory.hpp> #include <godot_cpp/core/memory.hpp>
@ -337,6 +338,46 @@ void ClassDB::bind_virtual_method(const StringName &p_class, const StringName &p
type.virtual_methods[p_method] = p_call; type.virtual_methods[p_method] = p_call;
} }
void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names) {
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
GDExtensionClassVirtualMethodInfo mi;
mi.name = (GDExtensionStringNamePtr)&p_method.name;
mi.method_flags = p_method.flags;
mi.return_value = p_method.return_val._to_gdextension();
mi.return_value_metadata = p_method.return_val_metadata;
mi.argument_count = p_method.arguments.size();
if (mi.argument_count > 0) {
mi.arguments = (GDExtensionPropertyInfo *)memalloc(sizeof(GDExtensionPropertyInfo) * mi.argument_count);
mi.arguments_metadata = (GDExtensionClassMethodArgumentMetadata *)memalloc(sizeof(GDExtensionClassMethodArgumentMetadata) * mi.argument_count);
for (int i = 0; i < mi.argument_count; i++) {
mi.arguments[i] = p_method.arguments[i]._to_gdextension();
mi.arguments_metadata[i] = p_method.arguments_metadata[i];
}
} else {
mi.arguments = nullptr;
mi.arguments_metadata = nullptr;
}
if (p_arg_names.size() != mi.argument_count) {
WARN_PRINT("Mismatch argument name count for virtual method: " + String(p_class) + "::" + p_method.name);
} else {
for (int i = 0; i < p_arg_names.size(); i++) {
mi.arguments[i].name = (GDExtensionStringNamePtr)&p_arg_names[i];
}
}
internal::gdextension_interface_classdb_register_extension_class_virtual_method(internal::library, &p_class, &mi);
if (mi.arguments) {
memfree(mi.arguments);
}
if (mi.arguments_metadata) {
memfree(mi.arguments_metadata);
}
}
void ClassDB::initialize_class(const ClassInfo &p_cl) { void ClassDB::initialize_class(const ClassInfo &p_cl) {
} }

View File

@ -171,11 +171,13 @@ GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_na
GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to = nullptr; GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to = nullptr;
GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id = nullptr; GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id = nullptr;
GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id = nullptr; GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id = nullptr;
GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create = nullptr; GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method = nullptr;
GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method = nullptr;
GDExtensionInterfaceCallableCustomCreate2 gdextension_interface_callable_custom_create2 = nullptr;
GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata = nullptr; GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata = nullptr;
GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object = nullptr; GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object = nullptr;
GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object = nullptr; GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object = nullptr;
GDExtensionInterfaceScriptInstanceCreate2 gdextension_interface_script_instance_create2 = nullptr; GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3 = nullptr;
GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create = nullptr; GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create = nullptr;
GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update = nullptr; GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update = nullptr;
GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr; GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr;
@ -183,6 +185,7 @@ GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_metho
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr; GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2 = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2 = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = 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; GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed = nullptr;
@ -408,11 +411,13 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(object_cast_to, GDExtensionInterfaceObjectCastTo); LOAD_PROC_ADDRESS(object_cast_to, GDExtensionInterfaceObjectCastTo);
LOAD_PROC_ADDRESS(object_get_instance_from_id, GDExtensionInterfaceObjectGetInstanceFromId); LOAD_PROC_ADDRESS(object_get_instance_from_id, GDExtensionInterfaceObjectGetInstanceFromId);
LOAD_PROC_ADDRESS(object_get_instance_id, GDExtensionInterfaceObjectGetInstanceId); LOAD_PROC_ADDRESS(object_get_instance_id, GDExtensionInterfaceObjectGetInstanceId);
LOAD_PROC_ADDRESS(callable_custom_create, GDExtensionInterfaceCallableCustomCreate); LOAD_PROC_ADDRESS(object_has_script_method, GDExtensionInterfaceObjectHasScriptMethod);
LOAD_PROC_ADDRESS(object_call_script_method, GDExtensionInterfaceObjectCallScriptMethod);
LOAD_PROC_ADDRESS(callable_custom_create2, GDExtensionInterfaceCallableCustomCreate2);
LOAD_PROC_ADDRESS(callable_custom_get_userdata, GDExtensionInterfaceCallableCustomGetUserData); LOAD_PROC_ADDRESS(callable_custom_get_userdata, GDExtensionInterfaceCallableCustomGetUserData);
LOAD_PROC_ADDRESS(ref_get_object, GDExtensionInterfaceRefGetObject); LOAD_PROC_ADDRESS(ref_get_object, GDExtensionInterfaceRefGetObject);
LOAD_PROC_ADDRESS(ref_set_object, GDExtensionInterfaceRefSetObject); LOAD_PROC_ADDRESS(ref_set_object, GDExtensionInterfaceRefSetObject);
LOAD_PROC_ADDRESS(script_instance_create2, GDExtensionInterfaceScriptInstanceCreate2); LOAD_PROC_ADDRESS(script_instance_create3, GDExtensionInterfaceScriptInstanceCreate3);
LOAD_PROC_ADDRESS(placeholder_script_instance_create, GDExtensionInterfacePlaceHolderScriptInstanceCreate); LOAD_PROC_ADDRESS(placeholder_script_instance_create, GDExtensionInterfacePlaceHolderScriptInstanceCreate);
LOAD_PROC_ADDRESS(placeholder_script_instance_update, GDExtensionInterfacePlaceHolderScriptInstanceUpdate); LOAD_PROC_ADDRESS(placeholder_script_instance_update, GDExtensionInterfacePlaceHolderScriptInstanceUpdate);
LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject); LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject);
@ -420,6 +425,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag); LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
LOAD_PROC_ADDRESS(classdb_register_extension_class2, GDExtensionInterfaceClassdbRegisterExtensionClass2); LOAD_PROC_ADDRESS(classdb_register_extension_class2, GDExtensionInterfaceClassdbRegisterExtensionClass2);
LOAD_PROC_ADDRESS(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod); 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); LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);
LOAD_PROC_ADDRESS(classdb_register_extension_class_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty); LOAD_PROC_ADDRESS(classdb_register_extension_class_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty);
LOAD_PROC_ADDRESS(classdb_register_extension_class_property_indexed, GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed); LOAD_PROC_ADDRESS(classdb_register_extension_class_property_indexed, GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed);

View File

@ -35,6 +35,11 @@
namespace godot { namespace godot {
int CallableCustomBase::get_argument_count(bool &r_is_valid) const {
r_is_valid = false;
return 0;
}
static void callable_custom_call(void *p_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) { static void callable_custom_call(void *p_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
CallableCustom *callable_custom = (CallableCustom *)p_userdata; CallableCustom *callable_custom = (CallableCustom *)p_userdata;
callable_custom->call((const Variant **)p_args, p_argument_count, *(Variant *)r_return, *r_error); callable_custom->call((const Variant **)p_args, p_argument_count, *(Variant *)r_return, *r_error);
@ -84,13 +89,21 @@ static GDExtensionBool callable_custom_less_than_func(void *p_a, void *p_b) {
return func_a(a, b); return func_a(a, b);
} }
static GDExtensionInt custom_callable_get_argument_count_func(void *p_userdata, GDExtensionBool *r_is_valid) {
CallableCustom *callable_custom = (CallableCustom *)p_userdata;
bool valid = false;
int ret = callable_custom->get_argument_count(valid);
*r_is_valid = valid;
return ret;
}
bool CallableCustom::is_valid() const { bool CallableCustom::is_valid() const {
// The same default implementation as in Godot. // The same default implementation as in Godot.
return ObjectDB::get_instance(get_object()); return ObjectDB::get_instance(get_object());
} }
Callable::Callable(CallableCustom *p_callable_custom) { Callable::Callable(CallableCustom *p_callable_custom) {
GDExtensionCallableCustomInfo info = {}; GDExtensionCallableCustomInfo2 info = {};
info.callable_userdata = p_callable_custom; info.callable_userdata = p_callable_custom;
info.token = internal::token; info.token = internal::token;
info.object_id = p_callable_custom->get_object(); info.object_id = p_callable_custom->get_object();
@ -101,8 +114,9 @@ Callable::Callable(CallableCustom *p_callable_custom) {
info.equal_func = &callable_custom_equal_func; info.equal_func = &callable_custom_equal_func;
info.less_than_func = &callable_custom_less_than_func; info.less_than_func = &callable_custom_less_than_func;
info.to_string_func = &callable_custom_to_string; info.to_string_func = &callable_custom_to_string;
info.get_argument_count_func = &custom_callable_get_argument_count_func;
::godot::internal::gdextension_interface_callable_custom_create(_native_ptr(), &info); ::godot::internal::gdextension_interface_callable_custom_create2(_native_ptr(), &info);
} }
CallableCustom *Callable::get_custom() const { CallableCustom *Callable::get_custom() const {

View File

@ -77,6 +77,14 @@ static GDExtensionBool custom_callable_mp_less_than_func(void *p_a, void *p_b) {
return memcmp(a->get_comp_ptr(), b->get_comp_ptr(), a->get_comp_size() * 4) < 0; return memcmp(a->get_comp_ptr(), b->get_comp_ptr(), a->get_comp_size() * 4) < 0;
} }
static GDExtensionInt custom_callable_mp_get_argument_count_func(void *p_userdata, GDExtensionBool *r_is_valid) {
CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)p_userdata;
bool valid = false;
int ret = callable_method_pointer->get_argument_count(valid);
*r_is_valid = valid;
return ret;
}
void CallableCustomMethodPointerBase::_setup(uint32_t *p_base_ptr, uint32_t p_ptr_size) { void CallableCustomMethodPointerBase::_setup(uint32_t *p_base_ptr, uint32_t p_ptr_size) {
comp_ptr = p_base_ptr; comp_ptr = p_base_ptr;
comp_size = p_ptr_size / 4; comp_size = p_ptr_size / 4;
@ -93,7 +101,7 @@ void CallableCustomMethodPointerBase::_setup(uint32_t *p_base_ptr, uint32_t p_pt
namespace internal { namespace internal {
Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer) { Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer) {
GDExtensionCallableCustomInfo info = {}; GDExtensionCallableCustomInfo2 info = {};
info.callable_userdata = p_callable_method_pointer; info.callable_userdata = p_callable_method_pointer;
info.token = internal::token; info.token = internal::token;
info.object_id = p_callable_method_pointer->get_object(); info.object_id = p_callable_method_pointer->get_object();
@ -103,9 +111,10 @@ Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_m
info.hash_func = &custom_callable_mp_hash; info.hash_func = &custom_callable_mp_hash;
info.equal_func = &custom_callable_mp_equal_func; info.equal_func = &custom_callable_mp_equal_func;
info.less_than_func = &custom_callable_mp_less_than_func; info.less_than_func = &custom_callable_mp_less_than_func;
info.get_argument_count_func = &custom_callable_mp_get_argument_count_func;
Callable callable; Callable callable;
::godot::internal::gdextension_interface_callable_custom_create(callable._native_ptr(), &info); ::godot::internal::gdextension_interface_callable_custom_create2(callable._native_ptr(), &info);
return callable; return callable;
} }

5
test/project/example.gd Normal file
View File

@ -0,0 +1,5 @@
extends Example
func _do_something_virtual(p_name, p_value):
custom_signal.emit(p_name, p_value)
return "Implemented"

View File

@ -102,6 +102,7 @@ func _ready():
# mp_callable() with void method. # mp_callable() with void method.
var mp_callable: Callable = example.test_callable_mp() var mp_callable: Callable = example.test_callable_mp()
assert_equal(mp_callable.is_valid(), true) assert_equal(mp_callable.is_valid(), true)
assert_equal(mp_callable.get_argument_count(), 3)
mp_callable.call(example, "void", 36) mp_callable.call(example, "void", 36)
assert_equal(custom_signal_emitted, ["unbound_method1: Example - void", 36]) assert_equal(custom_signal_emitted, ["unbound_method1: Example - void", 36])
@ -117,14 +118,17 @@ func _ready():
# mp_callable() with return value. # mp_callable() with return value.
var mp_callable_ret: Callable = example.test_callable_mp_ret() var mp_callable_ret: Callable = example.test_callable_mp_ret()
assert_equal(mp_callable_ret.get_argument_count(), 3)
assert_equal(mp_callable_ret.call(example, "test", 77), "unbound_method2: Example - test - 77") assert_equal(mp_callable_ret.call(example, "test", 77), "unbound_method2: Example - test - 77")
# mp_callable() with const method and return value. # mp_callable() with const method and return value.
var mp_callable_retc: Callable = example.test_callable_mp_retc() var mp_callable_retc: Callable = example.test_callable_mp_retc()
assert_equal(mp_callable_retc.get_argument_count(), 3)
assert_equal(mp_callable_retc.call(example, "const", 101), "unbound_method3: Example - const - 101") assert_equal(mp_callable_retc.call(example, "const", 101), "unbound_method3: Example - const - 101")
# mp_callable_static() with void method. # mp_callable_static() with void method.
var mp_callable_static: Callable = example.test_callable_mp_static() var mp_callable_static: Callable = example.test_callable_mp_static()
assert_equal(mp_callable_static.get_argument_count(), 3)
mp_callable_static.call(example, "static", 83) mp_callable_static.call(example, "static", 83)
assert_equal(custom_signal_emitted, ["unbound_static_method1: Example - static", 83]) assert_equal(custom_signal_emitted, ["unbound_static_method1: Example - static", 83])
@ -140,6 +144,7 @@ func _ready():
# mp_callable_static() with return value. # mp_callable_static() with return value.
var mp_callable_static_ret: Callable = example.test_callable_mp_static_ret() var mp_callable_static_ret: Callable = example.test_callable_mp_static_ret()
assert_equal(mp_callable_static_ret.get_argument_count(), 3)
assert_equal(mp_callable_static_ret.call(example, "static-ret", 84), "unbound_static_method2: Example - static-ret - 84") assert_equal(mp_callable_static_ret.call(example, "static-ret", 84), "unbound_static_method2: Example - static-ret - 84")
# CallableCustom. # CallableCustom.
@ -150,6 +155,7 @@ func _ready():
assert_equal(custom_callable.hash(), 27); assert_equal(custom_callable.hash(), 27);
assert_equal(custom_callable.get_object(), null); assert_equal(custom_callable.get_object(), null);
assert_equal(custom_callable.get_method(), ""); assert_equal(custom_callable.get_method(), "");
assert_equal(custom_callable.get_argument_count(), 2)
assert_equal(str(custom_callable), "<MyCallableCustom>"); assert_equal(str(custom_callable), "<MyCallableCustom>");
# PackedArray iterators # PackedArray iterators
@ -241,6 +247,10 @@ func _ready():
assert_equal(new_example_ref.was_post_initialized(), true) assert_equal(new_example_ref.was_post_initialized(), true)
assert_equal(example.test_post_initialize(), true) assert_equal(example.test_post_initialize(), true)
# Test a virtual method defined in GDExtension and implemented in script.
assert_equal(example.test_virtual_implemented_in_script("Virtual", 939), "Implemented")
assert_equal(custom_signal_emitted, ["Virtual", 939])
exit_with_status() exit_with_status()
func _on_Example_custom_signal(signal_name, value): func _on_Example_custom_signal(signal_name, value):

View File

@ -1,11 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://dmx2xuigcpvt4"] [gd_scene load_steps=3 format=3 uid="uid://dmx2xuigcpvt4"]
[ext_resource type="Script" path="res://main.gd" id="1_qesh5"] [ext_resource type="Script" path="res://main.gd" id="1_qesh5"]
[ext_resource type="Script" path="res://example.gd" id="2_jju25"]
[node name="Node" type="Node"] [node name="Node" type="Node"]
script = ExtResource("1_qesh5") script = ExtResource("1_qesh5")
[node name="Example" type="Example" parent="."] [node name="Example" type="Example" parent="."]
script = ExtResource("2_jju25")
[node name="ExampleMin" type="ExampleMin" parent="Example"] [node name="ExampleMin" type="ExampleMin" parent="Example"]
layout_mode = 0 layout_mode = 0

View File

@ -49,6 +49,11 @@ public:
return ObjectID(); return ObjectID();
} }
virtual int get_argument_count(bool &r_is_valid) const {
r_is_valid = true;
return 2;
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const { virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const {
r_return_value = "Hi"; r_return_value = "Hi";
r_call_error.error = GDEXTENSION_CALL_OK; r_call_error.error = GDEXTENSION_CALL_OK;
@ -230,6 +235,9 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("callable_bind"), &Example::callable_bind); ClassDB::bind_method(D_METHOD("callable_bind"), &Example::callable_bind);
ClassDB::bind_method(D_METHOD("test_post_initialize"), &Example::test_post_initialize); ClassDB::bind_method(D_METHOD("test_post_initialize"), &Example::test_post_initialize);
GDVIRTUAL_BIND(_do_something_virtual, "name", "value");
ClassDB::bind_method(D_METHOD("test_virtual_implemented_in_script"), &Example::test_virtual_implemented_in_script);
ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static); 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); ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2);
@ -626,3 +634,11 @@ void Example::_input(const Ref<InputEvent> &event) {
emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode()); emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode());
} }
} }
String Example::test_virtual_implemented_in_script(const String &p_name, int p_value) {
String ret;
if (GDVIRTUAL_CALL(_do_something_virtual, p_name, p_value, ret)) {
return ret;
}
return "Unimplemented";
}

View File

@ -24,6 +24,7 @@
#include <godot_cpp/variant/variant.hpp> #include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/core/binder_common.hpp> #include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/gdvirtual.gen.inc>
using namespace godot; using namespace godot;
@ -181,6 +182,9 @@ public:
// Virtual function override (no need to bind manually). // Virtual function override (no need to bind manually).
virtual bool _has_point(const Vector2 &point) const override; virtual bool _has_point(const Vector2 &point) const override;
virtual void _input(const Ref<InputEvent> &event) override; virtual void _input(const Ref<InputEvent> &event) override;
GDVIRTUAL2R(String, _do_something_virtual, String, int);
String test_virtual_implemented_in_script(const String &p_name, int p_value);
}; };
VARIANT_ENUM_CAST(Example::Constants); VARIANT_ENUM_CAST(Example::Constants);