From 031a83b0ea6b147c9466529b123cb149a52ea395 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Wed, 4 May 2022 14:27:08 +0300 Subject: [PATCH] [Method Bind] Add support for default argument values and static method binding. Sync headers. --- godot-headers/extension_api.json | 463 ++++++++++++++++++++--- include/godot_cpp/core/binder_common.hpp | 112 ++++++ include/godot_cpp/core/class_db.hpp | 33 +- include/godot_cpp/core/method_bind.hpp | 146 ++++++- include/godot_cpp/core/object.hpp | 6 +- src/core/class_db.cpp | 46 ++- src/core/method_bind.cpp | 8 + src/core/object.cpp | 10 +- test/demo/main.gd | 47 ++- test/src/example.cpp | 33 +- test/src/example.h | 5 + 11 files changed, 794 insertions(+), 115 deletions(-) diff --git a/godot-headers/extension_api.json b/godot-headers/extension_api.json index 4a0658f3..ed204aa3 100644 --- a/godot-headers/extension_api.json +++ b/godot-headers/extension_api.json @@ -8290,7 +8290,7 @@ "hash": 3, "arguments": [ { - "name": "phi", + "name": "angle", "type": "float" } ] @@ -9779,11 +9779,11 @@ "hash": 3, "arguments": [ { - "name": "by_axis", + "name": "axis", "type": "Vector3" }, { - "name": "phi", + "name": "angle", "type": "float" } ] @@ -10557,7 +10557,7 @@ "hash": 3, "arguments": [ { - "name": "phi", + "name": "angle", "type": "float" } ] @@ -11997,7 +11997,7 @@ "type": "Vector3" }, { - "name": "phi", + "name": "angle", "type": "float" } ] @@ -12212,7 +12212,7 @@ "type": "Vector3" }, { - "name": "phi", + "name": "angle", "type": "float" } ] @@ -12372,7 +12372,7 @@ "type": "Vector3" }, { - "name": "phi", + "name": "angle", "type": "float" } ] @@ -30002,56 +30002,6 @@ } ] }, - { - "name": "set_start_node", - "is_const": false, - "is_vararg": false, - "is_static": false, - "is_virtual": false, - "hash": 134188166, - "arguments": [ - { - "name": "name", - "type": "StringName" - } - ] - }, - { - "name": "get_start_node", - "is_const": true, - "is_vararg": false, - "is_static": false, - "is_virtual": false, - "hash": 135338183, - "return_value": { - "type": "String" - } - }, - { - "name": "set_end_node", - "is_const": false, - "is_vararg": false, - "is_static": false, - "is_virtual": false, - "hash": 134188166, - "arguments": [ - { - "name": "name", - "type": "StringName" - } - ] - }, - { - "name": "get_end_node", - "is_const": true, - "is_vararg": false, - "is_static": false, - "is_virtual": false, - "hash": 135338183, - "return_value": { - "type": "String" - } - }, { "name": "set_graph_offset", "is_const": false, @@ -120220,6 +120170,156 @@ } ] }, + { + "name": "MissingNode", + "is_refcounted": false, + "is_instantiable": true, + "inherits": "Node", + "api_type": "core", + "methods": [ + { + "name": "set_original_class", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "name", + "type": "String" + } + ] + }, + { + "name": "get_original_class", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135338183, + "return_value": { + "type": "String" + } + }, + { + "name": "set_recording_properties", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "enable", + "type": "bool" + } + ] + }, + { + "name": "is_recording_properties", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135338183, + "return_value": { + "type": "bool" + } + } + ], + "properties": [ + { + "type": "String", + "name": "original_class", + "setter": "set_original_class", + "getter": "get_original_class", + "index": -1 + }, + { + "type": "bool", + "name": "recording_properties", + "setter": "set_recording_properties", + "getter": "is_recording_properties", + "index": -1 + } + ] + }, + { + "name": "MissingResource", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "Resource", + "api_type": "core", + "methods": [ + { + "name": "set_original_class", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "name", + "type": "String" + } + ] + }, + { + "name": "get_original_class", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135338183, + "return_value": { + "type": "String" + } + }, + { + "name": "set_recording_properties", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "enable", + "type": "bool" + } + ] + }, + { + "name": "is_recording_properties", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135338183, + "return_value": { + "type": "bool" + } + } + ], + "properties": [ + { + "type": "String", + "name": "original_class", + "setter": "set_original_class", + "getter": "get_original_class", + "index": -1 + }, + { + "type": "bool", + "name": "recording_properties", + "setter": "set_recording_properties", + "getter": "is_recording_properties", + "index": -1 + } + ] + }, { "name": "MobileVRInterface", "is_refcounted": true, @@ -124876,7 +124976,14 @@ "is_vararg": false, "is_static": false, "is_virtual": false, - "hash": 134152229 + "hash": 133279208, + "arguments": [ + { + "name": "on_thread", + "type": "bool", + "default_value": "true" + } + ] } ], "signals": [ @@ -130865,6 +130972,24 @@ } ] }, + { + "name": "is_process_running", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135374120, + "return_value": { + "type": "bool" + }, + "arguments": [ + { + "name": "pid", + "type": "int", + "meta": "int32" + } + ] + }, { "name": "get_process_id", "is_const": true, @@ -151227,6 +151352,206 @@ } ] }, + { + "name": "PlaceholderCubemap", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "PlaceholderTextureLayered", + "api_type": "core" + }, + { + "name": "PlaceholderCubemapArray", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "PlaceholderTextureLayered", + "api_type": "core" + }, + { + "name": "PlaceholderMaterial", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "Material", + "api_type": "core" + }, + { + "name": "PlaceholderMesh", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "Mesh", + "api_type": "core", + "methods": [ + { + "name": "set_aabb", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "aabb", + "type": "AABB" + } + ] + } + ], + "properties": [ + { + "type": "AABB", + "name": "aabb", + "setter": "set_aabb", + "getter": "get_aabb", + "index": -1 + } + ] + }, + { + "name": "PlaceholderTexture2D", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "Texture2D", + "api_type": "core", + "methods": [ + { + "name": "set_size", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "size", + "type": "Vector2" + } + ] + } + ], + "properties": [ + { + "type": "Vector2i", + "name": "size", + "setter": "set_size", + "getter": "get_size", + "index": -1 + } + ] + }, + { + "name": "PlaceholderTexture2DArray", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "PlaceholderTextureLayered", + "api_type": "core" + }, + { + "name": "PlaceholderTexture3D", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "Texture3D", + "api_type": "core", + "methods": [ + { + "name": "set_size", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "size", + "type": "Vector3i" + } + ] + }, + { + "name": "get_size", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135338183, + "return_value": { + "type": "Vector3i" + } + } + ], + "properties": [ + { + "type": "Vector3i", + "name": "size", + "setter": "set_size", + "getter": "get_size", + "index": -1 + } + ] + }, + { + "name": "PlaceholderTextureLayered", + "is_refcounted": true, + "is_instantiable": false, + "inherits": "TextureLayered", + "api_type": "core", + "methods": [ + { + "name": "set_size", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "size", + "type": "Vector2i" + } + ] + }, + { + "name": "get_size", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135338183, + "return_value": { + "type": "Vector2i" + } + }, + { + "name": "set_layers", + "is_const": false, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 134188166, + "arguments": [ + { + "name": "layers", + "type": "int", + "meta": "int32" + } + ] + } + ], + "properties": [ + { + "type": "Vector2i", + "name": "size", + "setter": "set_size", + "getter": "get_size", + "index": -1 + }, + { + "type": "int", + "name": "layers", + "setter": "set_layers", + "getter": "get_layers", + "index": -1 + } + ] + }, { "name": "PlaneMesh", "is_refcounted": true, @@ -176586,6 +176911,17 @@ "type": "enum::RenderingDevice.DeviceType" } }, + { + "name": "get_video_adapter_api_version", + "is_const": true, + "is_vararg": false, + "is_static": false, + "is_virtual": false, + "hash": 135338183, + "return_value": { + "type": "String" + } + }, { "name": "make_sphere_mesh", "is_const": false, @@ -215014,6 +215350,13 @@ } ] }, + { + "name": "TextServerFallback", + "is_refcounted": true, + "is_instantiable": true, + "inherits": "TextServerExtension", + "api_type": "core" + }, { "name": "TextServerManager", "is_refcounted": false, @@ -223084,7 +223427,7 @@ ] }, { - "name": "get_datetime_dict_from_string", + "name": "get_datetime_dict_from_datetime_string", "is_const": true, "is_vararg": false, "is_static": false, @@ -223105,7 +223448,7 @@ ] }, { - "name": "get_datetime_string_from_dict", + "name": "get_datetime_string_from_datetime_dict", "is_const": true, "is_vararg": false, "is_static": false, diff --git a/include/godot_cpp/core/binder_common.hpp b/include/godot_cpp/core/binder_common.hpp index ff6621bb..d622470c 100644 --- a/include/godot_cpp/core/binder_common.hpp +++ b/include/godot_cpp/core/binder_common.hpp @@ -440,6 +440,118 @@ GDNativeExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_ar return md; } +template +void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDNativeCallError &r_error, IndexSequence) { + r_error.error = GDNATIVE_CALL_OK; + +#ifdef DEBUG_METHODS_ENABLED + (p_method)(VariantCasterAndValidate

::cast(p_args, Is, r_error)...); +#else + (p_method)(VariantCaster

