Compare commits
8 Commits
00ca87a6eb
...
9b138f2163
Author | SHA1 | Date |
---|---|---|
Kehom | 9b138f2163 | |
David Snopek | 5fcc43e54d | |
David Snopek | 9a13efa0e3 | |
David Snopek | 8fbb7cf795 | |
DaylilyZeleen | 6a3753c076 | |
David Snopek | 7c547c6c6b | |
Allen Pestaluky | 349b5a3146 | |
Kehom | 35905b11f3 |
17
SConstruct
17
SConstruct
|
@ -21,16 +21,15 @@ env.PrependENVPath("PATH", os.getenv("PATH"))
|
|||
|
||||
# Custom options and profile flags.
|
||||
customs = ["custom.py"]
|
||||
try:
|
||||
customs += Import("customs")
|
||||
except:
|
||||
pass
|
||||
profile = ARGUMENTS.get("profile", "")
|
||||
if profile:
|
||||
if os.path.isfile(profile):
|
||||
customs.append(profile)
|
||||
elif os.path.isfile(profile + ".py"):
|
||||
customs.append(profile + ".py")
|
||||
if not profile.endswith('.py'):
|
||||
profile += '.py'
|
||||
|
||||
path = str(Entry('#' + profile))
|
||||
|
||||
if (os.path.isfile(path)):
|
||||
customs.append(path)
|
||||
opts = Variables(customs, ARGUMENTS)
|
||||
cpp_tool = Tool("godotcpp", toolpath=["tools"])
|
||||
cpp_tool.options(opts, env)
|
||||
|
@ -39,6 +38,8 @@ opts.Update(env)
|
|||
Help(opts.GenerateHelpText(env))
|
||||
|
||||
# Detect and print a warning listing unknown SCons variables to ease troubleshooting.
|
||||
# But only do that if this is top level SConstruct, not subsidiary
|
||||
if Dir("#").abspath == Dir(".").abspath:
|
||||
unknown = opts.UnknownVariables()
|
||||
if unknown:
|
||||
print("WARNING: Unknown SCons variables were passed and will be ignored:")
|
||||
|
|
|
@ -70,6 +70,136 @@ def generate_wrappers(target):
|
|||
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):
|
||||
api = {}
|
||||
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"
|
||||
|
||||
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"]:
|
||||
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)
|
||||
|
||||
generate_wrappers(core_gen_folder / "ext_wrappers.gen.inc")
|
||||
generate_virtuals(core_gen_folder / "gdvirtual.gen.inc")
|
||||
|
||||
# Store types beforehand.
|
||||
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 + "{")
|
||||
|
||||
method_call = "\t"
|
||||
is_ref = False
|
||||
|
||||
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:
|
||||
method_call += "internal::_call_builtin_method_ptr_no_ret("
|
||||
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
|
||||
arguments.append(arg_name)
|
||||
method_call += ", ".join(arguments)
|
||||
|
||||
if is_ref:
|
||||
method_call += ")" # Close Ref<> constructor.
|
||||
method_call += ");"
|
||||
|
||||
result.append(method_call)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <godot_cpp/core/property_info.hpp>
|
||||
|
||||
#include <godot_cpp/templates/list.hpp>
|
||||
#include <godot_cpp/templates/vector.hpp>
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
|
@ -107,6 +108,26 @@ public:
|
|||
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 {
|
||||
|
||||
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.
|
||||
#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
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define GODOT_BUILTIN_PTRCALL_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
|
@ -39,6 +40,17 @@ namespace godot {
|
|||
|
||||
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>
|
||||
void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) {
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
|
|
|
@ -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_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);
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ struct MethodInfo {
|
|||
int id = 0;
|
||||
std::vector<PropertyInfo> 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 ? (name < p_method.name) : (id < p_method.id); }
|
||||
|
|
|
@ -80,6 +80,17 @@ struct PropertyInfo {
|
|||
p_info->usage = usage;
|
||||
*(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
|
||||
|
|
|
@ -370,11 +370,14 @@ MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
|
|||
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
|
||||
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(Quaternion, Variant::QUATERNION)
|
||||
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
|
||||
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
|
||||
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(StringName, Variant::STRING_NAME)
|
||||
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<Vector3>, Variant::PACKED_VECTOR3_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())
|
||||
|
||||
} // namespace godot
|
||||
|
|
|
@ -165,6 +165,8 @@ extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_g
|
|||
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
|
||||
extern "C" GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method;
|
||||
extern "C" GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method;
|
||||
extern "C" GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create;
|
||||
extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
|
||||
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
|
||||
|
@ -177,6 +179,7 @@ extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classd
|
|||
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2;
|
||||
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" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed;
|
||||
|
|
|
@ -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(uint8_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(Vector3i, Variant::VECTOR3I)
|
||||
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(Quaternion, Variant::QUATERNION)
|
||||
MAKE_TYPED_ARRAY(AABB, Variant::AABB)
|
||||
MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
|
||||
MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D)
|
||||
MAKE_TYPED_ARRAY(Projection, Variant::PROJECTION)
|
||||
MAKE_TYPED_ARRAY(Color, Variant::COLOR)
|
||||
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
|
||||
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(PackedVector3Array, Variant::PACKED_VECTOR3_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
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
#include <godot_cpp/templates/vector.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;
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,8 @@ GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_na
|
|||
GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to = nullptr;
|
||||
GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id = nullptr;
|
||||
GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id = nullptr;
|
||||
GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method = nullptr;
|
||||
GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method = nullptr;
|
||||
GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create = nullptr;
|
||||
GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata = nullptr;
|
||||
GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object = nullptr;
|
||||
|
@ -183,6 +185,7 @@ GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_metho
|
|||
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr;
|
||||
GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2 = 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;
|
||||
GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property = nullptr;
|
||||
GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed = nullptr;
|
||||
|
@ -408,6 +411,8 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
|
|||
LOAD_PROC_ADDRESS(object_cast_to, GDExtensionInterfaceObjectCastTo);
|
||||
LOAD_PROC_ADDRESS(object_get_instance_from_id, GDExtensionInterfaceObjectGetInstanceFromId);
|
||||
LOAD_PROC_ADDRESS(object_get_instance_id, GDExtensionInterfaceObjectGetInstanceId);
|
||||
LOAD_PROC_ADDRESS(object_has_script_method, GDExtensionInterfaceObjectHasScriptMethod);
|
||||
LOAD_PROC_ADDRESS(object_call_script_method, GDExtensionInterfaceObjectCallScriptMethod);
|
||||
LOAD_PROC_ADDRESS(callable_custom_create, GDExtensionInterfaceCallableCustomCreate);
|
||||
LOAD_PROC_ADDRESS(callable_custom_get_userdata, GDExtensionInterfaceCallableCustomGetUserData);
|
||||
LOAD_PROC_ADDRESS(ref_get_object, GDExtensionInterfaceRefGetObject);
|
||||
|
@ -420,6 +425,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
|
|||
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
|
||||
LOAD_PROC_ADDRESS(classdb_register_extension_class2, GDExtensionInterfaceClassdbRegisterExtensionClass2);
|
||||
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_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty);
|
||||
LOAD_PROC_ADDRESS(classdb_register_extension_class_property_indexed, GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
extends Example
|
||||
|
||||
func _do_something_virtual(p_name, p_value):
|
||||
custom_signal.emit(p_name, p_value)
|
||||
return "Implemented"
|
|
@ -241,6 +241,10 @@ func _ready():
|
|||
assert_equal(new_example_ref.was_post_initialized(), 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()
|
||||
|
||||
func _on_Example_custom_signal(signal_name, value):
|
||||
|
|
|
@ -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://example.gd" id="2_jju25"]
|
||||
|
||||
[node name="Node" type="Node"]
|
||||
script = ExtResource("1_qesh5")
|
||||
|
||||
[node name="Example" type="Example" parent="."]
|
||||
script = ExtResource("2_jju25")
|
||||
|
||||
[node name="ExampleMin" type="ExampleMin" parent="Example"]
|
||||
layout_mode = 0
|
||||
|
|
|
@ -230,6 +230,9 @@ void Example::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("callable_bind"), &Example::callable_bind);
|
||||
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_static2"), &Example::test_static2);
|
||||
|
||||
|
@ -626,3 +629,11 @@ void Example::_input(const Ref<InputEvent> &event) {
|
|||
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";
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
#include <godot_cpp/core/gdvirtual.gen.inc>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
|
@ -181,6 +182,9 @@ public:
|
|||
// Virtual function override (no need to bind manually).
|
||||
virtual bool _has_point(const Vector2 &point) const 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);
|
||||
|
|
|
@ -198,6 +198,15 @@ def options(opts, env):
|
|||
)
|
||||
)
|
||||
|
||||
opts.Add(
|
||||
PathVariable(
|
||||
key="profile",
|
||||
help="Allow specification of customization file other than `custom.py`.",
|
||||
default=env.get("profile", None),
|
||||
validator=validate_file,
|
||||
)
|
||||
)
|
||||
|
||||
# Add platform options
|
||||
for pl in platforms:
|
||||
tool = Tool(pl, toolpath=["tools"])
|
||||
|
|
Loading…
Reference in New Issue