diff options
71 files changed, 2083 insertions, 1234 deletions
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 719667e7ab..9fd5476f51 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -31,6 +31,7 @@ #include "input_map.h" #include "core/config/project_settings.h" +#include "core/input/input.h" #include "core/os/keyboard.h" InputMap *InputMap::singleton = nullptr; @@ -151,6 +152,9 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event); if (E) { input_map[p_action].inputs.erase(E); + if (Input::get_singleton()->is_action_pressed(p_action)) { + Input::get_singleton()->action_release(p_action); + } } } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 9991ee405e..a8ca6a817e 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -1057,7 +1057,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + "."); - ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj); + Ref<ResourceFormatLoader> crl = Object::cast_to<ResourceFormatLoader>(obj); crl->set_script(s); ResourceLoader::add_resource_format_loader(crl); diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 2eac2a6b4d..6ded27d82f 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -214,7 +214,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + "."); - ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj); + Ref<ResourceFormatSaver> crl = Object::cast_to<ResourceFormatSaver>(obj); crl->set_script(s); ResourceSaver::add_resource_format_saver(crl); diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 13c8904f7e..d1f15caa5e 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -410,7 +410,7 @@ Error Expression::_get_token(Token &r_token) { } else if (id == "self") { r_token.type = TK_SELF; } else { - if (Variant::has_builtin_func(id)) { + if (Variant::has_utility_function(id)) { r_token.type = TK_BUILTIN_FUNC; r_token.value = id; return OK; @@ -747,8 +747,8 @@ Expression::ENode *Expression::_parse_expression() { } } - if (!Variant::is_builtin_func_vararg(bifunc->func)) { - int expected_args = Variant::get_builtin_func_argument_count(bifunc->func); + if (!Variant::is_utility_function_vararg(bifunc->func)) { + int expected_args = Variant::get_utility_function_argument_count(bifunc->func); if (expected_args != bifunc->arguments.size()) { _set_error("Builtin func '" + String(bifunc->func) + "' expects " + itos(expected_args) + " arguments."); } @@ -1362,7 +1362,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: r_ret = Variant(); //may not return anything Callable::CallError ce; - Variant::call_builtin_func(bifunc->func, &r_ret, (const Variant **)argp.ptr(), argp.size(), ce); + Variant::call_utility_function(bifunc->func, &r_ret, (const Variant **)argp.ptr(), argp.size(), ce); if (ce.error != Callable::CallError::CALL_OK) { r_error_str = "Builtin Call Failed. " + Variant::get_call_error_text(bifunc->func, (const Variant **)argp.ptr(), argp.size(), ce); return true; @@ -1396,7 +1396,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: } Callable::CallError ce; - r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce); + base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); if (ce.error != Callable::CallError::CALL_OK) { r_error_str = vformat(RTR("On call to '%s':"), String(call->method)); diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 180aeaa0af..00e561f973 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -251,7 +251,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t real_t dot = v1.dot(v2); - dot = (dot < -1.0) ? -1.0 : ((dot > 1.0) ? 1.0 : dot); //clamp dot to [-1,1] + dot = CLAMP(dot, -1.0, 1.0); Vector2 v; diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index e72f76c5e1..2e38ce5b06 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -650,6 +650,39 @@ void call_with_variant_args_retc_static_helper(T *p_instance, R (*p_method)(T *, (void)p_args; } +template <class T, class R, class... P> +void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &default_values, Callable::CallError &r_error) { +#ifdef DEBUG_ENABLED + if ((size_t)p_argcount > sizeof...(P)) { + r_error.error = Callable::CallError::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 = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = sizeof...(P); + return; + } +#endif + + const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array + for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) { + if (i < p_argcount) { + args[i] = p_args[i]; + } else { + args[i] = &default_values[i - p_argcount + (dvs - missing)]; + } + } + + call_with_variant_args_retc_static_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); +} + #if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 055f61cf92..741d05c139 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3401,7 +3401,8 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) { Callable::CallError error; - Variant ret = call(p_method, argptr, argc, error); + Variant ret; + call(p_method, argptr, argc, ret, error); switch (error.error) { case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { @@ -3549,12 +3550,12 @@ void Variant::register_types() { _register_variant_methods(); _register_variant_setters_getters(); _register_variant_constructors(); - _register_variant_builtin_funcs(); + _register_variant_utility_functions(); } void Variant::unregister_types() { _unregister_variant_operators(); _unregister_variant_methods(); _unregister_variant_setters_getters(); _unregister_variant_constructors(); - _unregister_variant_builtin_funcs(); + _unregister_variant_utility_functions(); } diff --git a/core/variant/variant.h b/core/variant/variant.h index d3e2f84357..1a684eeea0 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -267,8 +267,8 @@ private: static void _unregister_variant_setters_getters(); static void _register_variant_constructors(); static void _unregister_variant_constructors(); - static void _register_variant_builtin_funcs(); - static void _unregister_variant_builtin_funcs(); + static void _register_variant_utility_functions(); + static void _unregister_variant_utility_functions(); public: _FORCE_INLINE_ Type get_type() const { @@ -482,54 +482,39 @@ public: static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst); static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst); - class InternalMethod { -#ifdef DEBUG_ENABLED - protected: - StringName method_name; - Variant::Type base_type; -#endif - public: - enum Flags { - FLAG_IS_CONST = 1, - FLAG_RETURNS_VARIANT = 2, - FLAG_NO_PTRCALL = 4, - FLAG_VARARGS = 8 - }; + /* Built-In Methods */ - virtual int get_argument_count() const = 0; - virtual Type get_argument_type(int p_arg) const = 0; - virtual Type get_return_type() const = 0; - virtual uint32_t get_flags() const = 0; + typedef void (*ValidatedBuiltInMethod)(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret); + typedef void (*PTRBuiltInMethod)(void *p_base, const void **p_args, void *r_ret, int p_argcount); -#ifdef DEBUG_ENABLED - virtual String get_argument_name(int p_arg) const = 0; - StringName get_name() const { - return method_name; - } - Variant::Type get_base_type() const { - return base_type; - } -#endif - virtual Vector<Variant> get_default_arguments() const = 0; - virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) = 0; - virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) = 0; -#ifdef PTRCALL_ENABLED - virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) = 0; -#endif - virtual ~InternalMethod() {} - }; + static bool has_builtin_method(Variant::Type p_type, const StringName &p_method); + + static ValidatedBuiltInMethod get_validated_builtin_method(Variant::Type p_type, const StringName &p_method); + static PTRBuiltInMethod get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method); - static InternalMethod *get_internal_method(Type p_type, const StringName &p_method_name); + static int get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method); + static Variant::Type get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument); + static String get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument); + static Vector<Variant> get_builtin_method_default_arguments(Variant::Type p_type, const StringName &p_method); + static bool has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method); + static Variant::Type get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method); + static bool is_builtin_method_const(Variant::Type p_type, const StringName &p_method); + static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method); + static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list); - void call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error); - Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); + void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error); Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant()); static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce); static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce); static String get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce); - // constructor + //dynamic (includes Object) + void get_method_list(List<MethodInfo> *p_list) const; + bool has_method(const StringName &p_method) const; + + /* Constructors */ + typedef void (*ValidatedConstructor)(Variant &r_base, const Variant **p_args); typedef void (*PTRConstructor)(void *base, const void **p_args); @@ -543,13 +528,7 @@ public: static void get_constructor_list(Type p_type, List<MethodInfo> *r_list); //convenience - void get_method_list(List<MethodInfo> *p_list) const; - bool has_method(const StringName &p_method) const; - static Vector<Variant::Type> get_method_argument_types(Variant::Type p_type, const StringName &p_method); - static Vector<Variant> get_method_default_arguments(Variant::Type p_type, const StringName &p_method); - static Variant::Type get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return = nullptr); - static Vector<StringName> get_method_argument_names(Variant::Type p_type, const StringName &p_method); - static bool is_method_const(Variant::Type p_type, const StringName &p_method); + /* Properties */ void set_named(const StringName &p_member, const Variant &p_value, bool &r_valid); Variant get_named(const StringName &p_member, bool &r_valid) const; @@ -570,6 +549,8 @@ public: static PTRSetter get_member_ptr_setter(Variant::Type p_type, const StringName &p_member); static PTRGetter get_member_ptr_getter(Variant::Type p_type, const StringName &p_member); + /* Indexing */ + static bool has_indexing(Variant::Type p_type); static Variant::Type get_indexed_element_type(Variant::Type p_type); @@ -590,6 +571,8 @@ public: uint64_t get_indexed_size() const; + /* Keying */ + static bool is_keyed(Variant::Type p_type); typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool &valid); @@ -612,6 +595,8 @@ public: Variant get_keyed(const Variant &p_key, bool &r_valid) const; bool has_key(const Variant &p_key, bool &r_valid) const; + /* Generic */ + void set(const Variant &p_index, const Variant &p_value, bool *r_valid = nullptr); Variant get(const Variant &p_index, bool *r_valid = nullptr) const; bool in(const Variant &p_index, bool *r_valid = nullptr) const; @@ -622,31 +607,31 @@ public: void get_property_list(List<PropertyInfo> *p_list) const; - static void call_builtin_func(const StringName &p_name, Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - static bool has_builtin_func(const StringName &p_name); + static void call_utility_function(const StringName &p_name, Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error); + static bool has_utility_function(const StringName &p_name); - typedef void (*BuiltinFunctionValidatedCall)(Variant *r_ret, const Variant **p_args, int p_argcount); - typedef void (*BuiltinFunctionPTRCall)(void *r_ret, const void **p_args, int p_argcount); + typedef void (*ValidatedUtilityFunction)(Variant *r_ret, const Variant **p_args, int p_argcount); + typedef void (*PTRUtilityFunction)(void *r_ret, const void **p_args, int p_argcount); - static BuiltinFunctionValidatedCall get_builtin_validated_caller(const StringName &p_name); - static BuiltinFunctionPTRCall get_builtin_ptr_caller(const StringName &p_name); + static ValidatedUtilityFunction get_validated_utility_function(const StringName &p_name); + static PTRUtilityFunction get_ptr_utility_function(const StringName &p_name); - enum BuiltInFunctionType { - BUILTIN_FUNC_TYPE_MATH, - BUILTIN_FUNC_TYPE_RANDOM, - BUILTIN_FUNC_TYPE_UTILITY, + enum UtilityFunctionType { + UTILITY_FUNC_TYPE_MATH, + UTILITY_FUNC_TYPE_RANDOM, + UTILITY_FUNC_TYPE_GENERAL, }; - static BuiltInFunctionType get_builtin_func_type(const StringName &p_name); + static UtilityFunctionType get_utility_function_type(const StringName &p_name); - static int get_builtin_func_argument_count(const StringName &p_name); - static Variant::Type get_builtin_func_argument_type(const StringName &p_name, int p_arg); - static String get_builtin_func_argument_name(const StringName &p_name, int p_arg); - static bool has_builtin_func_return_value(const StringName &p_name); - static Variant::Type get_builtin_func_return_type(const StringName &p_name); - static bool is_builtin_func_vararg(const StringName &p_name); + static int get_utility_function_argument_count(const StringName &p_name); + static Variant::Type get_utility_function_argument_type(const StringName &p_name, int p_arg); + static String get_utility_function_argument_name(const StringName &p_name, int p_arg); + static bool has_utility_function_return_value(const StringName &p_name); + static Variant::Type get_utility_function_return_type(const StringName &p_name); + static bool is_utility_function_vararg(const StringName &p_name); - static void get_builtin_function_list(List<StringName> *r_functions); + static void get_utility_function_list(List<StringName> *r_functions); //argsVariant call() diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 39290f2b04..4cb8457ccd 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -36,6 +36,7 @@ #include "core/io/compression.h" #include "core/object/class_db.h" #include "core/os/os.h" +#include "core/templates/local_vector.h" #include "core/templates/oa_hash_map.h" typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args); @@ -62,499 +63,330 @@ struct TypeAdjust<Object *> { } }; -struct _VariantCall { - template <class T, class... P> - class InternalMethod : public Variant::InternalMethod { - public: - void (T::*method)(P...); - Vector<Variant> default_values; -#ifdef DEBUG_ENABLED - Vector<String> argument_names; -#endif - - virtual int get_argument_count() const { - return sizeof...(P); - } - virtual Variant::Type get_argument_type(int p_arg) const { - return call_get_argument_type<P...>(p_arg); - } -#ifdef DEBUG_ENABLED - virtual String get_argument_name(int p_arg) const { - ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String()); - return argument_names[p_arg]; - } -#endif - virtual Vector<Variant> get_default_arguments() const { - return default_values; - } - - virtual Variant::Type get_return_type() const { - return Variant::NIL; - } - virtual uint32_t get_flags() const { - return 0; - } - - virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { - call_with_variant_args_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, default_values); - } - - virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) { - call_with_validated_variant_args(base, method, p_args); - } - -#ifdef PTRCALL_ENABLED - virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) { - call_with_ptr_args<T, P...>(reinterpret_cast<T *>(p_base), method, p_args); - } -#endif - InternalMethod(void (T::*p_method)(P...), const Vector<Variant> &p_default_args -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type -#endif - ) { - method = p_method; - default_values = p_default_args; -#ifdef DEBUG_ENABLED - argument_names = p_arg_names; - method_name = p_method_name; - base_type = p_base_type; -#endif - } - }; - - template <class T, class R, class... P> - class InternalMethodR : public Variant::InternalMethod { - public: - R(T::*method) - (P...); - Vector<Variant> default_values; -#ifdef DEBUG_ENABLED - Vector<String> argument_names; -#endif - - virtual int get_argument_count() const { - return sizeof...(P); - } - virtual Variant::Type get_argument_type(int p_arg) const { - return call_get_argument_type<P...>(p_arg); - return Variant::NIL; - } -#ifdef DEBUG_ENABLED - virtual String get_argument_name(int p_arg) const { - ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String()); - return argument_names[p_arg]; - } -#endif - virtual Vector<Variant> get_default_arguments() const { - return default_values; - } +template <class R, class T, class... P> +static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + call_with_variant_args_ret_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals); +} - virtual Variant::Type get_return_type() const { - return GetTypeInfo<R>::VARIANT_TYPE; - } - virtual uint32_t get_flags() const { - uint32_t f = 0; - if (get_return_type() == Variant::NIL) { - f |= FLAG_RETURNS_VARIANT; - } - return f; - } +template <class R, class T, class... P> +static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + call_with_variant_args_retc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals); +} - virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { - call_with_variant_args_ret_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, default_values); - } +template <class T, class... P> +static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + call_with_variant_args_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals); +} - virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) { - TypeAdjust<R>::adjust(r_ret); - call_with_validated_variant_args_ret(base, method, p_args, r_ret); - } -#ifdef PTRCALL_ENABLED - virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) { - call_with_ptr_args_ret<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret); - } -#endif - InternalMethodR(R (T::*p_method)(P...), const Vector<Variant> &p_default_args -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type -#endif - ) { - method = p_method; - default_values = p_default_args; -#ifdef DEBUG_ENABLED - argument_names = p_arg_names; - method_name = p_method_name; - base_type = p_base_type; -#endif - } - }; +template <class T, class... P> +static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + call_with_variant_argsc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals); +} - template <class T, class R, class... P> - class InternalMethodRC : public Variant::InternalMethod { - public: - R(T::*method) - (P...) const; - Vector<Variant> default_values; -#ifdef DEBUG_ENABLED - Vector<String> argument_names; -#endif +template <class R, class T, class... P> +static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) { + call_with_validated_variant_args_ret(base, method, p_args, r_ret); +} - virtual int get_argument_count() const { - return sizeof...(P); - } - virtual Variant::Type get_argument_type(int p_arg) const { - return call_get_argument_type<P...>(p_arg); - } -#ifdef DEBUG_ENABLED - virtual String get_argument_name(int p_arg) const { - ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String()); - return argument_names[p_arg]; - } -#endif - virtual Vector<Variant> get_default_arguments() const { - return default_values; - } +template <class R, class T, class... P> +static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) { + call_with_validated_variant_args_retc(base, method, p_args, r_ret); +} +template <class T, class... P> +static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) { + call_with_validated_variant_args(base, method, p_args); +} - virtual Variant::Type get_return_type() const { - return GetTypeInfo<R>::VARIANT_TYPE; - } - virtual uint32_t get_flags() const { - uint32_t f = FLAG_IS_CONST; - if (get_return_type() == Variant::NIL) { - f |= FLAG_RETURNS_VARIANT; - } - return f; - } +template <class T, class... P> +static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) { + call_with_validated_variant_argsc(base, method, p_args); +} - virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { - call_with_variant_args_retc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, default_values); - } +template <class R, class T, class... P> +static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) { + call_with_ptr_args_ret(reinterpret_cast<T *>(p_base), method, p_args, r_ret); +} - virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) { - TypeAdjust<R>::adjust(r_ret); - call_with_validated_variant_args_retc(base, method, p_args, r_ret); - } -#ifdef PTRCALL_ENABLED - virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) { - call_with_ptr_args_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret); - } -#endif - InternalMethodRC(R (T::*p_method)(P...) const, const Vector<Variant> &p_default_args -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type -#endif - ) { - method = p_method; - default_values = p_default_args; -#ifdef DEBUG_ENABLED - argument_names = p_arg_names; - method_name = p_method_name; - base_type = p_base_type; -#endif - } - }; +template <class R, class T, class... P> +static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) { + call_with_ptr_args_retc(reinterpret_cast<T *>(p_base), method, p_args, r_ret); +} - template <class T, class R, class... P> - class InternalMethodRS : public Variant::InternalMethod { - public: - R(*method) - (T *, P...); - Vector<Variant> default_values; -#ifdef DEBUG_ENABLED - Vector<String> argument_names; -#endif +template <class T, class... P> +static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) { + call_with_ptr_args(reinterpret_cast<T *>(p_base), method, p_args); +} - virtual int get_argument_count() const { - return sizeof...(P); - } - virtual Variant::Type get_argument_type(int p_arg) const { - return call_get_argument_type<P...>(p_arg); - } -#ifdef DEBUG_ENABLED - virtual String get_argument_name(int p_arg) const { - ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String()); - return argument_names[p_arg]; - } -#endif - virtual Vector<Variant> get_default_arguments() const { - return default_values; - } +template <class T, class... P> +static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) { + call_with_ptr_argsc(reinterpret_cast<T *>(p_base), method, p_args); +} - virtual Variant::Type get_return_type() const { - return GetTypeInfo<R>::VARIANT_TYPE; - } - virtual uint32_t get_flags() const { - uint32_t f = 0; - if (get_return_type() == Variant::NIL) { - f |= FLAG_RETURNS_VARIANT; - } - return f; - } +template <class R, class T, class... P> +static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...)) { + return sizeof...(P); +} +template <class R, class T, class... P> +static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...) const) { + return sizeof...(P); +} - virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { - const Variant **args = p_args; -#ifdef DEBUG_ENABLED - if ((size_t)p_argcount > sizeof...(P)) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = sizeof...(P); - return; - } -#endif - if ((size_t)p_argcount < sizeof...(P)) { - size_t missing = sizeof...(P) - (size_t)p_argcount; - if (missing <= (size_t)default_values.size()) { - args = (const Variant **)alloca(sizeof...(P) * sizeof(const Variant *)); - // GCC fails to see that `sizeof...(P)` cannot be 0 here given the previous - // conditions, so it raises a warning on the potential use of `i < 0` as the - // execution condition. -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" -#endif - for (size_t i = 0; i < sizeof...(P); i++) { - if (i < (size_t)p_argcount) { - args[i] = p_args[i]; - } else { - args[i] = &default_values[i - p_argcount + (default_values.size() - missing)]; - } - } -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - } else { -#ifdef DEBUG_ENABLED - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = sizeof...(P); -#endif - return; - } - } - call_with_variant_args_retc_static_helper(VariantGetInternalPtr<T>::get_ptr(base), method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); - } +template <class T, class... P> +static _FORCE_INLINE_ int vc_get_argument_count(void (T::*method)(P...)) { + return sizeof...(P); +} - virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) { - TypeAdjust<R>::adjust(r_ret); - call_with_validated_variant_args_static_retc(base, method, p_args, r_ret); - } -#ifdef PTRCALL_ENABLED - virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) { - call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret); - } -#endif - InternalMethodRS(R (*p_method)(T *, P...), const Vector<Variant> &p_default_args -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type -#endif - ) { - method = p_method; - default_values = p_default_args; -#ifdef DEBUG_ENABLED - argument_names = p_arg_names; - method_name = p_method_name; - base_type = p_base_type; -#endif - } - }; +template <class T, class... P> +static _FORCE_INLINE_ int vc_get_argument_count(void (T::*method)(P...) const) { + return sizeof...(P); +} - class InternalMethodVC : public Variant::InternalMethod { - public: - typedef void (*MethodVC)(Variant *, const Variant **, int, Variant &r_ret, Callable::CallError &); - MethodVC methodvc = nullptr; - uint32_t base_flags = 0; - Vector<String> argument_names; - Vector<Variant::Type> argument_types; - Variant::Type return_type = Variant::NIL; - - virtual int get_argument_count() const { - return argument_names.size(); - } - virtual Variant::Type get_argument_type(int p_arg) const { - ERR_FAIL_INDEX_V(p_arg, argument_types.size(), Variant::NIL); - return argument_types[p_arg]; - } -#ifdef DEBUG_ENABLED - virtual String get_argument_name(int p_arg) const { - ERR_FAIL_INDEX_V(p_arg, argument_names.size(), String()); - return argument_names[p_arg]; - } -#endif - virtual Vector<Variant> get_default_arguments() const { - return Vector<Variant>(); - } +template <class R, class T, class... P> +static _FORCE_INLINE_ int vc_get_argument_count(R (*method)(T *, P...)) { + return sizeof...(P); +} - virtual Variant::Type get_return_type() const { - return return_type; - } - virtual uint32_t get_flags() const { - return base_flags | FLAG_NO_PTRCALL; - } +template <class R, class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...), int p_arg) { + return call_get_argument_type<P...>(p_arg); +} +template <class R, class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...) const, int p_arg) { + return call_get_argument_type<P...>(p_arg); +} - virtual void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { - methodvc(base, p_args, p_argcount, r_ret, r_error); - } +template <class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_argument_type(void (T::*method)(P...), int p_arg) { + return call_get_argument_type<P...>(p_arg); +} - virtual void validated_call(Variant *base, const Variant **p_args, Variant *r_ret) { - ERR_FAIL_MSG("No support for validated call"); - } -#ifdef PTRCALL_ENABLED - virtual void ptrcall(void *p_base, const void **p_args, void *r_ret) { - ERR_FAIL_MSG("No support for ptrcall call"); - } -#endif - InternalMethodVC(MethodVC p_method, uint32_t p_flags, const Vector<Variant::Type> &p_argument_types, const Variant::Type &p_return_type -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_arg_names, const StringName &p_method_name, Variant::Type p_base_type -#endif - ) { - methodvc = p_method; - argument_types = p_argument_types; - return_type = p_return_type; - base_flags = p_flags; -#ifdef DEBUG_ENABLED - argument_names = p_arg_names; - method_name = p_method_name; - base_type = p_base_type; -#endif - } - }; +template <class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_argument_type(void (T::*method)(P...) const, int p_arg) { + return call_get_argument_type<P...>(p_arg); +} - typedef OAHashMap<StringName, Variant::InternalMethod *> MethodMap; - static MethodMap *type_internal_methods; - static List<StringName> *type_internal_method_names; +template <class R, class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (*method)(T *, P...), int p_arg) { + return call_get_argument_type<P...>(p_arg); +} - template <class T, class... P> - static void _bind_method(const StringName &p_name, void (T::*p_method)(P...), const Vector<Variant> &p_default_args = Vector<Variant>() -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_argument_names = Vector<String>() -#endif - ) { +template <class R, class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...)) { + return GetTypeInfo<R>::VARIANT_TYPE; +} -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name)); - ERR_FAIL_COND(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name)); -#endif -#ifdef DEBUG_ENABLED - Variant::InternalMethod *m = memnew((InternalMethod<T, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE)); -#else - Variant::InternalMethod *m = memnew((InternalMethod<T, P...>)(p_method, p_default_args)); -#endif +template <class R, class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...) const) { + return GetTypeInfo<R>::VARIANT_TYPE; +} - type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m); - type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name); - } +template <class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (T::*method)(P...)) { + return Variant::NIL; +} - template <class T, class R, class... P> - static void _bind_method(const StringName &p_name, R (T::*p_method)(P...) const, const Vector<Variant> &p_default_args = Vector<Variant>() -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_argument_names = Vector<String>() -#endif - ) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name)); - ERR_FAIL_COND_MSG(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name), " Method already registered: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name)); +template <class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (T::*method)(P...) const) { + return Variant::NIL; +} -#endif -#ifdef DEBUG_ENABLED - Variant::InternalMethod *m = memnew((InternalMethodRC<T, R, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE)); -#else - Variant::InternalMethod *m = memnew((InternalMethodRC<T, R, P...>)(p_method, p_default_args)); -#endif +template <class R, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (*method)(P...)) { + return GetTypeInfo<R>::VARIANT_TYPE; +} - type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m); - type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name); - } +template <class R, class T, class... P> +static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...)) { + return true; +} +template <class R, class T, class... P> +static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...) const) { + return true; +} - template <class T, class R, class... P> - static void _bind_method(const StringName &p_name, R (T::*p_method)(P...), const Vector<Variant> &p_default_args = Vector<Variant>() -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_argument_names = Vector<String>() -#endif - ) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name)); - ERR_FAIL_COND_MSG(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name), " Method already registered: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name)); -#endif +template <class T, class... P> +static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...)) { + return false; +} -#ifdef DEBUG_ENABLED - Variant::InternalMethod *m = memnew((InternalMethodR<T, R, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE)); -#else - Variant::InternalMethod *m = memnew((InternalMethodR<T, R, P...>)(p_method, p_default_args)); -#endif - type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m); - type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name); - } +template <class T, class... P> +static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...) const) { + return false; +} -#ifdef DEBUG_ENABLED -#define bind_method(m_type, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_method, &m_type ::m_method, m_default_args, m_arg_names) -#else -#define bind_method(m_type, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_method, &m_type ::m_method, m_default_args) -#endif +template <class R, class T, class... P> +static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...)) { + return false; +} +template <class R, class T, class... P> +static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...) const) { + return true; +} -#ifdef DEBUG_ENABLED -#define bind_methodv(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_name, m_method, m_default_args, m_arg_names) -#else -#define bind_methodv(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_method(#m_name, m_method, m_default_args) -#endif +template <class T, class... P> +static _FORCE_INLINE_ bool vc_is_const(void (T::*method)(P...)) { + return false; +} - template <class T, class R, class... P> - static void _bind_function(const StringName &p_name, R (*p_method)(T *, P...), const Vector<Variant> &p_default_args = Vector<Variant>() -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_argument_names = Vector<String>() -#endif - ) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_argument_names.size() != sizeof...(P), "Wrong argument name count supplied for method: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name)); - ERR_FAIL_COND_MSG(type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].has(p_name), " Method already registered: " + Variant::get_type_name(GetTypeInfo<T>::VARIANT_TYPE) + "::" + String(p_name)); -#endif +template <class T, class... P> +static _FORCE_INLINE_ bool vc_is_const(void (T::*method)(P...) const) { + return true; +} -#ifdef DEBUG_ENABLED - Variant::InternalMethod *m = memnew((InternalMethodRS<T, R, P...>)(p_method, p_default_args, p_argument_names, p_name, GetTypeInfo<T>::VARIANT_TYPE)); -#else - Variant::InternalMethod *m = memnew((InternalMethodRS<T, R, P...>)(p_method, p_default_args)); -#endif +template <class R, class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_base_type(R (T::*method)(P...)) { + return GetTypeInfo<T>::VARIANT_TYPE; +} +template <class R, class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_base_type(R (T::*method)(P...) const) { + return GetTypeInfo<T>::VARIANT_TYPE; +} - type_internal_methods[GetTypeInfo<T>::VARIANT_TYPE].insert(p_name, m); - type_internal_method_names[GetTypeInfo<T>::VARIANT_TYPE].push_back(p_name); - } +template <class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...)) { + return GetTypeInfo<T>::VARIANT_TYPE; +} -#ifdef DEBUG_ENABLED -#define bind_function(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_function(m_name, m_method, m_default_args, m_arg_names) -#else -#define bind_function(m_name, m_method, m_arg_names, m_default_args) _VariantCall::_bind_function(m_name, m_method, m_default_args) -#endif +template <class T, class... P> +static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) const) { + return GetTypeInfo<T>::VARIANT_TYPE; +} - static void _bind_custom(Variant::Type p_type, const StringName &p_name, InternalMethodVC::MethodVC p_method, uint32_t p_flags, const Vector<Variant::Type> &p_argument_types, const Variant::Type &p_return_type -#ifdef DEBUG_ENABLED - , - const Vector<String> &p_argument_names = Vector<String>() -#endif - ) { +#define METHOD_CLASS(m_class, m_method_name, m_method_ptr) \ + struct Method_##m_class##_##m_method_name { \ + static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \ + vc_method_call(m_method_ptr, base, p_args, p_argcount, r_ret, p_defvals, r_error); \ + } \ + static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \ + TypeAdjust<m_class>::adjust(r_ret); \ + vc_validated_call(m_method_ptr, base, p_args, r_ret); \ + } \ + static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \ + vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \ + } \ + static int get_argument_count() { \ + return vc_get_argument_count(m_method_ptr); \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return vc_get_argument_type(m_method_ptr, p_arg); \ + } \ + static Variant::Type get_return_type() { \ + return vc_get_return_type(m_method_ptr); \ + } \ + static bool has_return_type() { \ + return vc_has_return_type(m_method_ptr); \ + } \ + static bool is_const() { \ + return vc_is_const(m_method_ptr); \ + } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::Type get_base_type() { \ + return vc_get_base_type(m_method_ptr); \ + } \ + static StringName get_name() { \ + return #m_method_name; \ + } \ + }; -#ifdef DEBUG_ENABLED - Variant::InternalMethod *m = memnew(InternalMethodVC(p_method, p_flags, p_argument_types, p_return_type, p_argument_names, p_name, p_type)); -#else - Variant::InternalMethod *m = memnew(InternalMethodVC(p_method, p_flags, p_argument_types, p_return_type)); -#endif +template <class R, class T, class... P> +static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) { + call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret); +} - type_internal_methods[p_type].insert(p_name, m); - type_internal_method_names[p_type].push_back(p_name); - } +#define FUNCTION_CLASS(m_class, m_method_name, m_method_ptr) \ + struct Method_##m_class##_##m_method_name { \ + static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \ + call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<m_class>::get_ptr(base), m_method_ptr, p_args, p_argcount, r_ret, p_defvals, r_error); \ + } \ + static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \ + TypeAdjust<m_class>::adjust(r_ret); \ + call_with_validated_variant_args_static_retc(base, m_method_ptr, p_args, r_ret); \ + } \ + static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \ + vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \ + } \ + static int get_argument_count() { \ + return vc_get_argument_count(m_method_ptr); \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return vc_get_argument_type(m_method_ptr, p_arg); \ + } \ + static Variant::Type get_return_type() { \ + return vc_get_return_type(m_method_ptr); \ + } \ + static bool has_return_type() { \ + return true; \ + } \ + static bool is_const() { \ + return true; \ + } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::Type get_base_type() { \ + return GetTypeInfo<m_class>::VARIANT_TYPE; \ + } \ + static StringName get_name() { \ + return #m_method_name; \ + } \ + }; -#ifdef DEBUG_ENABLED -#define bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type, m_arg_names) _VariantCall::_bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type, m_arg_names) -#else -#define bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type, m_arg_names) _VariantCall::_bind_custom(m_type, m_name, m_method, m_flags, m_arg_types, m_ret_type) -#endif +#define VARARG_CLASS(m_class, m_method_name, m_method_ptr, m_has_return, m_return_type) \ + struct Method_##m_class##_##m_method_name { \ + static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \ + m_method_ptr(base, p_args, p_argcount, r_ret, r_error); \ + } \ + static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \ + Callable::CallError ce; \ + m_method_ptr(base, p_args, p_argcount, *r_ret, ce); \ + } \ + static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \ + LocalVector<Variant> vars; \ + vars.resize(p_argcount); \ + LocalVector<const Variant *> vars_ptrs; \ + vars_ptrs.resize(p_argcount); \ + for (int i = 0; i < p_argcount; i++) { \ + vars[i] = PtrToArg<Variant>::convert(p_args[i]); \ + vars_ptrs[i] = &vars[i]; \ + } \ + Variant base = PtrToArg<m_class>::convert(p_base); \ + Variant ret; \ + Callable::CallError ce; \ + m_method_ptr(&base, (const Variant **)&vars_ptrs[0], p_argcount, ret, ce); \ + if (m_has_return) { \ + m_return_type r = ret; \ + PtrToArg<m_return_type>::encode(ret, r_ret); \ + } \ + } \ + static int get_argument_count() { \ + return 0; \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return Variant::NIL; \ + } \ + static Variant::Type get_return_type() { \ + return GetTypeInfo<m_return_type>::VARIANT_TYPE; \ + } \ + static bool has_return_type() { \ + return m_has_return; \ + } \ + static bool is_const() { \ + return true; \ + } \ + static bool is_vararg() { \ + return true; \ + } \ + static Variant::Type get_base_type() { \ + return GetTypeInfo<m_class>::VARIANT_TYPE; \ + } \ + static StringName get_name() { \ + return #m_method_name; \ + } \ + }; +struct _VariantCall { static String func_PackedByteArray_get_string_from_ascii(PackedByteArray *p_instance) { String s; if (p_instance->size() > 0) { @@ -703,18 +535,61 @@ struct _VariantCall { }; _VariantCall::ConstantData *_VariantCall::constant_data = nullptr; -_VariantCall::MethodMap *_VariantCall::type_internal_methods = nullptr; -List<StringName> *_VariantCall::type_internal_method_names = nullptr; -Variant Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - Variant ret; - call_ptr(p_method, p_args, p_argcount, &ret, r_error); - return ret; -} +struct VariantBuiltInMethodInfo { + void (*call)(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error); + Variant::ValidatedBuiltInMethod validated_call; + Variant::PTRBuiltInMethod ptrcall; -void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error) { - Variant ret; + Vector<Variant> default_arguments; + Vector<String> argument_names; + bool is_const; + bool has_return_type; + bool is_vararg; + Variant::Type return_type; + int argument_count; + Variant::Type (*get_argument_type)(int p_arg); +}; + +typedef OAHashMap<StringName, VariantBuiltInMethodInfo> BuiltinMethodMap; +static BuiltinMethodMap *builtin_method_info; +static List<StringName> *builtin_method_names; + +template <class T> +static void register_builtin_method(const Vector<String> &p_argnames, const Vector<Variant> &p_def_args) { + StringName name = T::get_name(); + + ERR_FAIL_COND(builtin_method_info[T::get_base_type()].has(name)); + + VariantBuiltInMethodInfo imi; + + imi.call = T::call; + imi.validated_call = T::validated_call; + if (T::is_vararg()) { + imi.ptrcall = nullptr; + } else { + imi.ptrcall = T::ptrcall; + } + + imi.default_arguments = p_def_args; + imi.argument_names = p_argnames; + + imi.is_const = T::is_const(); + imi.is_vararg = T::is_vararg(); + imi.has_return_type = T::has_return_type(); + imi.return_type = T::get_return_type(); + imi.argument_count = T::get_argument_count(); + imi.get_argument_type = T::get_argument_type; +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND(!imi.is_vararg && imi.argument_count != imi.argument_names.size()); +#endif + + builtin_method_info[T::get_base_type()].insert(name, imi); + builtin_method_names[T::get_base_type()].push_back(name); +} + +void Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) { if (type == Variant::OBJECT) { //call object Object *obj = _get_obj().obj; @@ -729,31 +604,24 @@ void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p } #endif - ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error); + r_ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error); //else if (type==Variant::METHOD) { } else { r_error.error = Callable::CallError::CALL_OK; - Variant::InternalMethod **m = _VariantCall::type_internal_methods[type].lookup_ptr(p_method); + const VariantBuiltInMethodInfo *imf = builtin_method_info[type].lookup_ptr(p_method); - if (m) { - (*m)->call((Variant *)this, p_args, p_argcount, ret, r_error); - } else { - //ok fail because not found + if (!imf) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return; } - } - if (r_error.error == Callable::CallError::CALL_OK && r_ret) { - *r_ret = ret; + imf->call(this, p_args, p_argcount, r_ret, imf->default_arguments, r_error); } } -#define VCALL(m_type, m_method) _VariantCall::_call_##m_type##_##m_method - bool Variant::has_method(const StringName &p_method) const { if (type == OBJECT) { Object *obj = get_validated_object(); @@ -764,97 +632,143 @@ bool Variant::has_method(const StringName &p_method) const { return obj->has_method(p_method); } - return _VariantCall::type_internal_methods[type].has(p_method); + return builtin_method_info[type].has(p_method); } -Vector<Variant::Type> Variant::get_method_argument_types(Variant::Type p_type, const StringName &p_method) { - Vector<Variant::Type> types; +bool Variant::has_builtin_method(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false); + return builtin_method_info[p_type].has(p_method); +} - Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method); - if (*m) { - types.resize((*m)->get_argument_count()); - for (int i = 0; i < (*m)->get_argument_count(); i++) { - types.write[i] = (*m)->get_argument_type(i); - } - } +Variant::ValidatedBuiltInMethod Variant::get_validated_builtin_method(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, nullptr); + return method->validated_call; +} - return types; +Variant::PTRBuiltInMethod Variant::get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, nullptr); + return method->ptrcall; } -bool Variant::is_method_const(Variant::Type p_type, const StringName &p_method) { - Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method); - if (*m) { - return (*m)->get_flags() & Variant::InternalMethod::FLAG_IS_CONST; - } - return false; +int Variant::get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, 0); + return method->argument_count; } -Vector<StringName> Variant::get_method_argument_names(Variant::Type p_type, const StringName &p_method) { - Vector<StringName> argnames; +Variant::Type Variant::get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, Variant::NIL); + ERR_FAIL_INDEX_V(p_argument, method->argument_count, Variant::NIL); + return method->get_argument_type(p_argument); +} -#ifdef DEBUG_ENABLED - Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method); - if (*m) { - argnames.resize((*m)->get_argument_count()); - for (int i = 0; i < (*m)->get_argument_count(); i++) { - argnames.write[i] = (*m)->get_argument_name(i); - } - } +String Variant::get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, String()); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, String()); +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_INDEX_V(p_argument, method->argument_count, String()); + return method->argument_names[p_argument]; +#else + return "arg" + itos(p_argument + 1); #endif - return argnames; } -Variant::Type Variant::get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return) { - Variant::Type rt = Variant::NIL; - Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method); - if (*m) { - rt = (*m)->get_return_type(); - if (r_has_return) { - *r_has_return = ((*m)->get_flags() & Variant::InternalMethod::FLAG_RETURNS_VARIANT) || rt != Variant::NIL; - } - } - return rt; +Vector<Variant> Variant::get_builtin_method_default_arguments(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Vector<Variant>()); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, Vector<Variant>()); + return method->default_arguments; } -Vector<Variant> Variant::get_method_default_arguments(Variant::Type p_type, const StringName &p_method) { - Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method); - if (*m) { - return (*m)->get_default_arguments(); +bool Variant::has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, false); + return method->has_return_type; +} + +void Variant::get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list) { + ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); + for (List<StringName>::Element *E = builtin_method_names[p_type].front(); E; E = E->next()) { + p_list->push_back(E->get()); } - return Vector<Variant>(); +} + +Variant::Type Variant::get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, Variant::NIL); + return method->return_type; +} + +bool Variant::is_builtin_method_const(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, false); + return method->is_const; +} + +bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, false); + return method->is_vararg; } void Variant::get_method_list(List<MethodInfo> *p_list) const { - for (List<StringName>::Element *E = _VariantCall::type_internal_method_names[type].front(); E; E = E->next()) { - Variant::InternalMethod **m = _VariantCall::type_internal_methods[type].lookup_ptr(E->get()); - ERR_CONTINUE(!*m); - - MethodInfo mi; - mi.name = E->get(); - mi.return_val.type = (*m)->get_return_type(); - if ((*m)->get_flags() & Variant::InternalMethod::FLAG_RETURNS_VARIANT) { - mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - } - if ((*m)->get_flags() & Variant::InternalMethod::FLAG_IS_CONST) { - mi.flags |= METHOD_FLAG_CONST; - } - if ((*m)->get_flags() & Variant::InternalMethod::FLAG_VARARGS) { - mi.flags |= METHOD_FLAG_VARARG; + if (type == OBJECT) { + Object *obj = get_validated_object(); + if (obj) { + obj->get_method_list(p_list); } + } else { + for (List<StringName>::Element *E = builtin_method_names[type].front(); E; E = E->next()) { + const VariantBuiltInMethodInfo *method = builtin_method_info[type].lookup_ptr(E->get()); + ERR_CONTINUE(!method); + + MethodInfo mi; + mi.name = E->get(); + + //return type + if (method->has_return_type) { + mi.return_val.type = method->return_type; + if (mi.return_val.type == Variant::NIL) { + mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + } - for (int i = 0; i < (*m)->get_argument_count(); i++) { - PropertyInfo arg; -#ifdef DEBUG_ENABLED - arg.name = (*m)->get_argument_name(i); + if (method->is_const) { + mi.flags |= METHOD_FLAG_CONST; + } + if (method->is_vararg) { + mi.flags |= METHOD_FLAG_VARARG; + } + + for (int i = 0; i < method->argument_count; i++) { + PropertyInfo pi; +#ifdef DEBUG_METHODS_ENABLED + pi.name = method->argument_names[i]; #else - arg.name = "arg" + itos(i + 1); + pi.name = "arg" + itos(i + 1); #endif - arg.type = (*m)->get_argument_type(i); - mi.arguments.push_back(arg); - } + pi.type = method->get_argument_type(i); + if (pi.type == Variant::NIL) { + pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + mi.arguments.push_back(pi); + } - mi.default_arguments = (*m)->get_default_arguments(); - p_list->push_back(mi); + mi.default_arguments = method->default_arguments; + p_list->push_back(mi); + } } } @@ -915,20 +829,44 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va return E->get(); } -Variant::InternalMethod *Variant::get_internal_method(Type p_type, const StringName &p_method_name) { - ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr); +#ifdef DEBUG_METHODS_ENABLED +#define bind_method(m_type, m_method, m_arg_names, m_default_args) \ + METHOD_CLASS(m_type, m_method, &m_type::m_method); \ + register_builtin_method<Method_##m_type##_##m_method>(m_arg_names, m_default_args); +#else +#define bind_method(m_type, m_method, m_arg_names, m_default_args) \ + METHOD_CLASS(m_type, m_method, &m_type ::m_method); \ + register_builtin_method<Method_##m_type##_##m_method>(sarray(), m_default_args); +#endif - Variant::InternalMethod **m = _VariantCall::type_internal_methods[p_type].lookup_ptr(p_method_name); - if (*m) { - return *m; - } - return nullptr; -} +#ifdef DEBUG_METHODS_ENABLED +#define bind_methodv(m_type, m_name, m_method, m_arg_names, m_default_args) \ + METHOD_CLASS(m_type, m_name, m_method); \ + register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args); +#else +#define bind_methodv(m_type, m_name, m_method, m_arg_names, m_default_args) \ + METHOD_CLASS(m_type, m_name, m_method); \ + register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args); +#endif -void Variant::_register_variant_methods() { - _VariantCall::type_internal_methods = memnew_arr(_VariantCall::MethodMap, Variant::VARIANT_MAX); - _VariantCall::type_internal_method_names = memnew_arr(List<StringName>, Variant::VARIANT_MAX); +#ifdef DEBUG_METHODS_ENABLED +#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \ + FUNCTION_CLASS(m_type, m_name, m_method); \ + register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args); +#else +#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \ + FUNCTION_CLASS(m_type, m_name, m_method); \ + register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args); +#endif + +#define bind_custom(m_type, m_name, m_method, m_has_return, m_ret_type) \ + VARARG_CLASS(m_type, m_name, m_method, m_has_return, m_ret_type) \ + register_builtin_method<Method_##m_type##_##m_name>(sarray(), Vector<Variant>()); + +static void _register_variant_builtin_methods() { _VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX); + builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX); + builtin_method_names = memnew_arr(List<StringName>, Variant::VARIANT_MAX); /* String */ @@ -937,7 +875,7 @@ void Variant::_register_variant_methods() { bind_method(String, naturalnocasecmp_to, sarray("to"), varray()); bind_method(String, length, sarray(), varray()); bind_method(String, substr, sarray("from", "len"), varray(-1)); - bind_methodv(find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0)); + bind_methodv(String, find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0)); bind_method(String, count, sarray("what", "from", "to"), varray(0, 0)); bind_method(String, countn, sarray("what", "from", "to"), varray(0, 0)); bind_method(String, findn, sarray("what", "from"), varray(0)); @@ -945,7 +883,7 @@ void Variant::_register_variant_methods() { bind_method(String, rfindn, sarray("what", "from"), varray(-1)); bind_method(String, match, sarray("expr"), varray()); bind_method(String, matchn, sarray("expr"), varray()); - bind_methodv(begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray()); + bind_methodv(String, begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray()); bind_method(String, ends_with, sarray("text"), varray()); bind_method(String, is_subsequence_of, sarray("text"), varray()); bind_method(String, is_subsequence_ofi, sarray("text"), varray()); @@ -953,7 +891,7 @@ void Variant::_register_variant_methods() { bind_method(String, similarity, sarray("text"), varray()); bind_method(String, format, sarray("values", "placeholder"), varray("{_}")); - bind_methodv(replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray()); + bind_methodv(String, replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray()); bind_method(String, replacen, sarray("what", "forwhat"), varray()); bind_method(String, repeat, sarray("count"), varray()); bind_method(String, insert, sarray("position", "what"), varray()); @@ -1084,7 +1022,7 @@ void Variant::_register_variant_methods() { bind_method(Rect2, merge, sarray("b"), varray()); bind_method(Rect2, expand, sarray("to"), varray()); bind_method(Rect2, grow, sarray("by"), varray()); - bind_methodv(grow_margin, &Rect2::grow_margin_bind, sarray("margin", "by"), varray()); + bind_methodv(Rect2, grow_margin, &Rect2::grow_margin_bind, sarray("margin", "by"), varray()); bind_method(Rect2, grow_individual, sarray("left", "top", "right", "bottom"), varray()); bind_method(Rect2, abs, sarray(), varray()); @@ -1099,7 +1037,7 @@ void Variant::_register_variant_methods() { bind_method(Rect2i, merge, sarray("b"), varray()); bind_method(Rect2i, expand, sarray("to"), varray()); bind_method(Rect2i, grow, sarray("by"), varray()); - bind_methodv(grow_margin, &Rect2i::grow_margin_bind, sarray("margin", "by"), varray()); + bind_methodv(Rect2i, grow_margin, &Rect2i::grow_margin_bind, sarray("margin", "by"), varray()); bind_method(Rect2i, grow_individual, sarray("left", "top", "right", "bottom"), varray()); bind_method(Rect2i, abs, sarray(), varray()); @@ -1155,9 +1093,9 @@ void Variant::_register_variant_methods() { bind_method(Plane, distance_to, sarray("point"), varray()); bind_method(Plane, has_point, sarray("point", "epsilon"), varray(CMP_EPSILON)); bind_method(Plane, project, sarray("point"), varray()); - bind_methodv(intersect_3, &Plane::intersect_3_bind, sarray("b", "c"), varray()); - bind_methodv(intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray()); - bind_methodv(intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray()); + bind_methodv(Plane, intersect_3, &Plane::intersect_3_bind, sarray("b", "c"), varray()); + bind_methodv(Plane, intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray()); + bind_methodv(Plane, intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray()); /* Quat */ @@ -1199,7 +1137,7 @@ void Variant::_register_variant_methods() { /* RID */ - bind_method(::RID, get_id, sarray(), varray()); + bind_method(RID, get_id, sarray(), varray()); /* NodePath */ @@ -1223,9 +1161,9 @@ void Variant::_register_variant_methods() { bind_method(Callable, hash, sarray(), varray()); bind_method(Callable, unbind, sarray("argcount"), varray()); - bind_custom(Variant::CALLABLE, "call", _VariantCall::func_Callable_call, Variant::InternalMethod::FLAG_VARARGS | Variant::InternalMethod::FLAG_RETURNS_VARIANT, Vector<Variant::Type>(), Variant::NIL, sarray()); - bind_custom(Variant::CALLABLE, "call_deferred", _VariantCall::func_Callable_call_deferred, Variant::InternalMethod::FLAG_VARARGS, Vector<Variant::Type>(), Variant::NIL, sarray()); - bind_custom(Variant::CALLABLE, "bind", _VariantCall::func_Callable_bind, Variant::InternalMethod::FLAG_VARARGS, Vector<Variant::Type>(), Variant::CALLABLE, sarray()); + bind_custom(Callable, call, _VariantCall::func_Callable_call, true, Variant); + bind_custom(Callable, call_deferred, _VariantCall::func_Callable_call_deferred, false, Variant); + bind_custom(Callable, bind, _VariantCall::func_Callable_bind, true, Callable); /* Signal */ @@ -1239,7 +1177,7 @@ void Variant::_register_variant_methods() { bind_method(Signal, is_connected, sarray("callable"), varray()); bind_method(Signal, get_connections, sarray(), varray()); - bind_custom(Variant::SIGNAL, "emit", _VariantCall::func_Signal_emit, Variant::InternalMethod::FLAG_VARARGS, Vector<Variant::Type>(), Variant::NIL, sarray()); + bind_custom(Signal, emit, _VariantCall::func_Signal_emit, false, Variant); /* Transform2D */ @@ -1263,7 +1201,7 @@ void Variant::_register_variant_methods() { bind_method(Basis, transposed, sarray(), varray()); bind_method(Basis, orthonormalized, sarray(), varray()); bind_method(Basis, determinant, sarray(), varray()); - bind_methodv(rotated, static_cast<Basis (Basis::*)(const Vector3 &, float) const>(&Basis::rotated), sarray("axis", "phi"), varray()); + bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, float) const>(&Basis::rotated), sarray("axis", "phi"), varray()); bind_method(Basis, scaled, sarray("scale"), varray()); bind_method(Basis, get_scale, sarray(), varray()); bind_method(Basis, get_euler, sarray(), varray()); @@ -1277,29 +1215,29 @@ void Variant::_register_variant_methods() { /* AABB */ - bind_method(::AABB, abs, sarray(), varray()); - bind_method(::AABB, get_area, sarray(), varray()); - bind_method(::AABB, has_no_area, sarray(), varray()); - bind_method(::AABB, has_no_surface, sarray(), varray()); - bind_method(::AABB, has_point, sarray("point"), varray()); - bind_method(::AABB, is_equal_approx, sarray("aabb"), varray()); - bind_method(::AABB, intersects, sarray("with"), varray()); - bind_method(::AABB, encloses, sarray("with"), varray()); - bind_method(::AABB, intersects_plane, sarray("plane"), varray()); - bind_method(::AABB, intersection, sarray("with"), varray()); - bind_method(::AABB, merge, sarray("with"), varray()); - bind_method(::AABB, expand, sarray("to_point"), varray()); - bind_method(::AABB, grow, sarray("by"), varray()); - bind_method(::AABB, get_support, sarray("dir"), varray()); - bind_method(::AABB, get_longest_axis, sarray(), varray()); - bind_method(::AABB, get_longest_axis_index, sarray(), varray()); - bind_method(::AABB, get_longest_axis_size, sarray(), varray()); - bind_method(::AABB, get_shortest_axis, sarray(), varray()); - bind_method(::AABB, get_shortest_axis_index, sarray(), varray()); - bind_method(::AABB, get_shortest_axis_size, sarray(), varray()); - bind_method(::AABB, get_endpoint, sarray("idx"), varray()); - bind_methodv(intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray()); - bind_methodv(intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray()); + bind_method(AABB, abs, sarray(), varray()); + bind_method(AABB, get_area, sarray(), varray()); + bind_method(AABB, has_no_area, sarray(), varray()); + bind_method(AABB, has_no_surface, sarray(), varray()); + bind_method(AABB, has_point, sarray("point"), varray()); + bind_method(AABB, is_equal_approx, sarray("aabb"), varray()); + bind_method(AABB, intersects, sarray("with"), varray()); + bind_method(AABB, encloses, sarray("with"), varray()); + bind_method(AABB, intersects_plane, sarray("plane"), varray()); + bind_method(AABB, intersection, sarray("with"), varray()); + bind_method(AABB, merge, sarray("with"), varray()); + bind_method(AABB, expand, sarray("to_point"), varray()); + bind_method(AABB, grow, sarray("by"), varray()); + bind_method(AABB, get_support, sarray("dir"), varray()); + bind_method(AABB, get_longest_axis, sarray(), varray()); + bind_method(AABB, get_longest_axis_index, sarray(), varray()); + bind_method(AABB, get_longest_axis_size, sarray(), varray()); + bind_method(AABB, get_shortest_axis, sarray(), varray()); + bind_method(AABB, get_shortest_axis_index, sarray(), varray()); + bind_method(AABB, get_shortest_axis_size, sarray(), varray()); + bind_method(AABB, get_endpoint, sarray("idx"), varray()); + bind_methodv(AABB, intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray()); + bind_methodv(AABB, intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray()); /* Transform */ @@ -1376,14 +1314,14 @@ void Variant::_register_variant_methods() { bind_method(PackedByteArray, subarray, sarray("from", "to"), varray()); bind_method(PackedByteArray, sort, sarray(), varray()); - bind_function("get_string_from_ascii", _VariantCall::func_PackedByteArray_get_string_from_ascii, sarray(), varray()); - bind_function("get_string_from_utf8", _VariantCall::func_PackedByteArray_get_string_from_utf8, sarray(), varray()); - bind_function("get_string_from_utf16", _VariantCall::func_PackedByteArray_get_string_from_utf16, sarray(), varray()); - bind_function("get_string_from_utf32", _VariantCall::func_PackedByteArray_get_string_from_utf32, sarray(), varray()); - bind_function("hex_encode", _VariantCall::func_PackedByteArray_hex_encode, sarray(), varray()); - bind_function("compress", _VariantCall::func_PackedByteArray_compress, sarray("compression_mode"), varray(0)); - bind_function("decompress", _VariantCall::func_PackedByteArray_decompress, sarray("buffer_size", "compression_mode"), varray(0)); - bind_function("decompress_dynamic", _VariantCall::func_PackedByteArray_decompress_dynamic, sarray("max_output_size", "compression_mode"), varray(0)); + bind_function(PackedByteArray, get_string_from_ascii, _VariantCall::func_PackedByteArray_get_string_from_ascii, sarray(), varray()); + bind_function(PackedByteArray, get_string_from_utf8, _VariantCall::func_PackedByteArray_get_string_from_utf8, sarray(), varray()); + bind_function(PackedByteArray, get_string_from_utf16, _VariantCall::func_PackedByteArray_get_string_from_utf16, sarray(), varray()); + bind_function(PackedByteArray, get_string_from_utf32, _VariantCall::func_PackedByteArray_get_string_from_utf32, sarray(), varray()); + bind_function(PackedByteArray, hex_encode, _VariantCall::func_PackedByteArray_hex_encode, sarray(), varray()); + bind_function(PackedByteArray, compress, _VariantCall::func_PackedByteArray_compress, sarray("compression_mode"), varray(0)); + bind_function(PackedByteArray, decompress, _VariantCall::func_PackedByteArray_decompress, sarray("buffer_size", "compression_mode"), varray(0)); + bind_function(PackedByteArray, decompress_dynamic, _VariantCall::func_PackedByteArray_decompress_dynamic, sarray("max_output_size", "compression_mode"), varray(0)); /* Int32 Array */ @@ -1605,18 +1543,13 @@ void Variant::_register_variant_methods() { _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1)); } +void Variant::_register_variant_methods() { + _register_variant_builtin_methods(); //needs to be out due to namespace +} + void Variant::_unregister_variant_methods() { //clear methods - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - for (List<StringName>::Element *E = _VariantCall::type_internal_method_names[i].front(); E; E = E->next()) { - Variant::InternalMethod **m = _VariantCall::type_internal_methods[i].lookup_ptr(E->get()); - if (*m) { - memdelete(*m); - } - } - } - - memdelete_arr(_VariantCall::type_internal_methods); - memdelete_arr(_VariantCall::type_internal_method_names); + memdelete_arr(builtin_method_names); + memdelete_arr(builtin_method_info); memdelete_arr(_VariantCall::constant_data); } diff --git a/core/variant/variant_builtin_funcs.cpp b/core/variant/variant_utility.cpp index e89b83e6dd..91a1b0262c 100644 --- a/core/variant/variant_builtin_funcs.cpp +++ b/core/variant/variant_utility.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* variant_builtin_funcs.cpp */ +/* variant_utility.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -38,7 +38,7 @@ #include "core/variant/binder_common.h" #include "core/variant/variant_parser.h" -struct VariantBuiltinFunctions { +struct VariantUtilityFunctions { // Math static inline double sin(double arg) { return Math::sin(arg); @@ -725,7 +725,7 @@ template <class R, class... P, size_t... Is> static _FORCE_INLINE_ void call_helperpr(R (*p_func)(P...), Variant *ret, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) { r_error.error = Callable::CallError::CALL_OK; VCALLR; - (void)p_args; + (void)p_args; // avoid gcc warning (void)r_error; } @@ -827,50 +827,50 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - call_helperr(VariantBuiltinFunctions::m_func, r_ret, p_args, r_error); \ + call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args, r_error); \ } \ \ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - validated_call_helperr(VariantBuiltinFunctions::m_func, r_ret, p_args); \ + validated_call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args); \ } \ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - ptr_call_helperr(VariantBuiltinFunctions::m_func, ret, p_args); \ + ptr_call_helperr(VariantUtilityFunctions::m_func, ret, p_args); \ } \ \ static int get_argument_count() { \ - return get_arg_count_helperr(VariantBuiltinFunctions::m_func); \ + return get_arg_count_helperr(VariantUtilityFunctions::m_func); \ } \ \ static Variant::Type get_argument_type(int p_arg) { \ - return get_arg_type_helperr(VariantBuiltinFunctions::m_func, p_arg); \ + return get_arg_type_helperr(VariantUtilityFunctions::m_func, p_arg); \ } \ \ static Variant::Type get_return_type() { \ - return get_ret_type_helperr(VariantBuiltinFunctions::m_func); \ + return get_ret_type_helperr(VariantUtilityFunctions::m_func); \ } \ static bool has_return_type() { \ return true; \ } \ static bool is_vararg() { return false; } \ - static Variant::BuiltInFunctionType get_type() { return m_category; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ - register_builtin_function<Func_##m_func>(#m_func, m_args) + register_utility_function<Func_##m_func>(#m_func, m_args) #define FUNCBINDVR(m_func, m_args, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantBuiltinFunctions::m_func(*p_args[0], r_error); \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], r_error); \ } \ \ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ Callable::CallError ce; \ - *r_ret = VariantBuiltinFunctions::m_func(*p_args[0], ce); \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], ce); \ } \ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ Callable::CallError ce; \ - PtrToArg<Variant>::encode(VariantBuiltinFunctions::m_func(PtrToArg<Variant>::convert(p_args[0]), ce), ret); \ + PtrToArg<Variant>::encode(VariantUtilityFunctions::m_func(PtrToArg<Variant>::convert(p_args[0]), ce), ret); \ } \ \ static int get_argument_count() { \ @@ -888,26 +888,26 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return true; \ } \ static bool is_vararg() { return false; } \ - static Variant::BuiltInFunctionType get_type() { return m_category; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ - register_builtin_function<Func_##m_func>(#m_func, m_args) + register_utility_function<Func_##m_func>(#m_func, m_args) #define FUNCBINDVR3(m_func, m_args, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantBuiltinFunctions::m_func(*p_args[0], *p_args[1], *p_args[2], r_error); \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], *p_args[2], r_error); \ } \ \ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ Callable::CallError ce; \ - *r_ret = VariantBuiltinFunctions::m_func(*p_args[0], *p_args[1], *p_args[2], ce); \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], *p_args[2], ce); \ } \ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ Callable::CallError ce; \ Variant r; \ - r = VariantBuiltinFunctions::m_func(PtrToArg<Variant>::convert(p_args[0]), PtrToArg<Variant>::convert(p_args[1]), PtrToArg<Variant>::convert(p_args[2]), ce); \ + r = VariantUtilityFunctions::m_func(PtrToArg<Variant>::convert(p_args[0]), PtrToArg<Variant>::convert(p_args[1]), PtrToArg<Variant>::convert(p_args[2]), ce); \ PtrToArg<Variant>::encode(r, ret); \ } \ \ @@ -926,21 +926,21 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return true; \ } \ static bool is_vararg() { return false; } \ - static Variant::BuiltInFunctionType get_type() { return m_category; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ - register_builtin_function<Func_##m_func>(#m_func, m_args) + register_utility_function<Func_##m_func>(#m_func, m_args) #define FUNCBINDVARARG(m_func, m_args, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantBuiltinFunctions::m_func(p_args, p_argcount, r_error); \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ } \ \ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ Callable::CallError c; \ - *r_ret = VariantBuiltinFunctions::m_func(p_args, p_argcount, c); \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ } \ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ Vector<Variant> args; \ @@ -973,23 +973,23 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool is_vararg() { \ return true; \ } \ - static Variant::BuiltInFunctionType get_type() { \ + static Variant::UtilityFunctionType get_type() { \ return m_category; \ } \ }; \ - register_builtin_function<Func_##m_func>(#m_func, m_args) + register_utility_function<Func_##m_func>(#m_func, m_args) #define FUNCBINDVARARGS(m_func, m_args, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantBuiltinFunctions::m_func(p_args, p_argcount, r_error); \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ } \ \ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ Callable::CallError c; \ - *r_ret = VariantBuiltinFunctions::m_func(p_args, p_argcount, c); \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ } \ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ Vector<Variant> args; \ @@ -1022,23 +1022,23 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool is_vararg() { \ return true; \ } \ - static Variant::BuiltInFunctionType get_type() { \ + static Variant::UtilityFunctionType get_type() { \ return m_category; \ } \ }; \ - register_builtin_function<Func_##m_func>(#m_func, m_args) + register_utility_function<Func_##m_func>(#m_func, m_args) #define FUNCBINDVARARGV(m_func, m_args, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ r_error.error = Callable::CallError::CALL_OK; \ - VariantBuiltinFunctions::m_func(p_args, p_argcount, r_error); \ + VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ } \ \ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ Callable::CallError c; \ - VariantBuiltinFunctions::m_func(p_args, p_argcount, c); \ + VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ } \ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ Vector<Variant> args; \ @@ -1070,218 +1070,218 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool is_vararg() { \ return true; \ } \ - static Variant::BuiltInFunctionType get_type() { \ + static Variant::UtilityFunctionType get_type() { \ return m_category; \ } \ }; \ - register_builtin_function<Func_##m_func>(#m_func, m_args) + register_utility_function<Func_##m_func>(#m_func, m_args) #define FUNCBIND(m_func, m_args, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - call_helper(VariantBuiltinFunctions::m_func, p_args, r_error); \ + call_helper(VariantUtilityFunctions::m_func, p_args, r_error); \ } \ \ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - validated_call_helper(VariantBuiltinFunctions::m_func, p_args); \ + validated_call_helper(VariantUtilityFunctions::m_func, p_args); \ } \ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - ptr_call_helper(VariantBuiltinFunctions::m_func, p_args); \ + ptr_call_helper(VariantUtilityFunctions::m_func, p_args); \ } \ \ static int get_argument_count() { \ - return get_arg_count_helper(VariantBuiltinFunctions::m_func); \ + return get_arg_count_helper(VariantUtilityFunctions::m_func); \ } \ \ static Variant::Type get_argument_type(int p_arg) { \ - return get_arg_type_helper(VariantBuiltinFunctions::m_func, p_arg); \ + return get_arg_type_helper(VariantUtilityFunctions::m_func, p_arg); \ } \ \ static Variant::Type get_return_type() { \ - return get_ret_type_helper(VariantBuiltinFunctions::m_func); \ + return get_ret_type_helper(VariantUtilityFunctions::m_func); \ } \ static bool has_return_type() { \ return false; \ } \ static bool is_vararg() { return false; } \ - static Variant::BuiltInFunctionType get_type() { return m_category; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ - register_builtin_function<Func_##m_func>(#m_func, m_args) + register_utility_function<Func_##m_func>(#m_func, m_args) -struct VariantBuiltinFunctionInfo { - void (*call_builtin)(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - Variant::BuiltinFunctionValidatedCall validated_call_builtin; - Variant::BuiltinFunctionPTRCall ptr_call_builtin; +struct VariantUtilityFunctionInfo { + void (*call_utility)(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error); + Variant::ValidatedUtilityFunction validated_call_utility; + Variant::PTRUtilityFunction ptr_call_utility; Vector<String> argnames; bool is_vararg; bool returns_value; int argcount; Variant::Type (*get_arg_type)(int); Variant::Type return_type; - Variant::BuiltInFunctionType type; + Variant::UtilityFunctionType type; }; -static OAHashMap<StringName, VariantBuiltinFunctionInfo> builtin_function_table; -static List<StringName> builtin_function_name_table; +static OAHashMap<StringName, VariantUtilityFunctionInfo> utility_function_table; +static List<StringName> utility_function_name_table; template <class T> -static void register_builtin_function(const String &p_name, const Vector<String> &argnames) { +static void register_utility_function(const String &p_name, const Vector<String> &argnames) { String name = p_name; if (name.begins_with("_")) { name = name.substr(1, name.length() - 1); } StringName sname = name; - ERR_FAIL_COND(builtin_function_table.has(sname)); + ERR_FAIL_COND(utility_function_table.has(sname)); - VariantBuiltinFunctionInfo bfi; - bfi.call_builtin = T::call; - bfi.validated_call_builtin = T::validated_call; - bfi.ptr_call_builtin = T::ptrcall; + VariantUtilityFunctionInfo bfi; + bfi.call_utility = T::call; + bfi.validated_call_utility = T::validated_call; + bfi.ptr_call_utility = T::ptrcall; bfi.is_vararg = T::is_vararg(); bfi.argnames = argnames; bfi.argcount = T::get_argument_count(); if (!bfi.is_vararg) { - ERR_FAIL_COND_MSG(argnames.size() != bfi.argcount, "wrong number of arguments binding builtin function: " + name); + ERR_FAIL_COND_MSG(argnames.size() != bfi.argcount, "wrong number of arguments binding utility function: " + name); } bfi.get_arg_type = T::get_argument_type; bfi.return_type = T::get_return_type(); bfi.type = T::get_type(); bfi.returns_value = T::has_return_type(); - builtin_function_table.insert(sname, bfi); - builtin_function_name_table.push_back(sname); + utility_function_table.insert(sname, bfi); + utility_function_name_table.push_back(sname); } -void Variant::_register_variant_builtin_funcs() { +void Variant::_register_variant_utility_functions() { // Math - FUNCBINDR(sin, sarray("angle_rad"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(cos, sarray("angle_rad"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(tan, sarray("angle_rad"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(sin, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cos, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(tan, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(sinh, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(cosh, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(tanh, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(sinh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cosh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(tanh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(asin, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(acos, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(atan, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(asin, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(acos, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(atan, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(atan2, sarray("y", "x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(atan2, sarray("y", "x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(sqrt, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(fmod, sarray("x", "y"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(fposmod, sarray("x", "y"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(floor, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(ceil, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(round, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(sqrt, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR(abs, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDVR(abs, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(absf, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(absi, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(absf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(absi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR(sign, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDVR(sign, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(signf, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(signi, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(signf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(signi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(pow, sarray("x", "y"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(log, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(exp, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(pow, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(log, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(exp, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(is_nan, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(is_inf, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(is_nan, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(is_inf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(is_zero_approx, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(is_zero_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(ease, sarray("x", "c"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(step_decimals, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(range_step_decimals, sarray("x"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(stepify, sarray("x", "y"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(ease, sarray("x", "c"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(range_step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(stepify, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(lerp, sarray("from", "to", "c"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(lerp_angle, sarray("from", "to", "c"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(inverse_lerp, sarray("from", "to", "c"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(lerp, sarray("from", "to", "c"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(lerp_angle, sarray("from", "to", "c"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(inverse_lerp, sarray("from", "to", "c"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(smoothstep, sarray("from", "to", "c"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(dectime, sarray("value", "amount", "step"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(smoothstep, sarray("from", "to", "c"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(dectime, sarray("value", "amount", "step"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(deg2rad, sarray("deg"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(rad2deg, sarray("rad"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(linear2db, sarray("lin"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(db2linear, sarray("db"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(deg2rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(rad2deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(linear2db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(db2linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(polar2cartesian, sarray("r", "th"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(cartesian2polar, sarray("x", "y"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(polar2cartesian, sarray("r", "th"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cartesian2polar, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVARARG(max, sarray(), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDVARARG(max, sarray(), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(maxi, sarray("a", "b"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(maxf, sarray("a", "b"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(maxi, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(maxf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVARARG(min, sarray(), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDVARARG(min, sarray(), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(mini, sarray("a", "b"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(minf, sarray("a", "b"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(mini, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(minf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR3(clamp, sarray("value", "min", "max"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(clampi, sarray("value", "min", "max"), Variant::BUILTIN_FUNC_TYPE_MATH); - FUNCBINDR(clampf, sarray("value", "min", "max"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDVR3(clamp, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(clampi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(clampf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(nearest_po2, sarray("value"), Variant::BUILTIN_FUNC_TYPE_MATH); + FUNCBINDR(nearest_po2, sarray("value"), Variant::UTILITY_FUNC_TYPE_MATH); //Random - FUNCBIND(randomize, sarray(), Variant::BUILTIN_FUNC_TYPE_RANDOM); - FUNCBINDR(randi, sarray(), Variant::BUILTIN_FUNC_TYPE_RANDOM); - FUNCBINDR(randf, sarray(), Variant::BUILTIN_FUNC_TYPE_RANDOM); - FUNCBINDR(randi_range, sarray("from", "to"), Variant::BUILTIN_FUNC_TYPE_RANDOM); - FUNCBINDR(randf_range, sarray("from", "to"), Variant::BUILTIN_FUNC_TYPE_RANDOM); - FUNCBIND(seed, sarray("base"), Variant::BUILTIN_FUNC_TYPE_RANDOM); - FUNCBINDR(rand_from_seed, sarray("seed"), Variant::BUILTIN_FUNC_TYPE_RANDOM); + FUNCBIND(randomize, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randi, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randf, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randi_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randf_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBIND(seed, sarray("base"), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(rand_from_seed, sarray("seed"), Variant::UTILITY_FUNC_TYPE_RANDOM); // Utility - FUNCBINDVR(weakref, sarray("from"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDR(_typeof, sarray("variable"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGS(str, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGV(print, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGV(printerr, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGV(printt, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGV(prints, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGV(printraw, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGV(push_error, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDVARARGV(push_warning, sarray(), Variant::BUILTIN_FUNC_TYPE_UTILITY); - - FUNCBINDR(var2str, sarray("variable"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDR(str2var, sarray("string"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - - FUNCBINDR(var2bytes, sarray("variable"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDR(bytes2var, sarray("bytes"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - - FUNCBINDR(var2bytes_with_objects, sarray("variable"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDR(bytes2var_with_objects, sarray("bytes"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - - FUNCBINDR(hash, sarray("variable"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - - FUNCBINDR(instance_from_id, sarray("id"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDR(is_instance_id_valid, sarray("id"), Variant::BUILTIN_FUNC_TYPE_UTILITY); - FUNCBINDR(is_instance_valid, sarray("instance"), Variant::BUILTIN_FUNC_TYPE_UTILITY); + FUNCBINDVR(weakref, sarray("from"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(_typeof, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGS(str, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(print, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(printerr, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(printt, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(prints, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(printraw, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(push_error, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(push_warning, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + + FUNCBINDR(var2str, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(str2var, sarray("string"), Variant::UTILITY_FUNC_TYPE_GENERAL); + + FUNCBINDR(var2bytes, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(bytes2var, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL); + + FUNCBINDR(var2bytes_with_objects, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(bytes2var_with_objects, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL); + + FUNCBINDR(hash, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); + + FUNCBINDR(instance_from_id, sarray("id"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(is_instance_id_valid, sarray("id"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(is_instance_valid, sarray("instance"), Variant::UTILITY_FUNC_TYPE_GENERAL); } -void Variant::_unregister_variant_builtin_funcs() { - builtin_function_table.clear(); - builtin_function_name_table.clear(); +void Variant::_unregister_variant_utility_functions() { + utility_function_table.clear(); + utility_function_name_table.clear(); } -void Variant::call_builtin_func(const StringName &p_name, Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +void Variant::call_utility_function(const StringName &p_name, Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error.argument = 0; @@ -1303,57 +1303,57 @@ void Variant::call_builtin_func(const StringName &p_name, Variant *r_ret, const return; } - bfi->call_builtin(r_ret, p_args, p_argcount, r_error); + bfi->call_utility(r_ret, p_args, p_argcount, r_error); } -bool Variant::has_builtin_func(const StringName &p_name) { - return builtin_function_table.has(p_name); +bool Variant::has_utility_function(const StringName &p_name) { + return utility_function_table.has(p_name); } -Variant::BuiltinFunctionValidatedCall Variant::get_builtin_validated_caller(const StringName &p_name) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +Variant::ValidatedUtilityFunction Variant::get_validated_utility_function(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return nullptr; } - return bfi->validated_call_builtin; + return bfi->validated_call_utility; } -Variant::BuiltinFunctionPTRCall Variant::get_builtin_ptr_caller(const StringName &p_name) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +Variant::PTRUtilityFunction Variant::get_ptr_utility_function(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return nullptr; } - return bfi->ptr_call_builtin; + return bfi->ptr_call_utility; } -Variant::BuiltInFunctionType Variant::get_builtin_func_type(const StringName &p_name) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +Variant::UtilityFunctionType Variant::get_utility_function_type(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { - return Variant::BUILTIN_FUNC_TYPE_MATH; + return Variant::UTILITY_FUNC_TYPE_MATH; } return bfi->type; } -int Variant::get_builtin_func_argument_count(const StringName &p_name) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +int Variant::get_utility_function_argument_count(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return 0; } return bfi->argcount; } -Variant::Type Variant::get_builtin_func_argument_type(const StringName &p_name, int p_arg) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +Variant::Type Variant::get_utility_function_argument_type(const StringName &p_name, int p_arg) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return Variant::NIL; } return bfi->get_arg_type(p_arg); } -String Variant::get_builtin_func_argument_name(const StringName &p_name, int p_arg) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +String Variant::get_utility_function_argument_name(const StringName &p_name, int p_arg) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return String(); } @@ -1361,23 +1361,23 @@ String Variant::get_builtin_func_argument_name(const StringName &p_name, int p_a ERR_FAIL_INDEX_V(p_arg, bfi->argnames.size(), String()); return bfi->argnames[p_arg]; } -bool Variant::has_builtin_func_return_value(const StringName &p_name) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +bool Variant::has_utility_function_return_value(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return false; } return bfi->returns_value; } -Variant::Type Variant::get_builtin_func_return_type(const StringName &p_name) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +Variant::Type Variant::get_utility_function_return_type(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return Variant::NIL; } return bfi->return_type; } -bool Variant::is_builtin_func_vararg(const StringName &p_name) { - const VariantBuiltinFunctionInfo *bfi = builtin_function_table.lookup_ptr(p_name); +bool Variant::is_utility_function_vararg(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { return false; } @@ -1385,8 +1385,8 @@ bool Variant::is_builtin_func_vararg(const StringName &p_name) { return bfi->is_vararg; } -void Variant::get_builtin_function_list(List<StringName> *r_functions) { - for (List<StringName>::Element *E = builtin_function_name_table.front(); E; E = E->next()) { +void Variant::get_utility_function_list(List<StringName> *r_functions) { + for (List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) { r_functions->push_back(E->get()); } } diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index ae8703c837..9705a196ed 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -63,13 +63,13 @@ <argument index="3" name="a" type="float"> </argument> <description> - Constructs a [Color] from an RGBA profile using values between 0 and 1. + Constructs a [Color] from RGBA values, typically between 0 and 1. [codeblocks] [gdscript] - var color = Color(0.2, 1.0, 0.7, 0.8) # Equivalent to RGBA(51, 255, 178, 204) + var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)` [/gdscript] [csharp] - var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Equivalent to RGBA(51, 255, 178, 255, 204) + var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)` [/csharp] [/codeblocks] </description> @@ -84,13 +84,13 @@ <argument index="2" name="b" type="float"> </argument> <description> - Constructs a color from an RGB profile using values between 0 and 1. Alpha will always be 1. + Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1. [codeblocks] [gdscript] - var color = Color(0.2, 1.0, 0.7) # Equivalent to RGBA(51, 255, 178, 255) + var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)` [/gdscript] [csharp] - var color = new Color(0.2f, 1.0f, 0.7f); // Equivalent to RGBA(51, 255, 178, 255) + var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)` [/csharp] [/codeblocks] </description> @@ -143,11 +143,11 @@ [codeblocks] [gdscript] var color = Color(0.3, 0.4, 0.9) - var inverted_color = color.inverted() # A color of an RGBA(178, 153, 26, 255) + var inverted_color = color.inverted() # Equivalent to `Color(0.7, 0.6, 0.1)` [/gdscript] [csharp] var color = new Color(0.3f, 0.4f, 0.9f); - Color invertedColor = color.Inverted(); // A color of an RGBA(178, 153, 26, 255) + Color invertedColor = color.Inverted(); // Equivalent to `new Color(0.7f, 0.6f, 0.1f)` [/csharp] [/codeblocks] </description> @@ -174,12 +174,12 @@ [gdscript] var c1 = Color(1.0, 0.0, 0.0) var c2 = Color(0.0, 1.0, 0.0) - var lerp_color = c1.lerp(c2, 0.5) # A color of an RGBA(128, 128, 0, 255) + var lerp_color = c1.lerp(c2, 0.5) # Equivalent to `Color(0.5, 0.5, 0.0)` [/gdscript] [csharp] var c1 = new Color(1.0f, 0.0f, 0.0f); var c2 = new Color(0.0f, 1.0f, 0.0f); - Color lerpColor = c1.Lerp(c2, 0.5f); // A color of an RGBA(128, 128, 0, 255) + Color lerpColor = c1.Lerp(c2, 0.5f); // Equivalent to `new Color(0.5f, 0.5f, 0.0f)` [/csharp] [/codeblocks] </description> @@ -299,7 +299,7 @@ <return type="int"> </return> <description> - Returns the color's 32-bit integer in ABGR format (each byte represents a component of the ABGR profile). ABGR is the reversed version of the default format. + Returns the color converted to a 32-bit integer in ABGR format (each byte represents a color channel). ABGR is the reversed version of the default format. [codeblocks] [gdscript] var color = Color(1, 0.5, 0.2) @@ -316,7 +316,7 @@ <return type="int"> </return> <description> - Returns the color's 64-bit integer in ABGR format (each word represents a component of the ABGR profile). ABGR is the reversed version of the default format. + Returns the color converted to a 64-bit integer in ABGR format (each word represents a color channel). ABGR is the reversed version of the default format. [codeblocks] [gdscript] var color = Color(1, 0.5, 0.2) @@ -333,7 +333,7 @@ <return type="int"> </return> <description> - Returns the color's 32-bit integer in ARGB format (each byte represents a component of the ARGB profile). ARGB is more compatible with DirectX. + Returns the color converted to a 32-bit integer in ARGB format (each byte represents a color channel). ARGB is more compatible with DirectX. [codeblocks] [gdscript] var color = Color(1, 0.5, 0.2) @@ -350,7 +350,7 @@ <return type="int"> </return> <description> - Returns the color's 64-bit integer in ARGB format (each word represents a component of the ARGB profile). ARGB is more compatible with DirectX. + Returns the color converted to a 64-bit integer in ARGB format (each word represents a color channel). ARGB is more compatible with DirectX. [codeblocks] [gdscript] var color = Color(1, 0.5, 0.2) @@ -369,7 +369,7 @@ <argument index="0" name="with_alpha" type="bool" default="true"> </argument> <description> - Returns the color's HTML hexadecimal color string in RGBA format (ex: [code]ff34f822[/code]). + Returns the color converted to an HTML hexadecimal color string in RGBA format (ex: [code]ff34f822[/code]). Setting [code]with_alpha[/code] to [code]false[/code] excludes alpha from the hexadecimal string (and uses RGB instead of RGBA format). [codeblocks] [gdscript] @@ -389,7 +389,7 @@ <return type="int"> </return> <description> - Returns the color's 32-bit integer in RGBA format (each byte represents a component of the RGBA profile). RGBA is Godot's default format. + Returns the color converted to a 32-bit integer in RGBA format (each byte represents a color channel). RGBA is Godot's default format. [codeblocks] [gdscript] var color = Color(1, 0.5, 0.2) @@ -406,7 +406,7 @@ <return type="int"> </return> <description> - Returns the color's 64-bit integer in RGBA format (each word represents a component of the RGBA profile). RGBA is Godot's default format. + Returns the color converted to a 64-bit integer in RGBA format (each word represents a color channel). RGBA is Godot's default format. [codeblocks] [gdscript] var color = Color(1, 0.5, 0.2) diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml index 4dea1bb645..adaaed4f1c 100644 --- a/doc/classes/EditorNode3DGizmoPlugin.xml +++ b/doc/classes/EditorNode3DGizmoPlugin.xml @@ -59,8 +59,11 @@ </argument> <argument index="1" name="billboard" type="bool" default="false"> </argument> + <argument index="2" name="texture" type="Texture2D" default="null"> + </argument> <description> Creates a handle material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_handles]. Should not be overridden. + You can optionally provide a texture to use instead of the default icon. </description> </method> <method name="create_icon_material"> diff --git a/doc/classes/InstancePlaceholder.xml b/doc/classes/InstancePlaceholder.xml index 39827f6604..defd23afb1 100644 --- a/doc/classes/InstancePlaceholder.xml +++ b/doc/classes/InstancePlaceholder.xml @@ -18,13 +18,14 @@ <argument index="1" name="custom_scene" type="PackedScene" default="null"> </argument> <description> + Not thread-safe. Use [method Object.call_deferred] if calling from a thread. </description> </method> <method name="get_instance_path" qualifiers="const"> <return type="String"> </return> <description> - Gets the path to the [PackedScene] resource file that is loaded by default when calling [method create_instance]. + Gets the path to the [PackedScene] resource file that is loaded by default when calling [method create_instance]. Not thread-safe. Use [method Object.call_deferred] if calling from a thread. </description> </method> <method name="get_stored_values"> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index f08a15d873..5c2dffd538 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -78,6 +78,13 @@ Returns the [PopupMenu] of this [LineEdit]. By default, this menu is displayed when right-clicking on the [LineEdit]. </description> </method> + <method name="get_scroll_offset" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the scroll offset due to [member caret_position], as a number of characters. + </description> + </method> <method name="menu_option"> <return type="void"> </return> diff --git a/doc/classes/MarginContainer.xml b/doc/classes/MarginContainer.xml index fb5f437239..c8eebd4677 100644 --- a/doc/classes/MarginContainer.xml +++ b/doc/classes/MarginContainer.xml @@ -6,13 +6,22 @@ <description> Adds a top, left, bottom, and right margin to all [Control] nodes that are direct children of the container. To control the [MarginContainer]'s margin, use the [code]margin_*[/code] theme properties listed below. [b]Note:[/b] Be careful, [Control] margin values are different than the constant margin values. If you want to change the custom margin values of the [MarginContainer] by code, you should use the following examples: - [codeblock] + [codeblocks] + [gdscript] var margin_value = 100 set("custom_constants/margin_top", margin_value) set("custom_constants/margin_left", margin_value) set("custom_constants/margin_bottom", margin_value) set("custom_constants/margin_right", margin_value) - [/codeblock] + [/gdscript] + [csharp] + int marginValue = 100; + Set("custom_constants/margin_top", marginValue); + Set("custom_constants/margin_left", marginValue); + Set("custom_constants/margin_bottom", marginValue); + Set("custom_constants/margin_right", marginValue); + [/csharp] + [/codeblocks] </description> <tutorials> </tutorials> diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml index dcc3bbf2a6..e107b1a108 100644 --- a/doc/classes/MeshDataTool.xml +++ b/doc/classes/MeshDataTool.xml @@ -7,16 +7,44 @@ MeshDataTool provides access to individual vertices in a [Mesh]. It allows users to read and edit vertex data of meshes. It also creates an array of faces and edges. To use MeshDataTool, load a mesh with [method create_from_surface]. When you are finished editing the data commit the data to a mesh with [method commit_to_surface]. Below is an example of how MeshDataTool may be used. - [codeblock] + [codeblocks] + [gdscript] + var mesh = ArrayMesh.new() + mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, CubeMesh.new().get_mesh_arrays()) var mdt = MeshDataTool.new() mdt.create_from_surface(mesh, 0) for i in range(mdt.get_vertex_count()): var vertex = mdt.get_vertex(i) - ... + # In this example we extend the mesh by one unit, which results in seperated faces as it is flat shaded. + vertex += mdt.get_vertex_normal(i) + # Save your change. mdt.set_vertex(i, vertex) mesh.surface_remove(0) mdt.commit_to_surface(mesh) - [/codeblock] + var mi = MeshInstance.new() + mi.mesh = mesh + add_child(mi) + [/gdscript] + [csharp] + var mesh = new ArrayMesh(); + mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, new CubeMesh().GetMeshArrays()); + var mdt = new MeshDataTool(); + mdt.CreateFromSurface(mesh, 0); + for (var i = 0; i < mdt.GetVertexCount(); i++) + { + Vector3 vertex = mdt.GetVertex(i); + // In this example we extend the mesh by one unit, which results in seperated faces as it is flat shaded. + vertex += mdt.GetVertexNormal(i); + // Save your change. + mdt.SetVertex(i, vertex); + } + mesh.SurfaceRemove(0); + mdt.CommitToSurface(mesh); + var mi = new MeshInstance(); + mi.Mesh = mesh; + AddChild(mi); + [/csharp] + [/codeblocks] See also [ArrayMesh], [ImmediateGeometry3D] and [SurfaceTool] for procedural geometry generation. [b]Note:[/b] Godot uses clockwise [url=https://learnopengl.com/Advanced-OpenGL/Face-culling]winding order[/url] for front faces of triangle primitive modes. </description> diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml index e75efa3b27..38921078d7 100644 --- a/doc/classes/NavigationPolygon.xml +++ b/doc/classes/NavigationPolygon.xml @@ -6,22 +6,41 @@ <description> There are two ways to create polygons. Either by using the [method add_outline] method, or using the [method add_polygon] method. Using [method add_outline]: - [codeblock] + [codeblocks] + [gdscript] var polygon = NavigationPolygon.new() var outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)]) polygon.add_outline(outline) polygon.make_polygons_from_outlines() $NavigationRegion2D.navpoly = polygon - [/codeblock] + [/gdscript] + [csharp] + var polygon = new NavigationPolygon(); + var outline = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) }; + polygon.AddOutline(outline); + polygon.MakePolygonsFromOutlines(); + GetNode<NavigationRegion2D>("NavigationRegion2D").Navpoly = polygon; + [/csharp] + [/codeblocks] Using [method add_polygon] and indices of the vertices array. - [codeblock] + [codeblocks] + [gdscript] var polygon = NavigationPolygon.new() var vertices = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)]) - polygon.set_vertices(vertices) + polygon.vertices = vertices var indices = PackedInt32Array(0, 3, 1) polygon.add_polygon(indices) $NavigationRegion2D.navpoly = polygon - [/codeblock] + [/gdscript] + [csharp] + var polygon = new NavigationPolygon(); + var vertices = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) }; + polygon.Vertices = vertices; + var indices = new int[] { 0, 3, 1 }; + polygon.AddPolygon(indices); + GetNode<NavigationRegion2D>("NavigationRegion2D").Navpoly = polygon; + [/csharp] + [/codeblocks] </description> <tutorials> <link title="2D Navigation Demo">https://godotengine.org/asset-library/asset/117</link> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 2e8b76865d..3f212fa0f6 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -130,11 +130,22 @@ Adds a child node. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node. If [code]legible_unique_name[/code] is [code]true[/code], the child node will have an human-readable name based on the name of the node being instanced instead of its type. [b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example: - [codeblock] + [codeblocks] + [gdscript] + var child_node = get_child(0) if child_node.get_parent(): child_node.get_parent().remove_child(child_node) add_child(child_node) - [/codeblock] + [/gdscript] + [csharp] + Node childNode = GetChild(0); + if (childNode.GetParent() != null) + { + childNode.GetParent().RemoveChild(childNode); + } + AddChild(childNode); + [/csharp] + [/codeblocks] If you need the child node to be added below a specific node in the list of children, use [method add_sibling] instead of this method. [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=https://godot.readthedocs.io/en/latest/tutorials/misc/running_code_in_the_editor.html]tool scripts[/url] and [url=https://godot.readthedocs.io/en/latest/tutorials/plugins/editor/index.html]editor plugins[/url]. If [method add_child] is called without setting [member owner], the newly added [Node] will not be visible in the scene tree, though it will be visible in the 2D/3D view. </description> @@ -275,12 +286,20 @@ /root/Swamp/Goblin [/codeblock] Possible paths are: - [codeblock] + [codeblocks] + [gdscript] get_node("Sword") get_node("Backpack/Dagger") get_node("../Swamp/Alligator") get_node("/root/MyGame") - [/codeblock] + [/gdscript] + [csharp] + GetNode("Sword"); + GetNode("Backpack/Dagger"); + GetNode("../Swamp/Alligator"); + GetNode("/root/MyGame"); + [/csharp] + [/codeblocks] </description> </method> <method name="get_node_and_resource"> @@ -292,11 +311,18 @@ Fetches a node and one of its resources as specified by the [NodePath]'s subname (e.g. [code]Area2D/CollisionShape2D:shape[/code]). If several nested resources are specified in the [NodePath], the last one will be fetched. The return value is an array of size 3: the first index points to the [Node] (or [code]null[/code] if not found), the second index points to the [Resource] (or [code]null[/code] if not found), and the third index is the remaining [NodePath], if any. For example, assuming that [code]Area2D/CollisionShape2D[/code] is a valid node and that its [code]shape[/code] property has been assigned a [RectangleShape2D] resource, one could have this kind of output: - [codeblock] + [codeblocks] + [gdscript] print(get_node_and_resource("Area2D/CollisionShape2D")) # [[CollisionShape2D:1161], Null, ] print(get_node_and_resource("Area2D/CollisionShape2D:shape")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], ] print(get_node_and_resource("Area2D/CollisionShape2D:shape:extents")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], :extents] - [/codeblock] + [/gdscript] + [csharp] + GD.Print(GetNodeAndResource("Area2D/CollisionShape2D")); // [[CollisionShape2D:1161], Null, ] + GD.Print(GetNodeAndResource("Area2D/CollisionShape2D:shape")); // [[CollisionShape2D:1161], [RectangleShape2D:1156], ] + GD.Print(GetNodeAndResource("Area2D/CollisionShape2D:shape:extents")); // [[CollisionShape2D:1161], [RectangleShape2D:1156], :extents] + [/csharp] + [/codeblocks] </description> </method> <method name="get_node_or_null" qualifiers="const"> diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index 93ede047fd..36835d9e94 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -51,7 +51,7 @@ The "subnames" optionally included after the path to the target node can point to resources or properties, and can also be nested. Examples of valid NodePaths (assuming that those nodes exist and have the referenced resources or properties): [codeblock] - # Points to the Sprite2D node + # Points to the Sprite2D node. "Path2D/PathFollow2D/Sprite2D" # Points to the Sprite2D node and its "texture" resource. # get_node() would retrieve "Sprite2D", while get_node_and_resource() @@ -70,14 +70,23 @@ <return type="NodePath"> </return> <description> - Returns a node path with a colon character ([code]:[/code]) prepended, transforming it to a pure property path with no node name (defaults to resolving from the current node). - [codeblock] - # This will be parsed as a node path to the "x" property in the "position" node + Returns a node path with a colon character ([code]:[/code]) prepended, transforming it to a pure property path with no node name (defaults to resolving from the from the current node). + [codeblocks] + [gdscript] + # This will be parsed as a node path to the "x" property in the "position" node. var node_path = NodePath("position:x") - # This will be parsed as a node path to the "x" component of the "position" property in the current node + # This will be parsed as a node path to the "x" component of the "position" property in the current node. var property_path = node_path.get_as_property_path() print(property_path) # :position:x - [/codeblock] + [/gdscript] + [csharp] + // This will be parsed as a node path to the "x" property in the "position" node. + var nodePath = new NodePath("position:x"); + // This will be parsed as a node path to the "x" component of the "position" property in the current node. + NodePath propertyPath = nodePath.GetAsPropertyPath(); + GD.Print(propertyPath); // :position:x + [/csharp] + [/codeblocks] </description> </method> <method name="get_concatenated_subnames"> @@ -85,10 +94,16 @@ </return> <description> Returns all subnames concatenated with a colon character ([code]:[/code]) as separator, i.e. the right side of the first colon in a node path. - [codeblock] + [codeblocks] + [gdscript] var nodepath = NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path") print(nodepath.get_concatenated_subnames()) # texture:load_path - [/codeblock] + [/gdscript] + [csharp] + var nodepath = new NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path"); + GD.Print(nodepath.GetConcatenatedSubnames()); // texture:load_path + [/csharp] + [/codeblocks] </description> </method> <method name="get_name"> @@ -98,12 +113,20 @@ </argument> <description> Gets the node name indicated by [code]idx[/code] (0 to [method get_name_count]). - [codeblock] + [codeblocks] + [gdscript] var node_path = NodePath("Path2D/PathFollow2D/Sprite2D") print(node_path.get_name(0)) # Path2D print(node_path.get_name(1)) # PathFollow2D print(node_path.get_name(2)) # Sprite - [/codeblock] + [/gdscript] + [csharp] + var nodePath = new NodePath("Path2D/PathFollow2D/Sprite2D"); + GD.Print(nodePath.GetName(0)); // Path2D + GD.Print(nodePath.GetName(1)); // PathFollow2D + GD.Print(nodePath.GetName(2)); // Sprite + [/csharp] + [/codeblocks] </description> </method> <method name="get_name_count"> @@ -121,11 +144,18 @@ </argument> <description> Gets the resource or property name indicated by [code]idx[/code] (0 to [method get_subname_count]). - [codeblock] + [codeblocks] + [gdscript] var node_path = NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path") print(node_path.get_subname(0)) # texture print(node_path.get_subname(1)) # load_path - [/codeblock] + [/gdscript] + [csharp] + var nodePath = new NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path"); + GD.Print(nodePath.GetSubname(0)); // texture + GD.Print(nodePath.GetSubname(1)); // load_path + [/csharp] + [/codeblocks] </description> </method> <method name="get_subname_count"> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 1487c9e078..1d80695798 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -85,18 +85,36 @@ If [code]blocking[/code] is [code]false[/code], the Godot thread will continue while the new process runs. It is not possible to retrieve the shell output in non-blocking mode, so [code]output[/code] will be empty. The return value also depends on the blocking mode. When blocking, the method will return an exit code of the process. When non-blocking, the method returns a process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process forking (non-blocking) or opening (blocking) fails, the method will return [code]-1[/code] or another exit code. Example of blocking mode and retrieving the shell output: - [codeblock] + [codeblocks] + [gdscript] var output = [] var exit_code = OS.execute("ls", ["-l", "/tmp"], true, output) - [/codeblock] + [/gdscript] + [csharp] + var output = new Godot.Collections.Array(); + int exitCode = OS.Execute("ls", new string[] {"-l", "/tmp"}, true, output); + [/csharp] + [/codeblocks] Example of non-blocking mode, running another instance of the project and storing its process ID: - [codeblock] + [codeblocks] + [gdscript] var pid = OS.execute(OS.get_executable_path(), [], false) - [/codeblock] + [/gdscript] + [csharp] + var pid = OS.Execute(OS.GetExecutablePath(), new string[] {}, false); + [/csharp] + [/codeblocks] If you wish to access a shell built-in or perform a composite command, a platform-specific shell can be invoked. For example: - [codeblock] + [codeblocks] + [gdscript] + var output = [] OS.execute("CMD.exe", ["/C", "cd %TEMP% && dir"], true, output) - [/codeblock] + [/gdscript] + [csharp] + var output = new Godot.Collections.Array(); + OS.Execute("CMD.exe", new string[] {"/C", "cd %TEMP% && dir"}, true, output); + [/csharp] + [/codeblocks] [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. </description> </method> @@ -118,13 +136,26 @@ You can also incorporate environment variables using the [method get_environment] method. You can set [code]editor/main_run_args[/code] in the Project Settings to define command-line arguments to be passed by the editor when running the project. Here's a minimal example on how to parse command-line arguments into a dictionary using the [code]--key=value[/code] form for arguments: - [codeblock] + [codeblocks] + [gdscript] var arguments = {} for argument in OS.get_cmdline_args(): if argument.find("=") > -1: var key_value = argument.split("=") arguments[key_value[0].lstrip("--")] = key_value[1] - [/codeblock] + [/gdscript] + [csharp] + var arguments = new Godot.Collections.Dictionary(); + foreach (var argument in OS.GetCmdlineArgs()) + { + if (argument.Find("=") > -1) + { + string[] keyValue = argument.Split("="); + arguments[keyValue[0].LStrip("--")] = keyValue[1]; + } + } + [/csharp] + [/codeblocks] </description> </method> <method name="get_connected_midi_inputs"> diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml index 6b500d5ac3..e3c78e08f1 100644 --- a/doc/classes/PCKPacker.xml +++ b/doc/classes/PCKPacker.xml @@ -5,12 +5,20 @@ </brief_description> <description> The [PCKPacker] is used to create packages that can be loaded into a running project using [method ProjectSettings.load_resource_pack]. - [codeblock] + [codeblocks] + [gdscript] var packer = PCKPacker.new() packer.pck_start("test.pck") packer.add_file("res://text.txt", "text.txt") packer.flush() - [/codeblock] + [/gdscript] + [csharp] + var packer = new PCKPacker(); + packer.PckStart("test.pck"); + packer.AddFile("res://text.txt", "text.txt"); + packer.Flush(); + [/csharp] + [/codeblocks] The above [PCKPacker] creates package [code]test.pck[/code], then adds a file named [code]text.txt[/code] at the root of the package. </description> <tutorials> diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml index 4a6893879d..91d066260b 100644 --- a/doc/classes/PackedByteArray.xml +++ b/doc/classes/PackedByteArray.xml @@ -135,10 +135,16 @@ </return> <description> Returns a hexadecimal representation of this array as a [String]. - [codeblock] + [codeblocks] + [gdscript] var array = PackedByteArray([11, 46, 255]) print(array.hex_encode()) # Prints: 0b2eff - [/codeblock] + [/gdscript] + [csharp] + var array = new byte[] {11, 46, 255}; + GD.Print(array.HexEncode()); // Prints: 0b2eff + [/csharp] + [/codeblocks] </description> </method> <method name="insert"> diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml index be40ab05de..d15bcfd114 100644 --- a/doc/classes/PackedScene.xml +++ b/doc/classes/PackedScene.xml @@ -8,14 +8,23 @@ Can be used to save a node to a file. When saving, the node as well as all the node it owns get saved (see [code]owner[/code] property on [Node]). [b]Note:[/b] The node doesn't need to own itself. [b]Example of loading a saved scene:[/b] - [codeblock] - # Use `load()` instead of `preload()` if the path isn't known at compile-time. + [codeblocks] + [gdscript] + # Use load() instead of preload() if the path isn't known at compile-time. var scene = preload("res://scene.tscn").instance() # Add the node as a child of the node the script is attached to. add_child(scene) - [/codeblock] + [/gdscript] + [csharp] + // C# has no preload, so you have to always use ResourceLoader.Load<PackedScene>(). + var scene = ResourceLoader.Load<PackedScene>("res://scene.tscn").Instance(); + // Add the node as a child of the node the script is attached to. + AddChild(scene); + [/csharp] + [/codeblocks] [b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [code]Node2D[/code] ([code]node[/code]), [code]RigidBody2D[/code] ([code]rigid[/code]) and [code]CollisionObject2D[/code] ([code]collision[/code]). [code]collision[/code] is a child of [code]rigid[/code] which is a child of [code]node[/code]. Only [code]rigid[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code]. - [codeblock] + [codeblocks] + [gdscript] # Create the objects. var node = Node2D.new() var rigid = RigidBody2D.new() @@ -27,15 +36,41 @@ # Change owner of `rigid`, but not of `collision`. rigid.owner = node - var scene = PackedScene.new() + # Only `node` and `rigid` are now packed. var result = scene.pack(node) if result == OK: - var error = ResourceSaver.save("res://path/name.scn", scene) # Or "user://..." + var error = ResourceSaver.save("res://path/name.tscn", scene) # Or "user://..." if error != OK: push_error("An error occurred while saving the scene to disk.") - [/codeblock] + [/gdscript] + [csharp] + // Create the objects. + var node = new Node2D(); + var rigid = new RigidBody2D(); + var collision = new CollisionShape2D(); + + // Create the object hierarchy. + rigid.AddChild(collision); + node.AddChild(rigid); + + // Change owner of `rigid`, but not of `collision`. + rigid.Owner = node; + var scene = new PackedScene(); + + // Only `node` and `rigid` are now packed. + Error result = scene.Pack(node); + if (result == Error.Ok) + { + Error error = ResourceSaver.Save("res://path/name.tscn", scene); // Or "user://..." + if (error != Error.Ok) + { + GD.PushError("An error occurred while saving the scene to disk."); + } + } + [/csharp] + [/codeblocks] </description> <tutorials> <link title="2D Role Playing Game Demo">https://godotengine.org/asset-library/asset/520</link> diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml index cab821b4c0..d7cf6cc8c6 100644 --- a/doc/classes/PacketPeerUDP.xml +++ b/doc/classes/PacketPeerUDP.xml @@ -124,17 +124,36 @@ <description> Waits for a packet to arrive on the listening port. See [method listen]. [b]Note:[/b] [method wait] can't be interrupted once it has been called. This can be worked around by allowing the other party to send a specific "death pill" packet like this: - [codeblock] - # Server - socket.set_dest_address("127.0.0.1", 789) - socket.put_packet("Time to stop".to_ascii()) + [codeblocks] + [gdscript] + socket = PacketPeerUDP.new() + # Server + socket.set_dest_address("127.0.0.1", 789) + socket.put_packet("Time to stop".to_ascii()) - # Client - while socket.wait() == OK: - var data = socket.get_packet().get_string_from_ascii() - if data == "Time to stop": - return - [/codeblock] + # Client + while socket.wait() == OK: + var data = socket.get_packet().get_string_from_ascii() + if data == "Time to stop": + return + [/gdscript] + [csharp] + var socket = new PacketPeerUDP(); + // Server + socket.SetDestAddress("127.0.0.1", 789); + socket.PutPacket("Time To Stop".ToAscii()); + + // Client + while (socket.Wait() == OK) + { + string data = socket.GetPacket().GetStringFromASCII(); + if (data == "Time to stop") + { + return; + } + } + [/csharp] + [/codeblocks] </description> </method> </methods> diff --git a/doc/classes/Performance.xml b/doc/classes/Performance.xml index 0a9079ce71..9e9c5063ae 100644 --- a/doc/classes/Performance.xml +++ b/doc/classes/Performance.xml @@ -24,14 +24,53 @@ </argument> <description> Adds a custom monitor with name same as id. You can specify the category of monitor using '/' in id. If there are more than one '/' then default category is used. Default category is "Custom". - [codeblock] - Performance.add_custom_monitor("MyCategory/MyMonitor", some_callable) # Adds monitor with name "MyName" to category "MyCategory" - Performance.add_custom_monitor("MyMonitor", some_callable) # Adds monitor with name "MyName" to category "Custom" - # Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different ids so above code is valid - Performance.add_custom_monitor("Custom/MyMonitor", some_callable) # Adds monitor with name "MyName" to category "Custom" - # Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different ids so above code is valid - Performance.add_custom_monitor("MyCategoryOne/MyCategoryTwo/MyMonitor", some_callable) # Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom" - [/codeblock] + [codeblocks] + [gdscript] + func _ready(): + var monitor_value = Callable(self, "get_monitor_value") + + # Adds monitor with name "MyName" to category "MyCategory". + Performance.add_custom_monitor("MyCategory/MyMonitor", monitor_value) + + # Adds monitor with name "MyName" to category "Custom". + # Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different ids so the code is valid. + Performance.add_custom_monitor("MyMonitor", monitor_value) + + # Adds monitor with name "MyName" to category "Custom". + # Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different ids so the code is valid. + Performance.add_custom_monitor("Custom/MyMonitor", monitor_value) + + # Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom". + Performance.add_custom_monitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitor_value) + + func get_monitor_value(): + return randi() % 25 + [/gdscript] + [csharp] + public override void _Ready() + { + var monitorValue = new Callable(this, nameof(GetMonitorValue)); + + // Adds monitor with name "MyName" to category "MyCategory". + Performance.AddCustomMonitor("MyCategory/MyMonitor", monitorValue); + // Adds monitor with name "MyName" to category "Custom". + // Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different ids so the code is valid. + Performance.AddCustomMonitor("MyMonitor", monitorValue); + + // Adds monitor with name "MyName" to category "Custom". + // Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different ids so the code is valid. + Performance.AddCustomMonitor("Custom/MyMonitor", monitorValue); + + // Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom". + Performance.AddCustomMonitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitorValue); + } + + public int GetMonitorValue() + { + return GD.Randi() % 25; + } + [/csharp] + [/codeblocks] The debugger calls the callable to get the value of custom monitor. The callable must return a number. Callables are called with arguments supplied in argument array. [b]Note:[/b] It throws an error if given id is already present. @@ -61,9 +100,14 @@ </argument> <description> Returns the value of one of the available monitors. You should provide one of the [enum Monitor] constants as the argument, like this: - [codeblock] - print(Performance.get_monitor(Performance.TIME_FPS)) # Prints the FPS to the console - [/codeblock] + [codeblocks] + [gdscript] + print(Performance.get_monitor(Performance.TIME_FPS)) # Prints the FPS to the console. + [/gdscript] + [csharp] + GD.Print(Performance.GetMonitor(Performance.Monitor.TimeFps)); // Prints the FPS to the console. + [/csharp] + [/codeblocks] </description> </method> <method name="get_monitor_modification_time"> diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml index 93ca684b95..4d7fc61517 100644 --- a/doc/classes/PhysicsShapeQueryParameters2D.xml +++ b/doc/classes/PhysicsShapeQueryParameters2D.xml @@ -34,19 +34,34 @@ </member> <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid"> The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API: - [codeblock] - var shape_rid = PhysicsServer2D.circle_shape_create() - var radius = 64 - PhysicsServer2D.shape_set_data(shape_rid, radius) + [codeblocks] + [gdscript] + var shape_rid = PhysicsServer2D.circle_shape_create() + var radius = 64 + PhysicsServer2D.shape_set_data(shape_rid, radius) - var params = PhysicsShapeQueryParameters2D.new() - params.shape_rid = shape_rid + var params = PhysicsShapeQueryParameters2D.new() + params.shape_rid = shape_rid - # Execute physics queries here... + # Execute physics queries here... - # Release the shape when done with physics queries. - PhysicsServer2D.free_rid(shape_rid) - [/codeblock] + # Release the shape when done with physics queries. + PhysicsServer2D.free_rid(shape_rid) + [/gdscript] + [csharp] + RID shapeRid = PhysicsServer2D.CircleShapeCreate(); + int radius = 64; + PhysicsServer2D.ShapeSetData(shapeRid, radius); + + var params = new PhysicsShapeQueryParameters2D(); + params.ShapeRid = shapeRid; + + // Execute physics queries here... + + // Release the shape when done with physics queries. + PhysicsServer2D.FreeRid(shapeRid); + [/csharp] + [/codeblocks] </member> <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, 1, 0, 0 )"> The queried shape's transform matrix. diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml index 167fb31bb3..4b43ea66fc 100644 --- a/doc/classes/PhysicsShapeQueryParameters3D.xml +++ b/doc/classes/PhysicsShapeQueryParameters3D.xml @@ -31,19 +31,34 @@ </member> <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid"> The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API: - [codeblock] - var shape_rid = PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_SPHERE) - var radius = 2.0 - PhysicsServer3D.shape_set_data(shape_rid, radius) + [codeblocks] + [gdscript] + var shape_rid = PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_SPHERE) + var radius = 2.0 + PhysicsServer3D.shape_set_data(shape_rid, radius) - var params = PhysicsShapeQueryParameters3D.new() - params.shape_rid = shape_rid + var params = PhysicsShapeQueryParameters3D.new() + params.shape_rid = shape_rid - # Execute physics queries here... + # Execute physics queries here... - # Release the shape when done with physics queries. - PhysicsServer3D.free_rid(shape_rid) - [/codeblock] + # Release the shape when done with physics queries. + PhysicsServer3D.free_rid(shape_rid) + [/gdscript] + [csharp] + RID shapeRid = PhysicsServer3D.ShapeCreate(PhysicsServer3D.ShapeType.Sphere); + float radius = 2.0f; + PhysicsServer3D.ShapeSetData(shapeRid, radius); + + var params = new PhysicsShapeQueryParameters3D(); + params.ShapeRid = shapeRid; + + // Execute physics queries here... + + // Release the shape when done with physics queries. + PhysicsServer3D.FreeRid(shapeRid); + [/csharp] + [/codeblocks] </member> <member name="transform" type="Transform" setter="set_transform" getter="get_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> The queried shape's transform matrix. diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml index 9e7f26ed4f..7e9bccc1d7 100644 --- a/doc/classes/PrimitiveMesh.xml +++ b/doc/classes/PrimitiveMesh.xml @@ -14,11 +14,18 @@ </return> <description> Returns mesh arrays used to constitute surface of [Mesh]. The result can be passed to [method ArrayMesh.add_surface_from_arrays] to create a new surface. For example: - [codeblock] - var c := CylinderMesh.new() - var arr_mesh := ArrayMesh.new() + [codeblocks] + [gdscript] + var c = CylinderMesh.new() + var arr_mesh = ArrayMesh.new() arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, c.get_mesh_arrays()) - [/codeblock] + [/gdscript] + [csharp] + var c = new CylinderMesh(); + var arrMesh = new ArrayMesh(); + arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, c.GetMeshArrays()); + [/csharp] + [/codeblocks] </description> </method> </methods> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 7ca2dae4d7..298f70543e 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -25,7 +25,8 @@ - [code]type[/code]: [int] (see [enum Variant.Type]) - optionally [code]hint[/code]: [int] (see [enum PropertyHint]) and [code]hint_string[/code]: [String] [b]Example:[/b] - [codeblock] + [codeblocks] + [gdscript] ProjectSettings.set("category/property_name", 0) var property_info = { @@ -36,7 +37,21 @@ } ProjectSettings.add_property_info(property_info) - [/codeblock] + [/gdscript] + [csharp] + ProjectSettings.Singleton.Set("category/property_name", 0); + + var propertyInfo = new Godot.Collections.Dictionary + { + {"name", "category/propertyName"}, + {"type", Variant.Type.Int}, + {"hint", PropertyHint.Enum}, + {"hint_string", "one,two,three"}, + }; + + ProjectSettings.AddPropertyInfo(propertyInfo); + [/csharp] + [/codeblocks] </description> </method> <method name="clear"> @@ -65,9 +80,14 @@ <description> Returns the value of a setting. [b]Example:[/b] - [codeblock] + [codeblocks] + [gdscript] print(ProjectSettings.get_setting("application/config/name")) - [/codeblock] + [/gdscript] + [csharp] + GD.Print(ProjectSettings.GetSetting("application/config/name")); + [/csharp] + [/codeblocks] </description> </method> <method name="globalize_path" qualifiers="const"> @@ -178,9 +198,14 @@ <description> Sets the value of a setting. [b]Example:[/b] - [codeblock] + [codeblocks] + [gdscript] ProjectSettings.set_setting("application/config/name", "Example") - [/codeblock] + [/gdscript] + [csharp] + ProjectSettings.SetSetting("application/config/name", "Example"); + [/csharp] + [/codeblocks] </description> </method> </methods> @@ -895,18 +920,30 @@ <member name="physics/2d/default_gravity" type="int" setter="" getter="" default="98"> The default gravity strength in 2D. [b]Note:[/b] This property is only read when the project starts. To change the default gravity at runtime, use the following code sample: - [codeblock] + [codeblocks] + [gdscript] # Set the default gravity strength to 98. - PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), PhysicsServer2D.AREA_PARAM_GRAVITY, 98) - [/codeblock] + PhysicsServer2D.area_set_param(get_viewport().find_world_2d().space, PhysicsServer2D.AREA_PARAM_GRAVITY, 98) + [/gdscript] + [csharp] + // Set the default gravity strength to 98. + PhysicsServer2D.AreaSetParam(GetViewport().FindWorld2d().Space, PhysicsServer2D.AreaParameter.Gravity, 98); + [/csharp] + [/codeblocks] </member> <member name="physics/2d/default_gravity_vector" type="Vector2" setter="" getter="" default="Vector2( 0, 1 )"> The default gravity direction in 2D. [b]Note:[/b] This property is only read when the project starts. To change the default gravity vector at runtime, use the following code sample: - [codeblock] + [codeblocks] + [gdscript] # Set the default gravity direction to `Vector2(0, 1)`. - PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), PhysicsServer2D.AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1)) - [/codeblock] + PhysicsServer2D.area_set_param(get_viewport().find_world_2d().space, PhysicsServer2D.AREA_PARAM_GRAVITY_VECTOR, Vector2.DOWN) + [/gdscript] + [csharp] + // Set the default gravity direction to `Vector2(0, 1)`. + PhysicsServer2D.AreaSetParam(GetViewport().FindWorld2d().Space, PhysicsServer2D.AreaParameter.GravityVector, Vector2.Down) + [/csharp] + [/codeblocks] </member> <member name="physics/2d/default_linear_damp" type="float" setter="" getter="" default="0.1"> The default linear damp in 2D. @@ -942,18 +979,30 @@ <member name="physics/3d/default_gravity" type="float" setter="" getter="" default="9.8"> The default gravity strength in 3D. [b]Note:[/b] This property is only read when the project starts. To change the default gravity at runtime, use the following code sample: - [codeblock] + [codeblocks] + [gdscript] # Set the default gravity strength to 9.8. - PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), PhysicsServer3D.AREA_PARAM_GRAVITY, 9.8) - [/codeblock] + PhysicsServer3D.area_set_param(get_viewport().find_world().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 9.8) + [/gdscript] + [csharp] + // Set the default gravity strength to 9.8. + PhysicsServer3D.AreaSetParam(GetViewport().FindWorld().Space, PhysicsServer3D.AreaParameter.Gravity, 9.8); + [/csharp] + [/codeblocks] </member> <member name="physics/3d/default_gravity_vector" type="Vector3" setter="" getter="" default="Vector3( 0, -1, 0 )"> The default gravity direction in 3D. [b]Note:[/b] This property is only read when the project starts. To change the default gravity vector at runtime, use the following code sample: - [codeblock] + [codeblocks] + [gdscript] # Set the default gravity direction to `Vector3(0, -1, 0)`. - PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, Vector3(0, -1, 0)) - [/codeblock] + PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, Vector3.DOWN) + [/gdscript] + [csharp] + // Set the default gravity direction to `Vector3(0, -1, 0)`. + PhysicsServer3D.AreaSetParam(GetViewport().FindWorld().Space, PhysicsServer3D.AreaParameter.GravityVector, Vector3.Down) + [/csharp] + [/codeblocks] </member> <member name="physics/3d/default_linear_damp" type="float" setter="" getter="" default="0.1"> The default linear damp in 3D. diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 53d706db2d..168cc8a1c3 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -270,7 +270,7 @@ <return type="String"> </return> <description> - Returns a [String] text with the word under the mouse cursor location. + Returns a [String] text with the word under the caret (text cursor) location. </description> </method> <method name="insert_text_at_cursor"> diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index ebfd3e0454..28634d5e70 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -707,7 +707,8 @@ Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfa // We use a single GPU, but we need a surface to initialize the // queues, so this process must be deferred until a surface // is created. - _initialize_queues(p_surface); + Error err = _initialize_queues(p_surface); + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); } Window window; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 236d1e884e..3182bca0eb 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1138,6 +1138,7 @@ void CodeTextEditor::move_lines_up() { int from_col = text_editor->get_selection_from_column(); int to_line = text_editor->get_selection_to_line(); int to_column = text_editor->get_selection_to_column(); + int cursor_line = text_editor->cursor_get_line(); for (int i = from_line; i <= to_line; i++) { int line_id = i; @@ -1155,7 +1156,9 @@ void CodeTextEditor::move_lines_up() { } int from_line_up = from_line > 0 ? from_line - 1 : from_line; int to_line_up = to_line > 0 ? to_line - 1 : to_line; + int cursor_line_up = cursor_line > 0 ? cursor_line - 1 : cursor_line; text_editor->select(from_line_up, from_col, to_line_up, to_column); + text_editor->cursor_set_line(cursor_line_up); } else { int line_id = text_editor->cursor_get_line(); int next_id = line_id - 1; @@ -1181,6 +1184,7 @@ void CodeTextEditor::move_lines_down() { int from_col = text_editor->get_selection_from_column(); int to_line = text_editor->get_selection_to_line(); int to_column = text_editor->get_selection_to_column(); + int cursor_line = text_editor->cursor_get_line(); for (int i = to_line; i >= from_line; i--) { int line_id = i; @@ -1198,7 +1202,9 @@ void CodeTextEditor::move_lines_down() { } int from_line_down = from_line < text_editor->get_line_count() ? from_line + 1 : from_line; int to_line_down = to_line < text_editor->get_line_count() ? to_line + 1 : to_line; + int cursor_line_down = cursor_line < text_editor->get_line_count() ? cursor_line + 1 : cursor_line; text_editor->select(from_line_down, from_col, to_line_down, to_column); + text_editor->cursor_set_line(cursor_line_down); } else { int line_id = text_editor->cursor_get_line(); int next_id = line_id + 1; diff --git a/editor/doc_data.cpp b/editor/doc_data.cpp index 78c601d4bc..8504d61d2f 100644 --- a/editor/doc_data.cpp +++ b/editor/doc_data.cpp @@ -737,16 +737,16 @@ void DocData::generate(bool p_basic_types) { c.properties.push_back(pd); } - List<StringName> builtin_funcs; - Variant::get_builtin_function_list(&builtin_funcs); - builtin_funcs.sort_custom<StringName::AlphCompare>(); - for (List<StringName>::Element *E = builtin_funcs.front(); E; E = E->next()) { + List<StringName> utility_functions; + Variant::get_utility_function_list(&utility_functions); + utility_functions.sort_custom<StringName::AlphCompare>(); + for (List<StringName>::Element *E = utility_functions.front(); E; E = E->next()) { MethodDoc md; md.name = E->get(); //return - if (Variant::has_builtin_func_return_value(E->get())) { + if (Variant::has_utility_function_return_value(E->get())) { PropertyInfo pi; - pi.type = Variant::get_builtin_func_return_type(E->get()); + pi.type = Variant::get_utility_function_return_type(E->get()); if (pi.type == Variant::NIL) { pi.usage = PROPERTY_USAGE_NIL_IS_VARIANT; } @@ -755,13 +755,13 @@ void DocData::generate(bool p_basic_types) { md.return_type = ad.type; } - if (Variant::is_builtin_func_vararg(E->get())) { + if (Variant::is_utility_function_vararg(E->get())) { md.qualifiers = "vararg"; } else { - for (int i = 0; i < Variant::get_builtin_func_argument_count(E->get()); i++) { + for (int i = 0; i < Variant::get_utility_function_argument_count(E->get()); i++) { PropertyInfo pi; - pi.type = Variant::get_builtin_func_argument_type(E->get(), i); - pi.name = Variant::get_builtin_func_argument_name(E->get(), i); + pi.type = Variant::get_utility_function_argument_type(E->get(), i); + pi.name = Variant::get_utility_function_argument_name(E->get(), i); if (pi.type == Variant::NIL) { pi.usage = PROPERTY_USAGE_NIL_IS_VARIANT; } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d0d99e071a..c6613cdf63 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2705,10 +2705,14 @@ void EditorNode::_screenshot(bool p_use_utc) { } void EditorNode::_save_screenshot(NodePath p_path) { - SubViewport *viewport = Object::cast_to<SubViewport>(EditorInterface::get_singleton()->get_editor_viewport()->get_viewport()); - viewport->set_clear_mode(SubViewport::CLEAR_MODE_ONLY_NEXT_FRAME); - Ref<Image> img = viewport->get_texture()->get_data(); - viewport->set_clear_mode(SubViewport::CLEAR_MODE_ALWAYS); + Control *editor_viewport = EditorInterface::get_singleton()->get_editor_viewport(); + ERR_FAIL_COND_MSG(!editor_viewport, "Cannot get editor viewport."); + Viewport *viewport = editor_viewport->get_viewport(); + ERR_FAIL_COND_MSG(!viewport, "Cannot get editor viewport."); + Ref<ViewportTexture> texture = viewport->get_texture(); + ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor viewport texture."); + Ref<Image> img = texture->get_data(); + ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor viewport texture image."); Error error = img->save_png(p_path); ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'."); } diff --git a/editor/icons/CanvasGroup.svg b/editor/icons/CanvasGroup.svg new file mode 100644 index 0000000000..232ae53231 --- /dev/null +++ b/editor/icons/CanvasGroup.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v6h-6v8h8v-6h6v-8zm2 2h4v4h-4z" fill="#a5b8f3" fill-opacity=".588235"/><path d="m1 1v2c0 .0000234.446 0 1 0s1 .0000234 1 0v-2c0-.00002341-.446 0-1 0s-1-.00002341-1 0zm12 0v2c0 .0000234.446 0 1 0s1 .0000234 1 0v-2c0-.00002341-.446 0-1 0s-1-.00002341-1 0zm-12 12v2c0 .000023.446 0 1 0s1 .000023 1 0v-2c0-.000023-.446 0-1 0s-1-.000023-1 0zm12 0v2c0 .000023.446 0 1 0s1 .000023 1 0v-2c0-.000023-.446 0-1 0s-1-.000023-1 0z" fill="#a5b7f4"/></svg> diff --git a/editor/icons/CodeEdit.svg b/editor/icons/CodeEdit.svg new file mode 100644 index 0000000000..0750b072e7 --- /dev/null +++ b/editor/icons/CodeEdit.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m29 1042.4h1v1h-1z" fill="#fefeff"/><path d="m3 1c-1.1046 0-2 .8954-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm2 1-1 1 1 1-1 1 1 1 2-2zm2 3v1h2v-1z" fill="#a5efac" transform="translate(0 1036.4)"/></g></svg> diff --git a/editor/icons/EditorCurveHandle.svg b/editor/icons/EditorCurveHandle.svg index ea69f4e4cc..e0f3256807 100644 --- a/editor/icons/EditorCurveHandle.svg +++ b/editor/icons/EditorCurveHandle.svg @@ -1 +1 @@ -<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill="#fefefe" r="2.75" stroke="#000" stroke-linecap="square"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fefefe" r="4.4" stroke="#000" stroke-linecap="square" stroke-width="1.6"/></svg> diff --git a/editor/icons/EditorPathSharpHandle.svg b/editor/icons/EditorPathSharpHandle.svg index 328dc04677..5166930cca 100644 --- a/editor/icons/EditorPathSharpHandle.svg +++ b/editor/icons/EditorPathSharpHandle.svg @@ -1 +1 @@ -<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m-3.035534-10.106602h6.071068v6.071068h-6.071068z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="matrix(-.70710678 .70710678 -.70710678 -.70710678 0 0)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14.868629 8.0000002-6.8686288 6.8686288-6.8686293-6.8686288 6.8686293-6.8686293z" fill="#fefefe" stroke="#000" stroke-linecap="square" stroke-width="1.6"/></svg> diff --git a/editor/icons/EditorPathSmoothHandle.svg b/editor/icons/EditorPathSmoothHandle.svg index b498345d5a..2ab4f3a96a 100644 --- a/editor/icons/EditorPathSmoothHandle.svg +++ b/editor/icons/EditorPathSmoothHandle.svg @@ -1 +1 @@ -<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m1.5-8.5h7v7h-7z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="rotate(90)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.6 2.4v11.2h-11.2v-11.2z" fill="#fefefe" stroke="#000" stroke-linecap="square" stroke-width="1.6"/></svg> diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index fdbf3415db..28acb26012 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -6753,12 +6753,12 @@ void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const R materials[p_name] = icons; } -void EditorNode3DGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) { +void EditorNode3DGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard, const Ref<Texture2D> &p_icon) { Ref<StandardMaterial3D> handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true); - Ref<Texture2D> handle_t = Node3DEditor::get_singleton()->get_theme_icon("Editor3DHandle", "EditorIcons"); + Ref<Texture2D> handle_t = p_icon != nullptr ? p_icon : Node3DEditor::get_singleton()->get_theme_icon("Editor3DHandle", "EditorIcons"); handle_material->set_point_size(handle_t->get_width()); handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle_t); handle_material->set_albedo(Color(1, 1, 1)); @@ -6842,7 +6842,7 @@ void EditorNode3DGizmoPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorNode3DGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorNode3DGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1))); - ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard"), &EditorNode3DGizmoPlugin::create_handle_material, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard", "texture"), &EditorNode3DGizmoPlugin::create_handle_material, DEFVAL(false), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("add_material", "name", "material"), &EditorNode3DGizmoPlugin::add_material); ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorNode3DGizmoPlugin::get_material); //, DEFVAL(Ref<EditorNode3DGizmo>())); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 4c4faef07f..07f6d69d76 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -866,7 +866,7 @@ protected: public: void create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false); void create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1)); - void create_handle_material(const String &p_name, bool p_billboard = false); + void create_handle_material(const String &p_name, bool p_billboard = false, const Ref<Texture2D> &p_texture = nullptr); void add_material(const String &p_name, Ref<StandardMaterial3D> p_material); Ref<StandardMaterial3D> get_material(const String &p_name, const Ref<EditorNode3DGizmo> &p_gizmo = Ref<EditorNode3DGizmo>()); diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index f53130c24d..280f6fafd8 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -224,6 +224,7 @@ void Path3DGizmo::redraw() { Ref<StandardMaterial3D> path_material = gizmo_plugin->get_material("path_material", this); Ref<StandardMaterial3D> path_thin_material = gizmo_plugin->get_material("path_thin_material", this); Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles"); + Ref<StandardMaterial3D> sec_handles_material = gizmo_plugin->get_material("sec_handles"); Ref<Curve3D> c = path->get_curve(); if (c.is_null()) { @@ -281,7 +282,7 @@ void Path3DGizmo::redraw() { add_handles(handles, handles_material); } if (sec_handles.size()) { - add_handles(sec_handles, handles_material, false, true); + add_handles(sec_handles, sec_handles_material, false, true); } } } @@ -641,5 +642,6 @@ Path3DGizmoPlugin::Path3DGizmoPlugin() { Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8)); create_material("path_material", path_color); create_material("path_thin_material", Color(0.5, 0.5, 0.5)); - create_handle_material("handles"); + create_handle_material("handles", false, Node3DEditor::get_singleton()->get_theme_icon("EditorPathSmoothHandle", "EditorIcons")); + create_handle_material("sec_handles", false, Node3DEditor::get_singleton()->get_theme_icon("EditorCurveHandle", "EditorIcons")); } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index add5047c99..038b18a648 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1270,10 +1270,6 @@ void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<Stri } void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pair<NodePath, NodePath>> *p_renames) { - if (!bool(EDITOR_DEF("editors/animation/autorename_animation_tracks", true))) { - return; - } - Vector<StringName> base_path; Node *n = p_node->get_parent(); while (n) { diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp index 8e30eaae4d..417abeaad3 100644 --- a/modules/gdnative/gdnative/variant.cpp +++ b/modules/gdnative/gdnative/variant.cpp @@ -576,7 +576,9 @@ godot_variant GDAPI godot_variant_call(godot_variant *p_self, const godot_string godot_variant raw_dest; Variant *dest = (Variant *)&raw_dest; Callable::CallError error; - memnew_placement_custom(dest, Variant, Variant(self->call(*method, args, p_argcount, error))); + Variant ret; + self->call(*method, args, p_argcount, ret, error); + memnew_placement_custom(dest, Variant, Variant(ret)); if (r_error) { r_error->error = (godot_variant_call_error_error)error.error; r_error->argument = error.argument; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index bad450c9f9..a64a05fcba 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1963,6 +1963,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar } p_script->member_indices = base->member_indices; + native = base->native; + p_script->native = native; } break; default: { _set_error("Parser bug: invalid inheritance.", p_class); diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 59f3deb736..8372672cf7 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -1048,7 +1048,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Callable::CallError err; if (call_ret) { GET_VARIANT_PTR(ret, argc); - base->call_ptr(*methodname, (const Variant **)argptrs, argc, ret, err); + base->call(*methodname, (const Variant **)argptrs, argc, *ret, err); #ifdef DEBUG_ENABLED if (!call_async && ret->get_type() == Variant::OBJECT) { // Check if getting a function state without await. @@ -1066,7 +1066,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } #endif } else { - base->call_ptr(*methodname, (const Variant **)argptrs, argc, nullptr, err); + Variant ret; + base->call(*methodname, (const Variant **)argptrs, argc, ret, err); } #ifdef DEBUG_ENABLED if (GDScriptLanguage::get_singleton()->profiling) { diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 0942552ba8..3a7c1a8676 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -285,7 +285,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ int64_t i = *p_args[0]; r_ret = i < 0 ? -1 : (i > 0 ? +1 : 0); } else if (p_args[0]->get_type() == Variant::FLOAT) { - real_t r = *p_args[0]; + double r = *p_args[0]; r_ret = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0); } else { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; @@ -510,8 +510,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - real_t a = *p_args[0]; - real_t b = *p_args[1]; + double a = *p_args[0]; + double b = *p_args[1]; r_ret = MAX(a, b); } @@ -527,8 +527,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - real_t a = *p_args[0]; - real_t b = *p_args[1]; + double a = *p_args[0]; + double b = *p_args[1]; r_ret = MIN(a, b); } @@ -545,9 +545,9 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); - real_t a = *p_args[0]; - real_t b = *p_args[1]; - real_t c = *p_args[2]; + double a = *p_args[0]; + double b = *p_args[1]; + double c = *p_args[2]; r_ret = CLAMP(a, b, c); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index d0add835c0..90141928ca 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -337,8 +337,8 @@ namespace Godot } /// <summary> - /// Returns the color's 32-bit integer in ABGR format - /// (each byte represents a component of the ABGR profile). + /// Returns the color converted to an unsigned 32-bit integer in ABGR + /// format (each byte represents a color channel). /// ABGR is the reversed version of the default format. /// </summary> /// <returns>A uint representing this color in ABGR32 format.</returns> @@ -356,8 +356,8 @@ namespace Godot } /// <summary> - /// Returns the color's 64-bit integer in ABGR format - /// (each word represents a component of the ABGR profile). + /// Returns the color converted to an unsigned 64-bit integer in ABGR + /// format (each word represents a color channel). /// ABGR is the reversed version of the default format. /// </summary> /// <returns>A ulong representing this color in ABGR64 format.</returns> @@ -375,8 +375,8 @@ namespace Godot } /// <summary> - /// Returns the color's 32-bit integer in ARGB format - /// (each byte represents a component of the ARGB profile). + /// Returns the color converted to an unsigned 32-bit integer in ARGB + /// format (each byte represents a color channel). /// ARGB is more compatible with DirectX, but not used much in Godot. /// </summary> /// <returns>A uint representing this color in ARGB32 format.</returns> @@ -394,8 +394,8 @@ namespace Godot } /// <summary> - /// Returns the color's 64-bit integer in ARGB format - /// (each word represents a component of the ARGB profile). + /// Returns the color converted to an unsigned 64-bit integer in ARGB + /// format (each word represents a color channel). /// ARGB is more compatible with DirectX, but not used much in Godot. /// </summary> /// <returns>A ulong representing this color in ARGB64 format.</returns> @@ -413,8 +413,8 @@ namespace Godot } /// <summary> - /// Returns the color's 32-bit integer in RGBA format - /// (each byte represents a component of the RGBA profile). + /// Returns the color converted to an unsigned 32-bit integer in RGBA + /// format (each byte represents a color channel). /// RGBA is Godot's default and recommended format. /// </summary> /// <returns>A uint representing this color in RGBA32 format.</returns> @@ -432,8 +432,8 @@ namespace Godot } /// <summary> - /// Returns the color's 64-bit integer in RGBA format - /// (each word represents a component of the RGBA profile). + /// Returns the color converted to an unsigned 64-bit integer in RGBA + /// format (each word represents a color channel). /// RGBA is Godot's default and recommended format. /// </summary> /// <returns>A ulong representing this color in RGBA64 format.</returns> @@ -472,7 +472,7 @@ namespace Godot } /// <summary> - /// Constructs a color from RGBA values on the range of 0 to 1. + /// Constructs a color from RGBA values, typically on the range of 0 to 1. /// </summary> /// <param name="r">The color's red component, typically on the range of 0 to 1.</param> /// <param name="g">The color's green component, typically on the range of 0 to 1.</param> @@ -500,8 +500,8 @@ namespace Godot } /// <summary> - /// Constructs a color from a 32-bit integer - /// (each byte represents a component of the RGBA profile). + /// Constructs a color from an unsigned 32-bit integer in RGBA format + /// (each byte represents a color channel). /// </summary> /// <param name="rgba">The uint representing the color.</param> public Color(uint rgba) @@ -516,8 +516,8 @@ namespace Godot } /// <summary> - /// Constructs a color from a 64-bit integer - /// (each word represents a component of the RGBA profile). + /// Constructs a color from an unsigned 64-bit integer in RGBA format + /// (each word represents a color channel). /// </summary> /// <param name="rgba">The ulong representing the color.</param> public Color(ulong rgba) @@ -777,31 +777,10 @@ namespace Godot return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1); } - private String ToHex32(float val) + private string ToHex32(float val) { - int v = Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255)); - - var ret = string.Empty; - - for (int i = 0; i < 2; i++) - { - char c; - int lv = v & 0xF; - - if (lv < 10) - { - c = (char)('0' + lv); - } - else - { - c = (char)('a' + lv - 10); - } - - v >>= 4; - ret = c + ret; - } - - return ret; + byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255)); + return b.HexEncode(); } internal static bool HtmlIsValid(string color) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 7f4777777c..6699c5992c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -39,14 +39,6 @@ namespace Godot return val * sgn; } - public static FuncRef FuncRef(Object instance, StringName funcName) - { - var ret = new FuncRef(); - ret.SetInstance(instance); - ret.SetFunction(funcName); - return ret; - } - public static int Hash(object var) { return godot_icall_GD_hash(var); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index d63db0f905..0700f197ff 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -322,6 +322,15 @@ namespace Godot return instance.IndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } + /// <summary>Find the first occurrence of a char. Optionally, the search starting position can be passed.</summary> + /// <returns>The first instance of the char, or -1 if not found.</returns> + public static int Find(this string instance, char what, int from = 0, bool caseSensitive = true) + { + // TODO: Could be more efficient if we get a char version of `IndexOf`. + // See https://github.com/dotnet/runtime/issues/44116 + return instance.IndexOf(what.ToString(), from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); + } + /// <summary>Find the last occurrence of a substring.</summary> /// <returns>The starting position of the substring, or -1 if not found.</returns> public static int FindLast(this string instance, string what, bool caseSensitive = true) @@ -437,6 +446,53 @@ namespace Godot return hashv; } + /// <summary> + /// Returns a hexadecimal representation of this byte as a string. + /// </summary> + /// <param name="bytes">The byte to encode.</param> + /// <returns>The hexadecimal representation of this byte.</returns> + internal static string HexEncode(this byte b) + { + var ret = string.Empty; + + for (int i = 0; i < 2; i++) + { + char c; + int lv = b & 0xF; + + if (lv < 10) + { + c = (char)('0' + lv); + } + else + { + c = (char)('a' + lv - 10); + } + + b >>= 4; + ret = c + ret; + } + + return ret; + } + + /// <summary> + /// Returns a hexadecimal representation of this byte array as a string. + /// </summary> + /// <param name="bytes">The byte array to encode.</param> + /// <returns>The hexadecimal representation of this byte array.</returns> + public static string HexEncode(this byte[] bytes) + { + var ret = string.Empty; + + foreach (byte b in bytes) + { + ret += b.HexEncode(); + } + + return ret; + } + // <summary> // Convert a string containing an hexadecimal number into an int. // </summary> @@ -659,6 +715,33 @@ namespace Godot } /// <summary> + /// Returns a copy of the string with characters removed from the left. + /// </summary> + /// <param name="instance">The string to remove characters from.</param> + /// <param name="chars">The characters to be removed.</param> + /// <returns>A copy of the string with characters removed from the left.</returns> + public static string LStrip(this string instance, string chars) + { + int len = instance.Length; + int beg; + + for (beg = 0; beg < len; beg++) + { + if (chars.Find(instance[beg]) == -1) + { + break; + } + } + + if (beg == 0) + { + return instance; + } + + return instance.Substr(beg, len - beg); + } + + /// <summary> /// Do a simple expression match, where '*' matches zero or more arbitrary characters and '?' matches any single character except '.'. /// </summary> private static bool ExprMatch(this string instance, string expr, bool caseSensitive) @@ -886,6 +969,33 @@ namespace Godot return instance.Substring(pos, instance.Length - pos); } + /// <summary> + /// Returns a copy of the string with characters removed from the right. + /// </summary> + /// <param name="instance">The string to remove characters from.</param> + /// <param name="chars">The characters to be removed.</param> + /// <returns>A copy of the string with characters removed from the right.</returns> + public static string RStrip(this string instance, string chars) + { + int len = instance.Length; + int end; + + for (end = len - 1; end >= 0; end--) + { + if (chars.Find(instance[end]) == -1) + { + break; + } + } + + if (end == len - 1) + { + return instance; + } + + return instance.Substr(0, end + 1); + } + public static byte[] SHA256Buffer(this string instance) { return godot_icall_String_sha256_buffer(instance); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 06bbe98497..bc0f81b2a7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -221,8 +221,7 @@ namespace Godot real_t dot = v1.Dot(v2); - // Clamp dot to [-1, 1] - dot = dot < -1.0f ? -1.0f : (dot > 1.0f ? 1.0f : dot); + dot = Mathf.Clamp(dot, -1.0f, 1.0f); Vector2 v; diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index bb015b118d..10a18dfd5e 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -1463,7 +1463,7 @@ public: argp.write[i] = &arr[i]; } - r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce); + base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); if (ce.error != Callable::CallError::CALL_OK) { r_error_str = "On call to '" + String(call->method) + "':"; diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 3b46af3cbd..34a1cfc4fc 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -42,7 +42,7 @@ ////////////////////////////////////////// int VisualScriptFunctionCall::get_output_sequence_port_count() const { - if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function))) { + if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function))) { return 0; } else { return 1; @@ -50,7 +50,7 @@ int VisualScriptFunctionCall::get_output_sequence_port_count() const { } bool VisualScriptFunctionCall::has_input_sequence_port() const { - return !((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function))); + return !((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function))); } #ifdef TOOLS_ENABLED @@ -130,7 +130,11 @@ StringName VisualScriptFunctionCall::_get_base_type() const { int VisualScriptFunctionCall::get_input_value_port_count() const { if (call_mode == CALL_MODE_BASIC_TYPE) { - Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type, function); + Vector<Variant::Type> types; + int argc = Variant::get_builtin_method_argument_count(basic_type, function); + for (int i = 0; i < argc; i++) { + types.push_back(Variant::get_builtin_method_argument_type(basic_type, function, i)); + } return types.size() + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) + 1; } else { @@ -147,8 +151,7 @@ int VisualScriptFunctionCall::get_input_value_port_count() const { int VisualScriptFunctionCall::get_output_value_port_count() const { if (call_mode == CALL_MODE_BASIC_TYPE) { - bool returns = false; - Variant::get_method_return_type(basic_type, function, &returns); + bool returns = Variant::has_builtin_method_return_value(basic_type, function); return returns ? 1 : 0; } else { @@ -195,10 +198,7 @@ PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) cons #ifdef DEBUG_METHODS_ENABLED if (call_mode == CALL_MODE_BASIC_TYPE) { - Vector<StringName> names = Variant::get_method_argument_names(basic_type, function); - Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type, function); - return PropertyInfo(types[p_idx], names[p_idx]); - + return PropertyInfo(Variant::get_builtin_method_argument_type(basic_type, function, p_idx), Variant::get_builtin_method_argument_name(basic_type, function, p_idx)); } else { MethodBind *mb = ClassDB::get_method(_get_base_type(), function); if (mb) { @@ -220,7 +220,7 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con #ifdef DEBUG_METHODS_ENABLED if (call_mode == CALL_MODE_BASIC_TYPE) { - return PropertyInfo(Variant::get_method_return_type(basic_type, function), ""); + return PropertyInfo(Variant::get_builtin_method_return_type(basic_type, function), ""); } else { if (call_mode == CALL_MODE_INSTANCE) { if (p_idx == 0) { @@ -419,7 +419,7 @@ void VisualScriptFunctionCall::set_function(const StringName &p_type) { function = p_type; if (call_mode == CALL_MODE_BASIC_TYPE) { - use_default_args = Variant::get_method_default_arguments(basic_type, function).size(); + use_default_args = Variant::get_builtin_method_default_arguments(basic_type, function).size(); } else { //update all caches @@ -606,7 +606,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const int mc = 0; if (call_mode == CALL_MODE_BASIC_TYPE) { - mc = Variant::get_method_default_arguments(basic_type, function).size(); + mc = Variant::get_builtin_method_default_arguments(basic_type, function).size(); } else { MethodBind *mb = ClassDB::get_method(_get_base_type(), function); if (mb) { @@ -805,19 +805,21 @@ public: } else if (returns) { if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) { if (returns >= 2) { - *p_outputs[1] = v.call(function, p_inputs + 1, input_args, r_error); + v.call(function, p_inputs + 1, input_args, *p_outputs[1], r_error); } else if (returns == 1) { - v.call(function, p_inputs + 1, input_args, r_error); + Variant ret; + v.call(function, p_inputs + 1, input_args, ret, r_error); } else { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Invalid returns count for call_mode == CALL_MODE_INSTANCE"; return 0; } } else { - *p_outputs[0] = v.call(function, p_inputs + 1, input_args, r_error); + v.call(function, p_inputs + 1, input_args, *p_outputs[0], r_error); } } else { - v.call(function, p_inputs + 1, input_args, r_error); + Variant ret; + v.call(function, p_inputs + 1, input_args, ret, r_error); } if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) { diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 5007b3f570..53b43ae0e8 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -29,7 +29,6 @@ /*************************************************************************/ #include "export.h" -#include "gradle_export_util.h" #include "core/config/project_settings.h" #include "core/io/image_loader.h" @@ -827,7 +826,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { int version_code = p_preset->get("version/code"); String package_name = p_preset->get("package/unique_name"); - int orientation = p_preset->get("screen/orientation"); + const int screen_orientation = _get_android_orientation_value(_get_screen_orientation()); bool screen_support_small = p_preset->get("screen/support_small"); bool screen_support_normal = p_preset->get("screen/support_normal"); @@ -937,7 +936,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } if (tname == "activity" && attrname == "screenOrientation") { - encode_uint32(orientation == 0 ? 0 : 1, &p_manifest.write[iofs + 16]); + encode_uint32(screen_orientation, &p_manifest.write[iofs + 16]); } if (tname == "supports-screens") { @@ -1636,7 +1635,6 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "screen/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_normal"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true)); @@ -1645,10 +1643,10 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_background_option, PROPERTY_HINT_FILE, "*.png"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false)); @@ -1968,9 +1966,21 @@ public: valid = false; } else { Error errn; + // Check for the platform-tools directory. DirAccessRef da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn); if (errn != OK) { - err += TTR("Invalid Android SDK path for custom build in Editor Settings.") + "\n"; + err += TTR("Invalid Android SDK path for custom build in Editor Settings."); + err += TTR("Missing 'platform-tools' directory!"); + err += "\n"; + valid = false; + } + + // Check for the build-tools directory. + DirAccessRef build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn); + if (errn != OK) { + err += TTR("Invalid Android SDK path for custom build in Editor Settings."); + err += TTR("Missing 'build-tools' directory!"); + err += "\n"; valid = false; } } @@ -2159,14 +2169,16 @@ public: } } - Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, String apk_path, EditorProgress ep) { + Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, String export_path, EditorProgress ep) { + int export_format = int(p_preset->get("custom_template/export_format")); + String export_label = export_format == 1 ? "AAB" : "APK"; String release_keystore = p_preset->get("keystore/release"); String release_username = p_preset->get("keystore/release_user"); String release_password = p_preset->get("keystore/release_password"); String jarsigner = EditorSettings::get_singleton()->get("export/android/jarsigner"); if (!FileAccess::exists(jarsigner)) { - EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the Editor Settings.\nThe resulting APK is unsigned."); + EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the Editor Settings.\nThe resulting " + export_label + " is unsigned."); return OK; } @@ -2184,7 +2196,7 @@ public: user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); } - if (ep.step("Signing debug APK...", 103)) { + if (ep.step("Signing debug " + export_label + "...", 103)) { return ERR_SKIP; } @@ -2193,7 +2205,7 @@ public: password = release_password; user = release_username; - if (ep.step("Signing release APK...", 103)) { + if (ep.step("Signing release " + export_label + "...", 103)) { return ERR_SKIP; } } @@ -2218,7 +2230,7 @@ public: args.push_back(keystore); args.push_back("-storepass"); args.push_back(password); - args.push_back(apk_path); + args.push_back(export_path); args.push_back(user); int retval; OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); @@ -2227,7 +2239,7 @@ public: return ERR_CANT_CREATE; } - if (ep.step("Verifying APK...", 104)) { + if (ep.step("Verifying " + export_label + "...", 104)) { return ERR_SKIP; } @@ -2235,17 +2247,78 @@ public: args.push_back("-verify"); args.push_back("-keystore"); args.push_back(keystore); - args.push_back(apk_path); + args.push_back(export_path); args.push_back("-verbose"); OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); if (retval) { - EditorNode::add_io_error("'jarsigner' verification of APK failed. Make sure to use a jarsigner from OpenJDK 8."); + EditorNode::add_io_error("'jarsigner' verification of " + export_label + " failed. Make sure to use a jarsigner from OpenJDK 8."); return ERR_CANT_CREATE; } return OK; } + void _clear_assets_directory() { + DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da_res->dir_exists("res://android/build/assets")) { + DirAccessRef da_assets = DirAccess::open("res://android/build/assets"); + da_assets->erase_contents_recursive(); + da_res->remove("res://android/build/assets"); + } + } + + Error _zip_align_project(const String &sdk_path, const String &unaligned_file_path, const String &aligned_file_path) { + // Look for the zipalign tool. + String zipalign_command; + Error errn; + String build_tools_dir = sdk_path.plus_file("build-tools"); + DirAccessRef da = DirAccess::open(build_tools_dir, &errn); + if (errn != OK) { + return errn; + } + + // There are additional versions directories we need to go through. + da->list_dir_begin(); + String sub_dir = da->get_next(); + while (!sub_dir.empty()) { + if (!sub_dir.begins_with(".") && da->current_is_dir()) { + // Check if the tool is here. + String tool_path = build_tools_dir.plus_file(sub_dir).plus_file("zipalign"); + if (FileAccess::exists(tool_path)) { + zipalign_command = tool_path; + break; + } + } + sub_dir = da->get_next(); + } + da->list_dir_end(); + + if (zipalign_command.empty()) { + EditorNode::get_singleton()->show_warning(TTR("Unable to find the zipalign tool.")); + return ERR_CANT_CREATE; + } + + List<String> zipalign_args; + zipalign_args.push_back("-f"); + zipalign_args.push_back("-v"); + zipalign_args.push_back("4"); + zipalign_args.push_back(unaligned_file_path); // source file + zipalign_args.push_back(aligned_file_path); // destination file + + int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Aligning APK..."), zipalign_command, zipalign_args); + if (result != 0) { + EditorNode::get_singleton()->show_warning(TTR("Unable to complete APK alignment.")); + return ERR_CANT_CREATE; + } + + // Delete the unaligned path. + errn = da->remove(unaligned_file_path); + if (errn != OK) { + EditorNode::get_singleton()->show_warning(TTR("Unable to delete unaligned APK.")); + } + return OK; + } + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); @@ -2325,13 +2398,8 @@ public: _write_tmp_manifest(p_preset, p_give_internet, p_debug); //stores all the project files inside the Gradle project directory. Also includes all ABIs + _clear_assets_directory(); if (!apk_expansion) { - DirAccess *da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (da_res->dir_exists("res://android/build/assets")) { - DirAccess *da_assets = DirAccess::open("res://android/build/assets"); - da_assets->erase_contents_recursive(); - da_res->remove("res://android/build/assets"); - } err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, NULL, ignore_so_file); if (err != OK) { EditorNode::add_io_error("Could not export project files to gradle project\n"); @@ -2419,7 +2487,16 @@ public: copy_args.push_back(build_path); // start directory. String export_filename = p_path.get_file(); + if (export_format == 0) { + // By default, generated apk are not aligned. + export_filename += ".unaligned"; + } String export_path = p_path.get_base_dir(); + if (export_path.is_rel_path()) { + export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path); + } + export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path(); + String export_file_path = export_path.plus_file(export_filename); copy_args.push_back("-Pexport_path=file:" + export_path); copy_args.push_back("-Pexport_filename=" + export_filename); @@ -2430,11 +2507,20 @@ public: return ERR_CANT_CREATE; } if (_signed) { - err = sign_apk(p_preset, p_debug, p_path, ep); + err = sign_apk(p_preset, p_debug, export_file_path, ep); + if (err != OK) { + return err; + } + } + + if (export_format == 0) { + // Perform zip alignment + err = _zip_align_project(sdk_path, export_file_path, export_path.plus_file(p_path.get_file())); if (err != OK) { return err; } } + return OK; } // This is the start of the Legacy build system @@ -2781,7 +2867,7 @@ void register_android_exporter() { EDITOR_DEF("export/android/jarsigner", ""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/jarsigner", PROPERTY_HINT_GLOBAL_FILE, exe_ext)); EDITOR_DEF("export/android/debug_keystore", ""); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "*.keystore")); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks")); EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey"); EDITOR_DEF("export/android/debug_keystore_pass", "android"); EDITOR_DEF("export/android/force_system_user", false); diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 95f870bc35..3bc3651712 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -44,6 +44,67 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut </resources> )"; +DisplayServer::ScreenOrientation _get_screen_orientation() { + String orientation_settings = ProjectSettings::get_singleton()->get("display/window/handheld/orientation"); + DisplayServer::ScreenOrientation screen_orientation; + if (orientation_settings == "portrait") + screen_orientation = DisplayServer::SCREEN_PORTRAIT; + else if (orientation_settings == "reverse_landscape") + screen_orientation = DisplayServer::SCREEN_REVERSE_LANDSCAPE; + else if (orientation_settings == "reverse_portrait") + screen_orientation = DisplayServer::SCREEN_REVERSE_PORTRAIT; + else if (orientation_settings == "sensor_landscape") + screen_orientation = DisplayServer::SCREEN_SENSOR_LANDSCAPE; + else if (orientation_settings == "sensor_portrait") + screen_orientation = DisplayServer::SCREEN_SENSOR_PORTRAIT; + else if (orientation_settings == "sensor") + screen_orientation = DisplayServer::SCREEN_SENSOR; + else + screen_orientation = DisplayServer::SCREEN_LANDSCAPE; + + return screen_orientation; +} + +int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) { + switch (screen_orientation) { + case DisplayServer::SCREEN_PORTRAIT: + return 1; + case DisplayServer::SCREEN_REVERSE_LANDSCAPE: + return 8; + case DisplayServer::SCREEN_REVERSE_PORTRAIT: + return 9; + case DisplayServer::SCREEN_SENSOR_LANDSCAPE: + return 11; + case DisplayServer::SCREEN_SENSOR_PORTRAIT: + return 12; + case DisplayServer::SCREEN_SENSOR: + return 13; + case DisplayServer::SCREEN_LANDSCAPE: + default: + return 0; + } +} + +String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation) { + switch (screen_orientation) { + case DisplayServer::SCREEN_PORTRAIT: + return "portrait"; + case DisplayServer::SCREEN_REVERSE_LANDSCAPE: + return "reverseLandscape"; + case DisplayServer::SCREEN_REVERSE_PORTRAIT: + return "reversePortrait"; + case DisplayServer::SCREEN_SENSOR_LANDSCAPE: + return "userLandscape"; + case DisplayServer::SCREEN_SENSOR_PORTRAIT: + return "userPortrait"; + case DisplayServer::SCREEN_SENSOR: + return "fullUser"; + case DisplayServer::SCREEN_LANDSCAPE: + default: + return "landscape"; + } +} + // Utility method used to create a directory. Error create_directory(const String &p_dir) { if (!DirAccess::exists(p_dir)) { @@ -209,7 +270,7 @@ String _get_plugins_tag(const String &plugins_names) { String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; - String orientation = (int)(p_preset->get("screen/orientation")) == 1 ? "portrait" : "landscape"; + String orientation = _get_android_orientation_label(_get_screen_orientation()); String manifest_activity_text = vformat( " <activity android:name=\"com.godot.game.GodotApp\" " "tools:replace=\"android:screenOrientation\" " diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index 821a4dc584..73c136ed0e 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -22,8 +22,6 @@ allprojects { } ext { - sconsExt = org.gradle.internal.os.OperatingSystem.current().isWindows() ? ".bat" : "" - supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"] supportedTargets = ["release", "debug"] diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle index e3c5a02203..89ce3d15e6 100644 --- a/platform/android/java/lib/build.gradle +++ b/platform/android/java/lib/build.gradle @@ -64,10 +64,42 @@ android { throw new GradleException("Invalid default abi: " + defaultAbi) } + // Find scons' executable path + File sconsExecutableFile = null + def sconsName = "scons" + def sconsExts = (org.gradle.internal.os.OperatingSystem.current().isWindows() + ? [".bat", ".exe"] + : [""]) + logger.lifecycle("Looking for $sconsName executable path") + for (ext in sconsExts) { + String sconsNameExt = sconsName + ext + logger.lifecycle("Checking $sconsNameExt") + + sconsExecutableFile = org.gradle.internal.os.OperatingSystem.current().findInPath(sconsNameExt) + if (sconsExecutableFile != null) { + // We're done! + break + } + + // Check all the options in path + List<File> allOptions = org.gradle.internal.os.OperatingSystem.current().findAllInPath(sconsNameExt) + if (!allOptions.isEmpty()) { + // Pick the first option and we're done! + sconsExecutableFile = allOptions.get(0) + break + } + } + + if (sconsExecutableFile == null) { + throw new GradleException("Unable to find executable path for the '$sconsName' command.") + } else { + logger.lifecycle("Found executable path for $sconsName: ${sconsExecutableFile.absolutePath}") + } + // Creating gradle task to generate the native libraries for the default abi. def taskName = getSconsTaskName(buildType) tasks.create(name: taskName, type: Exec) { - executable "scons" + sconsExt + executable sconsExecutableFile.absolutePath args "--directory=${pathToRootDir}", "platform=android", "target=${releaseTarget}", "android_arch=${defaultAbi}", "-j" + Runtime.runtime.availableProcessors() } diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index 0a558f8e3d..d289e3a16f 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -17,6 +17,7 @@ iphone_lib = [ "godot_view_renderer.mm", "godot_view_gesture_recognizer.mm", "device_metrics.m", + "keyboard_input_view.mm", "native_video_view.m", ] diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index 6fa5e6ee4a..d47d131719 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -35,6 +35,7 @@ #import "device_metrics.h" #import "godot_view.h" #include "ios.h" +#import "keyboard_input_view.h" #import "native_video_view.h" #include "os_iphone.h" #import "view_controller.h" @@ -529,11 +530,17 @@ bool DisplayServerIPhone::screen_is_touchscreen(int p_screen) const { } void DisplayServerIPhone::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { - [AppDelegate.viewController.godotView becomeFirstResponderWithString:p_existing_text]; + NSString *existingString = [[NSString alloc] initWithUTF8String:p_existing_text.utf8().get_data()]; + + [AppDelegate.viewController.keyboardView + becomeFirstResponderWithString:existingString + multiline:p_multiline + cursorStart:p_cursor_start + cursorEnd:p_cursor_end]; } void DisplayServerIPhone::virtual_keyboard_hide() { - [AppDelegate.viewController.godotView resignFirstResponder]; + [AppDelegate.viewController.keyboardView resignFirstResponder]; } void DisplayServerIPhone::virtual_keyboard_set_height(int height) { diff --git a/platform/iphone/godot_view.h b/platform/iphone/godot_view.h index 62fa2f5a32..a8f4cb38d9 100644 --- a/platform/iphone/godot_view.h +++ b/platform/iphone/godot_view.h @@ -35,7 +35,7 @@ class String; @protocol DisplayLayer; @protocol GodotViewRendererProtocol; -@interface GodotView : UIView <UIKeyInput> +@interface GodotView : UIView @property(assign, nonatomic) id<GodotViewRendererProtocol> renderer; @@ -51,6 +51,4 @@ class String; - (void)stopRendering; - (void)startRendering; -- (BOOL)becomeFirstResponderWithString:(String)p_existing; - @end diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm index eaf7e962ce..0c50842cfa 100644 --- a/platform/iphone/godot_view.mm +++ b/platform/iphone/godot_view.mm @@ -42,7 +42,6 @@ static const int max_touches = 8; @interface GodotView () { UITouch *godot_touches[max_touches]; - String keyboard_text; } @property(assign, nonatomic) BOOL isActive; @@ -278,40 +277,6 @@ static const int max_touches = 8; // MARK: - Input -// MARK: Keyboard - -- (BOOL)canBecomeFirstResponder { - return YES; -} - -- (BOOL)becomeFirstResponderWithString:(String)p_existing { - keyboard_text = p_existing; - return [self becomeFirstResponder]; -} - -- (BOOL)resignFirstResponder { - keyboard_text = String(); - return [super resignFirstResponder]; -} - -- (void)deleteBackward { - if (keyboard_text.length()) { - keyboard_text.erase(keyboard_text.length() - 1, 1); - } - DisplayServerIPhone::get_singleton()->key(KEY_BACKSPACE, true); -} - -- (BOOL)hasText { - return keyboard_text.length() > 0; -} - -- (void)insertText:(NSString *)p_text { - String character; - character.parse_utf8([p_text UTF8String]); - keyboard_text = keyboard_text + character; - DisplayServerIPhone::get_singleton()->key(character[0] == 10 ? KEY_ENTER : character[0], true); -} - // MARK: Touches - (void)initTouches { diff --git a/platform/iphone/keyboard_input_view.h b/platform/iphone/keyboard_input_view.h new file mode 100644 index 0000000000..5382a2e9a9 --- /dev/null +++ b/platform/iphone/keyboard_input_view.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* keyboard_input_view.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import <UIKit/UIKit.h> + +@interface GodotKeyboardInputView : UITextView + +- (BOOL)becomeFirstResponderWithString:(NSString *)existingString multiline:(BOOL)flag cursorStart:(NSInteger)start cursorEnd:(NSInteger)end; + +@end diff --git a/platform/iphone/keyboard_input_view.mm b/platform/iphone/keyboard_input_view.mm new file mode 100644 index 0000000000..1a37403de7 --- /dev/null +++ b/platform/iphone/keyboard_input_view.mm @@ -0,0 +1,195 @@ +/*************************************************************************/ +/* keyboard_input_view.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "keyboard_input_view.h" + +#include "core/os/keyboard.h" +#include "display_server_iphone.h" +#include "os_iphone.h" + +@interface GodotKeyboardInputView () <UITextViewDelegate> + +@property(nonatomic, copy) NSString *previousText; +@property(nonatomic, assign) NSRange previousSelectedRange; + +@end + +@implementation GodotKeyboardInputView + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer { + self = [super initWithFrame:frame textContainer:textContainer]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (void)godot_commonInit { + self.hidden = YES; + self.delegate = self; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(observeTextChange:) + name:UITextViewTextDidChangeNotification + object:self]; +} + +- (void)dealloc { + self.delegate = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +// MARK: Keyboard + +- (BOOL)canBecomeFirstResponder { + return YES; +} + +- (BOOL)becomeFirstResponderWithString:(NSString *)existingString multiline:(BOOL)flag cursorStart:(NSInteger)start cursorEnd:(NSInteger)end { + self.text = existingString; + self.previousText = existingString; + + NSRange textRange; + + // Either a simple cursor or a selection. + if (end > 0) { + textRange = NSMakeRange(start, end - start); + } else { + textRange = NSMakeRange(start, 0); + } + + self.selectedRange = textRange; + self.previousSelectedRange = textRange; + + return [self becomeFirstResponder]; +} + +- (BOOL)resignFirstResponder { + self.text = nil; + self.previousText = nil; + return [super resignFirstResponder]; +} + +// MARK: OS Messages + +- (void)deleteText:(NSInteger)charactersToDelete { + for (int i = 0; i < charactersToDelete; i++) { + DisplayServerIPhone::get_singleton()->key(KEY_BACKSPACE, true); + DisplayServerIPhone::get_singleton()->key(KEY_BACKSPACE, false); + } +} + +- (void)enterText:(NSString *)substring { + String characters; + characters.parse_utf8([substring UTF8String]); + + for (int i = 0; i < characters.size(); i++) { + int character = characters[i]; + + switch (character) { + case 10: + character = KEY_ENTER; + break; + case 8198: + character = KEY_SPACE; + break; + default: + break; + } + + DisplayServerIPhone::get_singleton()->key(character, true); + DisplayServerIPhone::get_singleton()->key(character, false); + } +} + +// MARK: Observer + +- (void)observeTextChange:(NSNotification *)notification { + if (notification.object != self) { + return; + } + + if (self.previousSelectedRange.length == 0) { + // We are deleting all text before cursor if no range was selected. + // This way any inserted or changed text will be updated. + NSString *substringToDelete = [self.previousText substringToIndex:self.previousSelectedRange.location]; + [self deleteText:substringToDelete.length]; + } else { + // If text was previously selected + // we are sending only one `backspace`. + // It will remove all text from text input. + [self deleteText:1]; + } + + NSString *substringToEnter; + + if (self.selectedRange.length == 0) { + // If previous cursor had a selection + // we have to calculate an inserted text. + if (self.previousSelectedRange.length != 0) { + NSInteger rangeEnd = self.selectedRange.location + self.selectedRange.length; + NSInteger rangeStart = MIN(self.previousSelectedRange.location, self.selectedRange.location); + NSInteger rangeLength = MAX(0, rangeEnd - rangeStart); + + NSRange calculatedRange; + + if (rangeLength >= 0) { + calculatedRange = NSMakeRange(rangeStart, rangeLength); + } else { + calculatedRange = NSMakeRange(rangeStart, 0); + } + + substringToEnter = [self.text substringWithRange:calculatedRange]; + } else { + substringToEnter = [self.text substringToIndex:self.selectedRange.location]; + } + } else { + substringToEnter = [self.text substringWithRange:self.selectedRange]; + } + + [self enterText:substringToEnter]; + + self.previousText = self.text; + self.previousSelectedRange = self.selectedRange; +} + +@end diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h index 2cc4e4c388..ff76359842 100644 --- a/platform/iphone/view_controller.h +++ b/platform/iphone/view_controller.h @@ -32,11 +32,13 @@ @class GodotView; @class GodotNativeVideoView; +@class GodotKeyboardInputView; @interface ViewController : UIViewController @property(nonatomic, readonly, strong) GodotView *godotView; @property(nonatomic, readonly, strong) GodotNativeVideoView *videoView; +@property(nonatomic, readonly, strong) GodotKeyboardInputView *keyboardView; // MARK: Native Video Player diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index 5d18a72be1..d3969e6b02 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -33,6 +33,7 @@ #include "display_server_iphone.h" #import "godot_view.h" #import "godot_view_renderer.h" +#import "keyboard_input_view.h" #import "native_video_view.h" #include "os_iphone.h" @@ -43,6 +44,7 @@ @property(strong, nonatomic) GodotViewRenderer *renderer; @property(strong, nonatomic) GodotNativeVideoView *videoView; +@property(strong, nonatomic) GodotKeyboardInputView *keyboardView; @end @@ -102,6 +104,10 @@ } - (void)observeKeyboard { + printf("******** setting up keyboard input view\n"); + self.keyboardView = [GodotKeyboardInputView new]; + [self.view addSubview:self.keyboardView]; + printf("******** adding observer for keyboard show/hide\n"); [[NSNotificationCenter defaultCenter] addObserver:self @@ -119,6 +125,9 @@ [self.videoView stopVideo]; self.videoView = nil; + + self.keyboardView = nil; + self.renderer = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 35418116b4..5fa737af8e 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -794,7 +794,9 @@ void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window Atom _net_wm_name = XInternAtom(x11_display, "_NET_WM_NAME", false); Atom utf8_string = XInternAtom(x11_display, "UTF8_STRING", false); - XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length()); + if (_net_wm_name != None && utf8_string != None) { + XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length()); + } } void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { @@ -1184,6 +1186,10 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a unsigned char *data = nullptr; bool retval = false; + if (property == None) { + return false; + } + int result = XGetWindowProperty( x11_display, wd.x11_window, @@ -1272,7 +1278,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { hints.flags = 2; hints.decorations = 0; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } } if (p_enabled) { @@ -1299,7 +1307,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { // set bypass compositor hint Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False); unsigned long compositing_disable_on = p_enabled ? 1 : 0; - XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1); + if (bypass_compositor != None) { + XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1); + } XFlush(x11_display); @@ -1313,7 +1323,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { hints.flags = 2; hints.decorations = window_get_flag(WINDOW_FLAG_BORDERLESS, p_window) ? 0 : 1; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } } } @@ -1448,6 +1460,10 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c { // Test minimized. // Using ICCCM -- Inter-Client Communication Conventions Manual Atom property = XInternAtom(x11_display, "WM_STATE", True); + if (property == None) { + return WINDOW_MODE_WINDOWED; + } + Atom type; int format; unsigned long len; @@ -1503,7 +1519,9 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo hints.flags = 2; hints.decorations = p_enabled ? 0 : 1; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } // Preserve window size window_set_size(window_get_size(p_window), p_window); @@ -1943,28 +1961,29 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const { } DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) { - Atom actual_type; - int actual_format; - unsigned long nitems; - unsigned long bytes_after; + Atom actual_type = None; + int actual_format = 0; + unsigned long nitems = 0; + unsigned long bytes_after = 0; unsigned char *ret = nullptr; int read_bytes = 1024; - //Keep trying to read the property until there are no - //bytes unread. - do { - if (ret != nullptr) { - XFree(ret); - } + // Keep trying to read the property until there are no bytes unread. + if (p_property != None) { + do { + if (ret != nullptr) { + XFree(ret); + } - XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType, - &actual_type, &actual_format, &nitems, &bytes_after, - &ret); + XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType, + &actual_type, &actual_format, &nitems, &bytes_after, + &ret); - read_bytes *= 2; + read_bytes *= 2; - } while (bytes_after != 0); + } while (bytes_after != 0); + } Property p = { ret, actual_format, (int)nitems, actual_type }; @@ -3376,7 +3395,9 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) { pr += 4; } - XChangeProperty(x11_display, wd.x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size()); + if (net_wm_icon != None) { + XChangeProperty(x11_display, wd.x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size()); + } if (!g_set_icon_error) { break; @@ -3469,7 +3490,9 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u { const long pid = OS::get_singleton()->get_process_id(); Atom net_wm_pid = XInternAtom(x11_display, "_NET_WM_PID", False); - XChangeProperty(x11_display, wd.x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); + if (net_wm_pid != None) { + XChangeProperty(x11_display, wd.x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); + } } long im_event_mask = 0; @@ -3517,7 +3540,9 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u /* set the titlebar name */ XStoreName(x11_display, wd.x11_window, "Godot"); XSetWMProtocols(x11_display, wd.x11_window, &wm_delete, 1); - XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1); + if (xdnd_aware != None) { + XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1); + } if (xim && xim_style) { // Block events polling while changing input focus @@ -3548,20 +3573,25 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u hints.flags = 2; hints.decorations = 0; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } } if (wd.menu_type) { // Set Utility type to disable fade animations. Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False); Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); - - XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + if (wt_atom != None && type_atom != None) { + XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + } } else { Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False); Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); - XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + if (wt_atom != None && type_atom != None) { + XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + } } _update_size_hints(id); @@ -3843,6 +3873,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); WindowID main_window = _create_window(p_mode, p_flags, Rect2i(window_position, p_resolution)); + if (main_window == INVALID_WINDOW_ID) { + r_error = ERR_CANT_CREATE; + return; + } for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, main_window); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 5fccde3597..649f5a5f66 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -679,7 +679,7 @@ void LineEdit::_notification(int p_what) { } break; #endif case NOTIFICATION_RESIZED: { - window_pos = 0; + scroll_offset = 0; set_cursor_position(get_cursor_position()); } break; @@ -735,7 +735,7 @@ void LineEdit::_notification(int p_what) { x_ofs = style->get_offset().x; } break; case ALIGN_CENTER: { - if (window_pos != 0) { + if (scroll_offset != 0) { x_ofs = style->get_offset().x; } else { x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - (cached_text_width)) / 2); @@ -747,7 +747,7 @@ void LineEdit::_notification(int p_what) { } int ofs_max = width - style->get_margin(MARGIN_RIGHT); - int char_ofs = window_pos; + int char_ofs = scroll_offset; int y_area = height - style->get_minimum_size().height; int y_ofs = style->get_offset().y + (y_area - font->get_height()) / 2; @@ -780,7 +780,7 @@ void LineEdit::_notification(int p_what) { r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); if (align == ALIGN_CENTER) { - if (window_pos == 0) { + if (scroll_offset == 0) { x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); } } else { @@ -1023,7 +1023,7 @@ void LineEdit::undo() { TextOperation op = undo_stack_pos->get(); text = op.text; cached_width = op.cached_width; - window_pos = op.window_pos; + scroll_offset = op.scroll_offset; set_cursor_position(op.cursor_pos); if (expand_to_text_length) { @@ -1044,7 +1044,7 @@ void LineEdit::redo() { TextOperation op = undo_stack_pos->get(); text = op.text; cached_width = op.cached_width; - window_pos = op.window_pos; + scroll_offset = op.scroll_offset; set_cursor_position(op.cursor_pos); if (expand_to_text_length) { @@ -1071,7 +1071,7 @@ void LineEdit::shift_selection_check_post(bool p_shift) { void LineEdit::set_cursor_at_pixel_pos(int p_x) { Ref<Font> font = get_theme_font("font"); - int ofs = window_pos; + int ofs = scroll_offset; Ref<StyleBox> style = get_theme_stylebox("normal"); int pixel_ofs = 0; Size2 size = get_size(); @@ -1084,7 +1084,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { pixel_ofs = int(style->get_offset().x); } break; case ALIGN_CENTER: { - if (window_pos != 0) { + if (scroll_offset != 0) { pixel_ofs = int(style->get_offset().x); } else { pixel_ofs = int(size.width - (cached_width)) / 2; @@ -1122,7 +1122,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { int LineEdit::get_cursor_pixel_pos() { Ref<Font> font = get_theme_font("font"); - int ofs = window_pos; + int ofs = scroll_offset; Ref<StyleBox> style = get_theme_stylebox("normal"); int pixel_ofs = 0; Size2 size = get_size(); @@ -1135,7 +1135,7 @@ int LineEdit::get_cursor_pixel_pos() { pixel_ofs = int(style->get_offset().x); } break; case ALIGN_CENTER: { - if (window_pos != 0) { + if (scroll_offset != 0) { pixel_ofs = int(style->get_offset().x); } else { pixel_ofs = int(size.width - (cached_width)) / 2; @@ -1236,7 +1236,7 @@ void LineEdit::delete_char() { set_cursor_position(get_cursor_position() - 1); if (align == ALIGN_CENTER || align == ALIGN_RIGHT) { - window_pos = CLAMP(window_pos - 1, 0, MAX(text.length() - 1, 0)); + scroll_offset = CLAMP(scroll_offset - 1, 0, MAX(text.length() - 1, 0)); } _text_changed(); @@ -1262,12 +1262,12 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) { if (cursor_pos >= text.length()) { cursor_pos = text.length(); } - if (window_pos > cursor_pos) { - window_pos = cursor_pos; + if (scroll_offset > cursor_pos) { + scroll_offset = cursor_pos; } if (align == ALIGN_CENTER || align == ALIGN_RIGHT) { - window_pos = CLAMP(window_pos - (p_to_column - p_from_column), 0, MAX(text.length() - 1, 0)); + scroll_offset = CLAMP(scroll_offset - (p_to_column - p_from_column), 0, MAX(text.length() - 1, 0)); } if (!text_changed_dirty) { @@ -1288,7 +1288,7 @@ void LineEdit::set_text(String p_text) { update(); cursor_pos = 0; - window_pos = 0; + scroll_offset = 0; } void LineEdit::clear() { @@ -1332,16 +1332,16 @@ void LineEdit::set_cursor_position(int p_pos) { cursor_pos = p_pos; if (!is_inside_tree()) { - window_pos = cursor_pos; + scroll_offset = cursor_pos; return; } Ref<StyleBox> style = get_theme_stylebox("normal"); Ref<Font> font = get_theme_font("font"); - if (cursor_pos <= window_pos) { + if (cursor_pos <= scroll_offset) { // Adjust window if cursor goes too much to the left. - set_window_pos(MAX(0, cursor_pos - 1)); + set_scroll_offset(MAX(0, cursor_pos - 1)); } else { // Adjust window if cursor goes too much to the right. int window_width = get_size().width - style->get_minimum_size().width; @@ -1354,12 +1354,12 @@ void LineEdit::set_cursor_position(int p_pos) { if (window_width < 0) { return; } - int wp = window_pos; + int wp = scroll_offset; if (font.is_valid()) { int accum_width = 0; - for (int i = cursor_pos; i >= window_pos; i--) { + for (int i = cursor_pos; i >= scroll_offset; i--) { if (i >= text.length()) { // Do not do this, because if the cursor is at the end, its just fine that it takes no space. // accum_width = font->get_char_size(' ').width; @@ -1378,8 +1378,8 @@ void LineEdit::set_cursor_position(int p_pos) { } } - if (wp != window_pos) { - set_window_pos(wp); + if (wp != scroll_offset) { + set_scroll_offset(wp); } } update(); @@ -1389,13 +1389,17 @@ int LineEdit::get_cursor_position() const { return cursor_pos; } -void LineEdit::set_window_pos(int p_pos) { - window_pos = p_pos; - if (window_pos < 0) { - window_pos = 0; +void LineEdit::set_scroll_offset(int p_pos) { + scroll_offset = p_pos; + if (scroll_offset < 0) { + scroll_offset = 0; } } +int LineEdit::get_scroll_offset() const { + return scroll_offset; +} + void LineEdit::append_at_cursor(String p_text) { if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) { String pre = text.substr(0, cursor_pos); @@ -1413,7 +1417,7 @@ void LineEdit::clear_internal() { _clear_undo_stack(); cached_width = 0; cursor_pos = 0; - window_pos = 0; + scroll_offset = 0; undo_text = ""; text = ""; update(); @@ -1644,7 +1648,7 @@ void LineEdit::_editor_settings_changed() { void LineEdit::set_expand_to_text_length(bool p_enabled) { expand_to_text_length = p_enabled; minimum_size_changed(); - set_window_pos(0); + set_scroll_offset(0); } bool LineEdit::get_expand_to_text_length() const { @@ -1771,7 +1775,7 @@ void LineEdit::_create_undo_state() { op.text = text; op.cached_width = cached_width; op.cursor_pos = cursor_pos; - op.window_pos = window_pos; + op.scroll_offset = scroll_offset; undo_stack.push_back(op); } @@ -1816,6 +1820,7 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_placeholder_alpha"), &LineEdit::get_placeholder_alpha); ClassDB::bind_method(D_METHOD("set_cursor_position", "position"), &LineEdit::set_cursor_position); ClassDB::bind_method(D_METHOD("get_cursor_position"), &LineEdit::get_cursor_position); + ClassDB::bind_method(D_METHOD("get_scroll_offset"), &LineEdit::get_scroll_offset); ClassDB::bind_method(D_METHOD("set_expand_to_text_length", "enabled"), &LineEdit::set_expand_to_text_length); ClassDB::bind_method(D_METHOD("get_expand_to_text_length"), &LineEdit::get_expand_to_text_length); ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enabled"), &LineEdit::cursor_set_blink_enabled); @@ -1898,7 +1903,7 @@ LineEdit::LineEdit() { cached_width = 0; cached_placeholder_width = 0; cursor_pos = 0; - window_pos = 0; + scroll_offset = 0; window_has_focus = true; max_length = 0; pass = false; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index d6cc1f1f11..a5e5b6988f 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -80,7 +80,7 @@ private: PopupMenu *menu; int cursor_pos; - int window_pos; + int scroll_offset; int max_length; // 0 for no maximum. int cached_width; @@ -106,7 +106,7 @@ private: struct TextOperation { int cursor_pos; - int window_pos; + int scroll_offset; int cached_width; String text; }; @@ -144,7 +144,8 @@ private: void shift_selection_check_post(bool); void selection_fill_at_cursor(); - void set_window_pos(int p_pos); + void set_scroll_offset(int p_pos); + int get_scroll_offset() const; void set_cursor_at_pixel_pos(int p_x); int get_cursor_pixel_pos(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index cbe6c6bdb9..77ac3d6702 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1559,7 +1559,19 @@ void TextEdit::_notification(int p_what) { } if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { - DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true); + String text = _base_get_text(0, 0, selection.selecting_line, selection.selecting_column); + int cursor_start = text.length(); + int cursor_end = -1; + + if (selection.active) { + String selected_text = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); + + if (selected_text.length() > 0) { + cursor_end = cursor_start + selected_text.length(); + } + } + + DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true, -1, cursor_start, cursor_end); } } break; case NOTIFICATION_FOCUS_EXIT: { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 39ef6eeafa..07de202cc8 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -498,7 +498,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &t ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER); FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); @@ -893,7 +893,7 @@ Image::Format StreamTexture3D::get_format() const { Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); @@ -2325,7 +2325,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER); FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp index 4480b79f75..5a12be5659 100644 --- a/servers/rendering/rendering_server_canvas.cpp +++ b/servers/rendering/rendering_server_canvas.cpp @@ -115,7 +115,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo Rect2 rect = ci->get_rect(); Transform2D xform = ci->xform; if (snapping_2d_transforms_to_pixel) { - xform.elements[2].floor(); + xform.elements[2] = xform.elements[2].floor(); } xform = p_transform * xform; |