::cast(*p_args[Is])...); +#endif +} + +template +void call_with_variant_args_static_dv(void (*p_method)(P...), const GDNativeVariantPtr *p_args, int p_argcount, GDNativeCallError &r_error, const std::vector &default_values) { +#ifdef DEBUG_ENABLED + if ((size_t)p_argcount > sizeof...(P)) { + r_error.error = GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } +#endif + + int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount; + + int32_t dvs = default_values.size(); +#ifdef DEBUG_ENABLED + if (missing > dvs) { + r_error.error = GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } +#endif + + Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array. + std::array argsp; + for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) { + if (i < p_argcount) { + args[i] = Variant(p_args[i]); + } else { + args[i] = default_values[i - p_argcount + (dvs - missing)]; + } + argsp[i] = &args[i]; + } + + call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence{}); +} + +template +void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDNativeTypePtr *p_args, IndexSequence) { + p_method(PtrToArg

::convert(p_args[Is])...); +} + +template +void call_with_ptr_args_static_method(void (*p_method)(P...), const GDNativeTypePtr *p_args) { + call_with_ptr_args_static_method_helper(p_method, p_args, BuildIndexSequence{}); +} + +template +void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDNativeCallError &r_error, IndexSequence) { + r_error.error = GDNATIVE_CALL_OK; + +#ifdef DEBUG_METHODS_ENABLED + r_ret = (p_method)(VariantCasterAndValidate

::cast(p_args, Is, r_error)...); +#else + r_ret = (p_method)(VariantCaster

::cast(*p_args[Is])...); +#endif +} + +template +void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDNativeVariantPtr *p_args, int p_argcount, Variant &r_ret, GDNativeCallError &r_error, const std::vector &default_values) { +#ifdef DEBUG_ENABLED + if ((size_t)p_argcount > sizeof...(P)) { + r_error.error = GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } +#endif + + int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount; + + int32_t dvs = default_values.size(); +#ifdef DEBUG_ENABLED + if (missing > dvs) { + r_error.error = GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } +#endif + + Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array. + std::array argsp; + for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) { + if (i < p_argcount) { + args[i] = Variant(p_args[i]); + } else { + args[i] = default_values[i - p_argcount + (dvs - missing)]; + } + argsp[i] = &args[i]; + } + + call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence{}); +} + +template +void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDNativeTypePtr *p_args, void *r_ret, IndexSequence) { + PtrToArg::encode(p_method(PtrToArg

::convert(p_args[Is])...), r_ret); +} + +template +void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDNativeTypePtr *p_args, void *r_ret) { + call_with_ptr_args_static_method_ret_helper(p_method, p_args, r_ret, BuildIndexSequence{}); +} + #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 2034c272..71005f50 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -46,6 +46,8 @@ namespace godot { +#define DEFVAL(m_defval) (m_defval) + struct MethodDefinition { const char *name = nullptr; std::list args; @@ -101,10 +103,15 @@ public: template static void register_class(); - template - static MethodBind *bind_method(N p_method_name, M p_method); + template + static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args); + + template + static MethodBind *bind_static_method(const char *p_class, N p_method_name, M p_method, VarArgs... p_args); + template static MethodBind *bind_vararg_method(uint32_t p_flags, const char *p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector &p_default_args = std::vector{}, bool p_return_nil_is_variant = true); + static void add_property_group(const char *p_class, const char *p_name, const char *p_prefix); static void add_property_subgroup(const char *p_class, const char *p_name, const char *p_prefix); static void add_property(const char *p_class, const PropertyInfo &p_pinfo, const char *p_setter, const char *p_getter, int p_index = -1); @@ -172,11 +179,27 @@ void ClassDB::register_class() { initialize_class(classes[cl.name]); } -template -MethodBind *ClassDB::bind_method(N p_method_name, M p_method) { +template +MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } MethodBind *bind = create_method_bind(p_method); + return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args)); +} - return bind_methodfi(0, bind, p_method_name, nullptr, 0); +template +MethodBind *ClassDB::bind_static_method(const char *p_class, N p_method_name, M p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + MethodBind *bind = create_static_method_bind(p_method); + bind->set_instance_class(p_class); + return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args)); } template diff --git a/include/godot_cpp/core/method_bind.hpp b/include/godot_cpp/core/method_bind.hpp index ba082e6d..379b62e6 100644 --- a/include/godot_cpp/core/method_bind.hpp +++ b/include/godot_cpp/core/method_bind.hpp @@ -53,8 +53,10 @@ class MethodBind { int argument_count = 0; uint32_t hint_flags = METHOD_FLAGS_DEFAULT; + bool _static = false; bool _is_const = false; bool _has_return = false; + bool _vararg = false; std::vector argument_names; GDNativeVariantType *argument_types = nullptr; @@ -66,6 +68,8 @@ protected: void generate_argument_types(int p_count); void set_const(bool p_const); void set_return(bool p_return); + void set_static(bool p_static); + void set_vararg(bool p_vararg); void set_argument_count(int p_count); public: @@ -96,8 +100,10 @@ public: _FORCE_INLINE_ int get_argument_count() const { return argument_count; }; _FORCE_INLINE_ bool is_const() const { return _is_const; } + _FORCE_INLINE_ bool is_static() const { return _static; } + _FORCE_INLINE_ bool is_vararg() const { return _vararg; } _FORCE_INLINE_ bool has_return() const { return _has_return; } - _FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags; } + _FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDNATIVE_EXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDNATIVE_EXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDNATIVE_EXTENSION_METHOD_FLAG_STATIC : 0); } _FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; } void set_argument_names(const std::vector &p_names); std::vector get_argument_names() const; @@ -155,15 +161,13 @@ public: ERR_FAIL(); // Can't call. } - virtual bool is_const() const { return false; } - - virtual bool is_vararg() const { return true; } - MethodBindVarArgBase( R (T::*p_method)(const Variant **, GDNativeInt, GDNativeCallError &), const MethodInfo &p_method_info, bool p_return_nil_is_variant) : method(p_method), method_info(p_method_info) { + set_vararg(true); + set_const(true); set_argument_count(method_info.arguments.size()); if (method_info.arguments.size()) { std::vector names; @@ -572,6 +576,138 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) { return a; } +// STATIC BINDS + +// no return + +template +class MethodBindTS : public MethodBind { + void (*function)(P...); + +protected: +// GCC raises warnings in the case P = {} as the comparison is always false... +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wlogical-op" +#endif + virtual GDNativeVariantType gen_argument_type(int p_arg) const { + if (p_arg >= 0 && p_arg < (int)sizeof...(P)) { + return call_get_argument_type(p_arg); + } else { + return GDNATIVE_VARIANT_TYPE_NIL; + } + } + + virtual GDNativePropertyInfo gen_argument_type_info(int p_arg) const { + GDNativePropertyInfo pi; + call_get_argument_type_info(p_arg, pi); + return pi; + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + +public: + virtual GDNativeExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const { + return call_get_argument_metadata(p_arg); + } + + virtual Variant call(GDExtensionClassInstancePtr p_object, const GDNativeVariantPtr *p_args, const GDNativeInt p_arg_count, GDNativeCallError &r_error) const { + (void)p_object; // unused + call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments()); + return Variant(); + } + + virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret) const { + (void)p_object; + (void)r_ret; + call_with_ptr_args_static_method(function, p_args); + } + + MethodBindTS(void (*p_function)(P...)) { + function = p_function; + generate_argument_types(sizeof...(P)); + set_argument_count(sizeof...(P)); + set_static(true); + } +}; + +template +MethodBind *create_static_method_bind(void (*p_method)(P...)) { + MethodBind *a = memnew((MethodBindTS)(p_method)); + return a; +} + +// return + +template +class MethodBindTRS : public MethodBind { + R(*function) + (P...); + +protected: +// GCC raises warnings in the case P = {} as the comparison is always false... +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wlogical-op" +#endif + virtual GDNativeVariantType gen_argument_type(int p_arg) const { + if (p_arg >= 0 && p_arg < (int)sizeof...(P)) { + return call_get_argument_type(p_arg); + } else { + return GetTypeInfo::VARIANT_TYPE; + } + } + + virtual GDNativePropertyInfo gen_argument_type_info(int p_arg) const { + if (p_arg >= 0 && p_arg < (int)sizeof...(P)) { + GDNativePropertyInfo pi; + call_get_argument_type_info(p_arg, pi); + return pi; + } else { + return GetTypeInfo::get_class_info(); + } + } + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + +public: + virtual GDNativeExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const { + if (p_arg >= 0) { + return call_get_argument_metadata(p_arg); + } else { + return GetTypeInfo::METADATA; + } + } + + virtual Variant call(GDExtensionClassInstancePtr p_object, const GDNativeVariantPtr *p_args, const GDNativeInt p_arg_count, GDNativeCallError &r_error) const { + Variant ret; + call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments()); + return ret; + } + + virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret) const { + (void)p_object; + call_with_ptr_args_static_method_ret(function, p_args, r_ret); + } + + MethodBindTRS(R (*p_function)(P...)) { + function = p_function; + generate_argument_types(sizeof...(P)); + set_argument_count(sizeof...(P)); + set_static(true); + set_return(true); + } +}; + +template +MethodBind *create_static_method_bind(R (*p_method)(P...)) { + MethodBind *a = memnew((MethodBindTRS)(p_method)); + return a; +} + } // namespace godot #endif // ! GODOT_CPP_METHOD_BIND_HPP diff --git a/include/godot_cpp/core/object.hpp b/include/godot_cpp/core/object.hpp index fb8974d7..6b1bed9d 100644 --- a/include/godot_cpp/core/object.hpp +++ b/include/godot_cpp/core/object.hpp @@ -117,20 +117,20 @@ struct MethodInfo { template MethodInfo::MethodInfo(const char *p_name, const Args &...args) : - name(p_name), flags(METHOD_FLAG_NORMAL) { + name(p_name), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) { arguments = { args... }; } template MethodInfo::MethodInfo(Variant::Type ret, const char *p_name, const Args &...args) : - name(p_name), flags(METHOD_FLAG_NORMAL) { + name(p_name), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) { return_val.type = ret; arguments = { args... }; } template MethodInfo::MethodInfo(const PropertyInfo &p_ret, const char *p_name, const Args &...args) : - name(p_name), return_val(p_ret), flags(METHOD_FLAG_NORMAL) { + name(p_name), return_val(p_ret), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) { arguments = { args... }; } diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp index f750fca4..44b953a0 100644 --- a/src/core/class_db.cpp +++ b/src/core/class_db.cpp @@ -95,9 +95,9 @@ void ClassDB::add_property(const char *p_class, const PropertyInfo &p_pinfo, con // register with Godot GDNativePropertyInfo prop_info = { - (uint32_t)p_pinfo.type, //uint32_t type; - p_pinfo.name, //const char *name; - p_pinfo.class_name, //const char *class_name; + (uint32_t)p_pinfo.type, // uint32_t type; + p_pinfo.name, // const char *name; + p_pinfo.class_name, // const char *class_name; p_pinfo.hint, // NONE //uint32_t hint; p_pinfo.hint_string, // const char *hint_string; p_pinfo.usage, // DEFAULT //uint32_t usage; @@ -169,6 +169,16 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const M p_bind->set_argument_names(args); + std::vector defvals; + + defvals.resize(p_defcount); + for (int i = 0; i < p_defcount; i++) { + defvals[i] = *static_cast(p_defs[i]); + } + + p_bind->set_default_arguments(defvals); + p_bind->set_hint_flags(p_flags); + // register our method bind within our plugin type.method_map[method_name.name] = p_bind; @@ -179,19 +189,27 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const M } void ClassDB::bind_method_godot(const char *p_class_name, MethodBind *p_method) { + std::vector def_args; + const std::vector &def_args_val = p_method->get_default_arguments(); + + def_args.resize(def_args_val.size()); + for (int i = 0; i < def_args_val.size(); i++) { + def_args[i] = (GDNativeVariantPtr)&def_args_val[i]; + } + GDNativeExtensionClassMethodInfo method_info = { - p_method->get_name(), //const char *name; - p_method, //void *method_userdata; - MethodBind::bind_call, //GDNativeExtensionClassMethodCall call_func; - MethodBind::bind_ptrcall, //GDNativeExtensionClassMethodPtrCall ptrcall_func; - GDNATIVE_EXTENSION_METHOD_FLAGS_DEFAULT, //uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */ - (uint32_t)p_method->get_argument_count(), //uint32_t argument_count; - (GDNativeBool)p_method->has_return(), //GDNativeBool has_return_value; + p_method->get_name(), // const char *name; + p_method, // void *method_userdata; + MethodBind::bind_call, // GDNativeExtensionClassMethodCall call_func; + MethodBind::bind_ptrcall, // GDNativeExtensionClassMethodPtrCall ptrcall_func; + p_method->get_hint_flags(), // uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */ + (uint32_t)p_method->get_argument_count(), // uint32_t argument_count; + (GDNativeBool)p_method->has_return(), // GDNativeBool has_return_value; MethodBind::bind_get_argument_type, //(GDNativeExtensionClassMethodGetArgumentType) get_argument_type_func; - MethodBind::bind_get_argument_info, //GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */ - MethodBind::bind_get_argument_metadata, //GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func; - p_method->get_hint_flags(), //uint32_t default_argument_count; - nullptr, //GDNativeVariantPtr *default_arguments; + MethodBind::bind_get_argument_info, // GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */ + MethodBind::bind_get_argument_metadata, // GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func; + (uint32_t)p_method->get_default_argument_count(), // uint32_t default_argument_count; + def_args.data(), // GDNativeVariantPtr *default_arguments; }; internal::gdn_interface->classdb_register_extension_class_method(internal::library, p_class_name, &method_info); } diff --git a/src/core/method_bind.cpp b/src/core/method_bind.cpp index 2090408f..563ea7f0 100644 --- a/src/core/method_bind.cpp +++ b/src/core/method_bind.cpp @@ -52,6 +52,14 @@ void MethodBind::set_return(bool p_return) { _has_return = p_return; } +void MethodBind::set_static(bool p_static) { + _static = p_static; +} + +void MethodBind::set_vararg(bool p_vararg) { + _vararg = p_vararg; +} + void MethodBind::set_argument_names(const std::vector &p_names) { argument_names = p_names; } diff --git a/src/core/object.cpp b/src/core/object.cpp index 08d00284..e1feabb8 100644 --- a/src/core/object.cpp +++ b/src/core/object.cpp @@ -33,22 +33,22 @@ namespace godot { MethodInfo::MethodInfo() : - flags(METHOD_FLAG_NORMAL) {} + flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) {} MethodInfo::MethodInfo(const char *p_name) : - name(p_name), flags(METHOD_FLAG_NORMAL) {} + name(p_name), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) {} MethodInfo::MethodInfo(Variant::Type ret) : - flags(METHOD_FLAG_NORMAL) { + flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) { return_val.type = ret; } MethodInfo::MethodInfo(Variant::Type ret, const char *p_name) : - name(p_name), flags(METHOD_FLAG_NORMAL) { + name(p_name), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) { return_val.type = ret; } MethodInfo::MethodInfo(const PropertyInfo &p_ret, const char *p_name) : - name(p_name), return_val(p_ret), flags(METHOD_FLAG_NORMAL) {} + name(p_name), return_val(p_ret), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) {} } // namespace godot diff --git a/test/demo/main.gd b/test/demo/main.gd index 1004af11..8ff16ac0 100644 --- a/test/demo/main.gd +++ b/test/demo/main.gd @@ -2,32 +2,49 @@ extends Node func _ready(): # Bind signals + prints("Signal bind") $Button.button_up.connect($Example.emit_custom_signal.bind("Button", 42)) + + prints("") + + # Call static methods. + prints("Static method calls") + prints(" static (109)", Example.test_static(9, 100)); + Example.test_static2(); # Call methods. + prints("Instance method calls") $Example.simple_func() ($Example as Example).simple_const_func() # Force use of ptrcall - prints("returned", $Example.return_something("some string")) - prints("returned const", $Example.return_something_const()) - prints("returned ref", $Example.return_extended_ref()) + prints(" returned", $Example.return_something("some string")) + prints(" returned const", $Example.return_something_const()) + prints(" returned ref", $Example.return_extended_ref()) + + prints("VarArg method calls") var ref = ExampleRef.new() - prints("sending ref: ", ref.get_instance_id(), "returned ref: ", $Example.extended_ref_checks(ref).get_instance_id()) - prints("vararg args", $Example.varargs_func("some", "arguments", "to", "test")) - prints("vararg_nv ret", $Example.varargs_func_nv("some", "arguments", "to", "test")) + prints(" sending ref: ", ref.get_instance_id(), "returned ref: ", $Example.extended_ref_checks(ref).get_instance_id()) + prints(" vararg args", $Example.varargs_func("some", "arguments", "to", "test")) + prints(" vararg_nv ret", $Example.varargs_func_nv("some", "arguments", "to", "test")) $Example.varargs_func_void("some", "arguments", "to", "test") - prints("test array", $Example.test_array()) - prints("test dictionary", $Example.test_dictionary()) + prints("Method calls with default values") + prints(" defval (300)", $Example.def_args()) + prints(" defval (250)", $Example.def_args(50)) + prints(" defval (150)", $Example.def_args(50, 100)) - # Use properties. - prints("custom position is", $Example.group_subgroup_custom_position) + prints("Array and Dictionary") + prints(" test array", $Example.test_array()) + prints(" test dictionary", $Example.test_dictionary()) + + prints("Properties") + prints(" custom position is", $Example.group_subgroup_custom_position) $Example.group_subgroup_custom_position = Vector2(50, 50) - prints("custom position now is", $Example.group_subgroup_custom_position) + prints(" custom position now is", $Example.group_subgroup_custom_position) - # Get constants - prints("FIRST", $Example.FIRST) - prints("ANSWER_TO_EVERYTHING", $Example.ANSWER_TO_EVERYTHING) - prints("CONSTANT_WITHOUT_ENUM", $Example.CONSTANT_WITHOUT_ENUM) + prints("Constnts") + prints(" FIRST", $Example.FIRST) + prints(" ANSWER_TO_EVERYTHING", $Example.ANSWER_TO_EVERYTHING) + prints(" CONSTANT_WITHOUT_ENUM", $Example.CONSTANT_WITHOUT_ENUM) func _on_Example_custom_signal(name, value): prints("Example emitted:", name, value) diff --git a/test/src/example.cpp b/test/src/example.cpp index 058b33bc..68eeb2ac 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -46,6 +46,18 @@ ExampleRef::~ExampleRef() { UtilityFunctions::print("ExampleRef destroyed."); } +int Example::test_static(int p_a, int p_b) { + return p_a + p_b; +} + +void Example::test_static2() { + UtilityFunctions::print(" void static"); +} + +int Example::def_args(int p_a, int p_b) { + return p_a + p_b; +} + void Example::_bind_methods() { // Methods. ClassDB::bind_method(D_METHOD("simple_func"), &Example::simple_func); @@ -58,6 +70,11 @@ void Example::_bind_methods() { ClassDB::bind_method(D_METHOD("test_array"), &Example::test_array); ClassDB::bind_method(D_METHOD("test_dictionary"), &Example::test_dictionary); + ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200)); + + 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); + { MethodInfo mi; mi.arguments.push_back(PropertyInfo(Variant::STRING, "some_argument")); @@ -108,20 +125,20 @@ Example::~Example() { // Methods. void Example::simple_func() { - UtilityFunctions::print("Simple func called."); + UtilityFunctions::print(" Simple func called."); } void Example::simple_const_func() const { - UtilityFunctions::print("Simple const func called."); + UtilityFunctions::print(" Simple const func called."); } String Example::return_something(const String &base) { - UtilityFunctions::print("Return something called."); + UtilityFunctions::print(" Return something called."); return base; } Viewport *Example::return_something_const() const { - UtilityFunctions::print("Return something const called."); + UtilityFunctions::print(" Return something const called."); if (is_inside_tree()) { Viewport *result = get_viewport(); return result; @@ -138,22 +155,22 @@ Ref Example::extended_ref_checks(Ref p_ref) const { ref.instantiate(); // TODO the returned value gets dereferenced too early and return a null object otherwise. ref->reference(); - UtilityFunctions::print("Example ref checks called with value: ", p_ref->get_instance_id(), ", returning value: ", ref->get_instance_id()); + UtilityFunctions::print(" Example ref checks called with value: ", p_ref->get_instance_id(), ", returning value: ", ref->get_instance_id()); return ref; } Variant Example::varargs_func(const Variant **args, GDNativeInt arg_count, GDNativeCallError &error) { - UtilityFunctions::print("Varargs (Variant return) called with ", String::num((double)arg_count), " arguments"); + UtilityFunctions::print(" Varargs (Variant return) called with ", String::num((double)arg_count), " arguments"); return arg_count; } int Example::varargs_func_nv(const Variant **args, GDNativeInt arg_count, GDNativeCallError &error) { - UtilityFunctions::print("Varargs (int return) called with ", String::num((double)arg_count), " arguments"); + UtilityFunctions::print(" Varargs (int return) called with ", String::num((double)arg_count), " arguments"); return 42; } void Example::varargs_func_void(const Variant **args, GDNativeInt arg_count, GDNativeCallError &error) { - UtilityFunctions::print("Varargs (no return) called with ", String::num((double)arg_count), " arguments"); + UtilityFunctions::print(" Varargs (no return) called with ", String::num((double)arg_count), " arguments"); } void Example::emit_custom_signal(const String &name, int value) { diff --git a/test/src/example.h b/test/src/example.h index fb331a5d..35bc7c88 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -90,6 +90,7 @@ public: int varargs_func_nv(const Variant **args, GDNativeInt arg_count, GDNativeCallError &error); void varargs_func_void(const Variant **args, GDNativeInt arg_count, GDNativeCallError &error); void emit_custom_signal(const String &name, int value); + int def_args(int p_a = 100, int p_b = 200); Array test_array() const; Dictionary test_dictionary() const; @@ -98,6 +99,10 @@ public: void set_custom_position(const Vector2 &pos); Vector2 get_custom_position() const; + // Static method. + static int test_static(int p_a, int p_b); + static void test_static2(); + // Virtual function override (no need to bind manually). virtual bool _has_point(const Vector2 &point) const override; };