diff options
Diffstat (limited to 'core')
31 files changed, 298 insertions, 182 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 21e910be5b..7aa5f4d06d 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -48,6 +48,15 @@ int Engine::get_physics_ticks_per_second() const { return ips; } +void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) { + ERR_FAIL_COND_MSG(p_max_physics_steps <= 0, "Maximum number of physics steps per frame must be greater than 0."); + max_physics_steps_per_frame = p_max_physics_steps; +} + +int Engine::get_max_physics_steps_per_frame() const { + return max_physics_steps_per_frame; +} + void Engine::set_physics_jitter_fix(double p_threshold) { if (p_threshold < 0) { p_threshold = 0; diff --git a/core/config/engine.h b/core/config/engine.h index 21517e46b7..1b179c5727 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -63,6 +63,7 @@ private: int _max_fps = 0; double _time_scale = 1.0; uint64_t _physics_frames = 0; + int max_physics_steps_per_frame = 8; double _physics_interpolation_fraction = 0.0f; bool abort_on_gpu_errors = false; bool use_validation_layers = false; @@ -93,6 +94,9 @@ public: virtual void set_physics_ticks_per_second(int p_ips); virtual int get_physics_ticks_per_second() const; + virtual void set_max_physics_steps_per_frame(int p_max_physics_steps); + virtual int get_max_physics_steps_per_frame() const; + void set_physics_jitter_fix(double p_threshold); double get_physics_jitter_fix() const; diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 4d2006d42a..7aaa9a46b7 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -82,7 +82,7 @@ String ProjectSettings::get_imported_files_path() const { // Returns the features that a project must have when opened with this build of Godot. // This is used by the project manager to provide the initial_settings for config/features. const PackedStringArray ProjectSettings::get_required_features() { - PackedStringArray features = PackedStringArray(); + PackedStringArray features; features.append(VERSION_BRANCH); #ifdef REAL_T_IS_DOUBLE features.append("Double Precision"); @@ -115,7 +115,7 @@ const PackedStringArray ProjectSettings::_get_supported_features() { // Returns the features that this project needs but this build of Godot lacks. const PackedStringArray ProjectSettings::get_unsupported_features(const PackedStringArray &p_project_features) { - PackedStringArray unsupported_features = PackedStringArray(); + PackedStringArray unsupported_features; PackedStringArray supported_features = singleton->_get_supported_features(); for (int i = 0; i < p_project_features.size(); i++) { if (!supported_features.has(p_project_features[i])) { @@ -1246,12 +1246,12 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres"); custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"); - GLOBAL_DEF_RST("audio/general/2d_panning_strength", 1.0f); - custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01"); - GLOBAL_DEF_RST("audio/general/3d_panning_strength", 1.0f); - custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01"); + GLOBAL_DEF_RST("audio/general/2d_panning_strength", 0.5f); + custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"); + GLOBAL_DEF_RST("audio/general/3d_panning_strength", 0.5f); + custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"); - PackedStringArray extensions = PackedStringArray(); + PackedStringArray extensions; extensions.push_back("gd"); if (Engine::get_singleton()->has_singleton("GodotSharp")) { extensions.push_back("cs"); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 87b36f7a21..1fe34cb4fd 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1477,6 +1477,14 @@ int Engine::get_physics_ticks_per_second() const { return ::Engine::get_singleton()->get_physics_ticks_per_second(); } +void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) { + ::Engine::get_singleton()->set_max_physics_steps_per_frame(p_max_physics_steps); +} + +int Engine::get_max_physics_steps_per_frame() const { + return ::Engine::get_singleton()->get_max_physics_steps_per_frame(); +} + void Engine::set_physics_jitter_fix(double p_threshold) { ::Engine::get_singleton()->set_physics_jitter_fix(p_threshold); } @@ -1628,6 +1636,8 @@ bool Engine::is_printing_error_messages() const { void Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_physics_ticks_per_second", "physics_ticks_per_second"), &Engine::set_physics_ticks_per_second); ClassDB::bind_method(D_METHOD("get_physics_ticks_per_second"), &Engine::get_physics_ticks_per_second); + ClassDB::bind_method(D_METHOD("set_max_physics_steps_per_frame", "max_physics_steps"), &Engine::set_max_physics_steps_per_frame); + ClassDB::bind_method(D_METHOD("get_max_physics_steps_per_frame"), &Engine::get_max_physics_steps_per_frame); ClassDB::bind_method(D_METHOD("set_physics_jitter_fix", "physics_jitter_fix"), &Engine::set_physics_jitter_fix); ClassDB::bind_method(D_METHOD("get_physics_jitter_fix"), &Engine::get_physics_jitter_fix); ClassDB::bind_method(D_METHOD("get_physics_interpolation_fraction"), &Engine::get_physics_interpolation_fraction); @@ -1675,6 +1685,7 @@ void Engine::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages"); ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_physics_steps_per_frame"), "set_max_physics_steps_per_frame", "get_max_physics_steps_per_frame"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_fps"), "set_max_fps", "get_max_fps"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_scale"), "set_time_scale", "get_time_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "physics_jitter_fix"), "set_physics_jitter_fix", "get_physics_jitter_fix"); diff --git a/core/core_bind.h b/core/core_bind.h index 784f3e63b1..748ecb4929 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -486,6 +486,9 @@ public: void set_physics_ticks_per_second(int p_ips); int get_physics_ticks_per_second() const; + void set_max_physics_steps_per_frame(int p_max_physics_steps); + int get_max_physics_steps_per_frame() const; + void set_physics_jitter_fix(double p_threshold); double get_physics_jitter_fix() const; double get_physics_interpolation_fraction() const; diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 0e8532a327..628740ed32 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -595,8 +595,6 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA); - BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY); - BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_ID); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING); diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 23ee977df4..a2e3fab82c 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -39,89 +39,6 @@ #include "core/object/script_language.h" #include "core/os/os.h" -class RemoteDebugger::MultiplayerProfiler : public EngineProfiler { - struct BandwidthFrame { - uint32_t timestamp; - int packet_size; - }; - - int bandwidth_in_ptr = 0; - Vector<BandwidthFrame> bandwidth_in; - int bandwidth_out_ptr = 0; - Vector<BandwidthFrame> bandwidth_out; - uint64_t last_bandwidth_time = 0; - - int bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) { - ERR_FAIL_COND_V(p_buffer.size() == 0, 0); - int total_bandwidth = 0; - - uint64_t timestamp = OS::get_singleton()->get_ticks_msec(); - uint64_t final_timestamp = timestamp - 1000; - - int i = (p_pointer + p_buffer.size() - 1) % p_buffer.size(); - - while (i != p_pointer && p_buffer[i].packet_size > 0) { - if (p_buffer[i].timestamp < final_timestamp) { - return total_bandwidth; - } - total_bandwidth += p_buffer[i].packet_size; - i = (i + p_buffer.size() - 1) % p_buffer.size(); - } - - ERR_FAIL_COND_V_MSG(i == p_pointer, total_bandwidth, "Reached the end of the bandwidth profiler buffer, values might be inaccurate."); - return total_bandwidth; - } - -public: - void toggle(bool p_enable, const Array &p_opts) { - if (!p_enable) { - bandwidth_in.clear(); - bandwidth_out.clear(); - } else { - bandwidth_in_ptr = 0; - bandwidth_in.resize(16384); // ~128kB - for (int i = 0; i < bandwidth_in.size(); ++i) { - bandwidth_in.write[i].packet_size = -1; - } - bandwidth_out_ptr = 0; - bandwidth_out.resize(16384); // ~128kB - for (int i = 0; i < bandwidth_out.size(); ++i) { - bandwidth_out.write[i].packet_size = -1; - } - } - } - - void add(const Array &p_data) { - ERR_FAIL_COND(p_data.size() < 3); - const String inout = p_data[0]; - int time = p_data[1]; - int size = p_data[2]; - if (inout == "in") { - bandwidth_in.write[bandwidth_in_ptr].timestamp = time; - bandwidth_in.write[bandwidth_in_ptr].packet_size = size; - bandwidth_in_ptr = (bandwidth_in_ptr + 1) % bandwidth_in.size(); - } else if (inout == "out") { - bandwidth_out.write[bandwidth_out_ptr].timestamp = time; - bandwidth_out.write[bandwidth_out_ptr].packet_size = size; - bandwidth_out_ptr = (bandwidth_out_ptr + 1) % bandwidth_out.size(); - } - } - - void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) { - uint64_t pt = OS::get_singleton()->get_ticks_msec(); - if (pt - last_bandwidth_time > 200) { - last_bandwidth_time = pt; - int incoming_bandwidth = bandwidth_usage(bandwidth_in, bandwidth_in_ptr); - int outgoing_bandwidth = bandwidth_usage(bandwidth_out, bandwidth_out_ptr); - - Array arr; - arr.push_back(incoming_bandwidth); - arr.push_back(outgoing_bandwidth); - EngineDebugger::get_singleton()->send_message("multiplayer:bandwidth", arr); - } - } -}; - class RemoteDebugger::PerformanceProfiler : public EngineProfiler { Object *performance = nullptr; int last_perf_time = 0; @@ -659,10 +576,6 @@ RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) { max_errors_per_second = GLOBAL_GET("network/limits/debugger/max_errors_per_second"); max_warnings_per_second = GLOBAL_GET("network/limits/debugger/max_warnings_per_second"); - // Multiplayer Profiler - multiplayer_profiler.instantiate(); - multiplayer_profiler->bind("multiplayer"); - // Performance Profiler Object *perf = Engine::get_singleton()->get_singleton_object("Performance"); if (perf) { diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h index fe4bbe86ea..944229d361 100644 --- a/core/debugger/remote_debugger.h +++ b/core/debugger/remote_debugger.h @@ -50,10 +50,8 @@ public: private: typedef DebuggerMarshalls::OutputError ErrorMessage; - class MultiplayerProfiler; class PerformanceProfiler; - Ref<MultiplayerProfiler> multiplayer_profiler; Ref<PerformanceProfiler> performance_profiler; Ref<RemoteDebuggerPeer> peer; diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h index 68eed5a161..50410c4857 100644 --- a/core/extension/gdnative_interface.h +++ b/core/extension/gdnative_interface.h @@ -109,6 +109,7 @@ typedef enum { GDNATIVE_VARIANT_OP_LESS_EQUAL, GDNATIVE_VARIANT_OP_GREATER, GDNATIVE_VARIANT_OP_GREATER_EQUAL, + /* mathematic */ GDNATIVE_VARIANT_OP_ADD, GDNATIVE_VARIANT_OP_SUBTRACT, @@ -118,6 +119,7 @@ typedef enum { GDNATIVE_VARIANT_OP_POSITIVE, GDNATIVE_VARIANT_OP_MODULE, GDNATIVE_VARIANT_OP_POWER, + /* bitwise */ GDNATIVE_VARIANT_OP_SHIFT_LEFT, GDNATIVE_VARIANT_OP_SHIFT_RIGHT, @@ -125,11 +127,13 @@ typedef enum { GDNATIVE_VARIANT_OP_BIT_OR, GDNATIVE_VARIANT_OP_BIT_XOR, GDNATIVE_VARIANT_OP_BIT_NEGATE, + /* logic */ GDNATIVE_VARIANT_OP_AND, GDNATIVE_VARIANT_OP_OR, GDNATIVE_VARIANT_OP_XOR, GDNATIVE_VARIANT_OP_NOT, + /* containment */ GDNATIVE_VARIANT_OP_IN, GDNATIVE_VARIANT_OP_MAX @@ -152,11 +156,11 @@ typedef uint64_t GDObjectInstanceID; typedef enum { GDNATIVE_CALL_OK, GDNATIVE_CALL_ERROR_INVALID_METHOD, - GDNATIVE_CALL_ERROR_INVALID_ARGUMENT, /* expected is variant type */ - GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */ - GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */ + GDNATIVE_CALL_ERROR_INVALID_ARGUMENT, // Expected a different variant type. + GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, // Expected lower number of arguments. + GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, // Expected higher number of arguments. GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL, - GDNATIVE_CALL_ERROR_METHOD_NOT_CONST, /* used for const call */ + GDNATIVE_CALL_ERROR_METHOD_NOT_CONST, // Used for const call. } GDNativeCallErrorType; typedef struct { @@ -204,20 +208,24 @@ typedef struct { GDNativeVariantType type; GDNativeStringNamePtr name; GDNativeStringNamePtr class_name; - uint32_t hint; // Bitfield of `PropertyHint` (defined in `extension_api.json`) + uint32_t hint; // Bitfield of `PropertyHint` (defined in `extension_api.json`). GDNativeStringPtr hint_string; - uint32_t usage; // Bitfield of `PropertyUsageFlags` (defined in `extension_api.json`) + uint32_t usage; // Bitfield of `PropertyUsageFlags` (defined in `extension_api.json`). } GDNativePropertyInfo; typedef struct { GDNativeStringNamePtr name; GDNativePropertyInfo return_value; - uint32_t flags; // Bitfield of `GDNativeExtensionClassMethodFlags` + uint32_t flags; // Bitfield of `GDNativeExtensionClassMethodFlags`. int32_t id; - GDNativePropertyInfo *arguments; // array of `argument_count` size + + /* Arguments: `default_arguments` is an array of size `argument_count`. */ uint32_t argument_count; - GDNativeVariantPtr *default_arguments; // array of `default_argument_count` size + GDNativePropertyInfo *arguments; + + /* Default arguments: `default_arguments` is an array of size `default_argument_count`. */ uint32_t default_argument_count; + GDNativeVariantPtr *default_arguments; } GDNativeMethodInfo; typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count); @@ -246,11 +254,11 @@ typedef struct { GDNativeExtensionClassToString to_string_func; GDNativeExtensionClassReference reference_func; GDNativeExtensionClassUnreference unreference_func; - GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ - GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */ - GDNativeExtensionClassGetVirtual get_virtual_func; + GDNativeExtensionClassCreateInstance create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract. + GDNativeExtensionClassFreeInstance free_instance_func; // Destructor; mandatory. + GDNativeExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function. GDNativeExtensionClassGetRID get_rid_func; - void *class_userdata; + void *class_userdata; // Per-class user data, later accessible in instance bindings. } GDNativeExtensionClassCreationInfo; typedef void *GDNativeExtensionClassLibraryPtr; @@ -289,26 +297,34 @@ typedef struct { void *method_userdata; GDNativeExtensionClassMethodCall call_func; GDNativeExtensionClassMethodPtrCall ptrcall_func; - uint32_t method_flags; // Bitfield of `GDNativeExtensionClassMethodFlags` - uint32_t argument_count; + uint32_t method_flags; // Bitfield of `GDNativeExtensionClassMethodFlags`. + + /* If `has_return_value` is false, `return_value_info` and `return_value_metadata` are ignored. */ GDNativeBool has_return_value; - GDNativePropertyInfo *return_value_info; // Ignored if `has_return_value` is false - GDNativeExtensionClassMethodArgumentMetadata return_value_metadata; // Ignored if `has_return_value` is false - /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */ - GDNativePropertyInfo *aguments_info; // array of `argument_count` size - GDNativeExtensionClassMethodArgumentMetadata *aguments_metadata; // array of `argument_count` size + GDNativePropertyInfo *return_value_info; + GDNativeExtensionClassMethodArgumentMetadata return_value_metadata; + + /* Arguments: `arguments_info` and `arguments_metadata` are array of size `argument_count`. + * Name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. + */ + uint32_t argument_count; + GDNativePropertyInfo *arguments_info; + GDNativeExtensionClassMethodArgumentMetadata *arguments_metadata; + + /* Default arguments: `default_arguments` is an array of size `default_argument_count`. */ uint32_t default_argument_count; - GDNativeVariantPtr *default_arguments; // array of `default_argument_count` size + GDNativeVariantPtr *default_arguments; } GDNativeExtensionClassMethodInfo; /* SCRIPT INSTANCE EXTENSION */ -typedef void *GDNativeExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation +typedef void *GDNativeExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation. typedef GDNativeBool (*GDNativeExtensionScriptInstanceSet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value); typedef GDNativeBool (*GDNativeExtensionScriptInstanceGet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret); typedef const GDNativePropertyInfo *(*GDNativeExtensionScriptInstanceGetPropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count); typedef void (*GDNativeExtensionScriptInstanceFreePropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativePropertyInfo *p_list); +typedef GDNativeVariantType (*GDNativeExtensionScriptInstanceGetPropertyType)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeBool *r_is_valid); typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyCanRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name); typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyGetRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret); @@ -354,6 +370,7 @@ typedef struct { GDNativeExtensionScriptInstanceGetMethodList get_method_list_func; GDNativeExtensionScriptInstanceFreeMethodList free_method_list_func; + GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func; GDNativeExtensionScriptInstanceHasMethod has_method_func; @@ -387,6 +404,7 @@ typedef struct { const char *version_string; /* GODOT CORE */ + void *(*mem_alloc)(size_t p_bytes); void *(*mem_realloc)(void *p_ptr, size_t p_bytes); void (*mem_free)(void *p_ptr); @@ -453,7 +471,6 @@ typedef struct { GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const GDNativeStringNamePtr p_function, GDNativeInt p_hash); /* extra utilities */ - void (*string_new_with_latin1_chars)(GDNativeStringPtr r_dest, const char *p_contents); void (*string_new_with_utf8_chars)(GDNativeStringPtr r_dest, const char *p_contents); void (*string_new_with_utf16_chars)(GDNativeStringPtr r_dest, const char16_t *p_contents); @@ -464,6 +481,7 @@ typedef struct { void (*string_new_with_utf16_chars_and_len)(GDNativeStringPtr r_dest, const char16_t *p_contents, const GDNativeInt p_size); void (*string_new_with_utf32_chars_and_len)(GDNativeStringPtr r_dest, const char32_t *p_contents, const GDNativeInt p_size); void (*string_new_with_wide_chars_and_len)(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size); + /* Information about the following functions: * - The return value is the resulting encoded string length. * - The length returned is in characters, not in bytes. It also does not include a trailing zero. @@ -535,13 +553,14 @@ typedef struct { GDNativeScriptInstancePtr (*script_instance_create)(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data); /* CLASSDB */ + GDNativeObjectPtr (*classdb_construct_object)(const GDNativeStringNamePtr p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */ GDNativeMethodBindPtr (*classdb_get_method_bind)(const GDNativeStringNamePtr p_classname, const GDNativeStringNamePtr p_methodname, GDNativeInt p_hash); void *(*classdb_get_class_tag)(const GDNativeStringNamePtr p_classname); /* CLASSDB EXTENSION */ - // Provided parameters for `classdb_register_extension_*` can be safely freed once the function returns + /* Provided parameters for `classdb_register_extension_*` can be safely freed once the function returns. */ void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs); void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info); void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_enum_name, const GDNativeStringNamePtr p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield); @@ -577,9 +596,10 @@ typedef struct { } GDNativeInitialization; /* Define a C function prototype that implements the function below and expose it to dlopen() (or similar). - * It will be called on initialization. The name must be an unique one specified in the .gdextension config file. + * This is the entry point of the GDExtension library and will be called on initialization. + * It can be used to set up different init levels, which are called during various stages of initialization/shutdown. + * The function name must be a unique one specified in the .gdextension config file. */ - typedef GDNativeBool (*GDNativeInitializationFunction)(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization); #ifdef __cplusplus diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp index 8bbb72fd82..83a2e80793 100644 --- a/core/extension/native_extension.cpp +++ b/core/extension/native_extension.cpp @@ -108,8 +108,8 @@ public: } for (uint32_t i = 0; i < p_method_info->argument_count; i++) { - arguments_info.push_back(PropertyInfo(p_method_info->aguments_info[i])); - arguments_metadata.push_back(GodotTypeInfo::Metadata(p_method_info->aguments_metadata[i])); + arguments_info.push_back(PropertyInfo(p_method_info->arguments_info[i])); + arguments_metadata.push_back(GodotTypeInfo::Metadata(p_method_info->arguments_metadata[i])); } set_hint_flags(p_method_info->method_flags); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 9dc071de9c..0a32b4bf68 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -1562,7 +1562,7 @@ String InputEventMIDI::as_text() const { } String InputEventMIDI::to_string() { - return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d", channel, message, pitch, velocity, pressure); + return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d, controller_number=%d, controller_value=%d", channel, message, pitch, velocity, pressure, controller_number, controller_value); } void InputEventMIDI::_bind_methods() { diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index aa1b323db2..0118b4c6af 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -107,6 +107,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String & } Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) { + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_INVALID_PARAMETER, "File must be opened before use."); + Ref<FileAccess> f = FileAccess::open(p_src, FileAccess::READ); if (f.is_null()) { return ERR_FILE_CANT_OPEN; diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index abae48fdd8..16b7f3a1f6 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -41,11 +41,11 @@ static inline bool _is_white_space(char c) { } //! sets the state that text was found. Returns true if set should be set -bool XMLParser::_set_text(char *start, char *end) { +bool XMLParser::_set_text(const char *start, const char *end) { // check if text is more than 2 characters, and if not, check if there is // only white space, so that this text won't be reported if (end - start < 3) { - char *p = start; + const char *p = start; for (; p != end; ++p) { if (!_is_white_space(*p)) { break; @@ -92,7 +92,7 @@ void XMLParser::_parse_closing_xml_element() { void XMLParser::_ignore_definition() { node_type = NODE_UNKNOWN; - char *F = P; + const char *F = P; // move until end marked with '>' reached while (*P && *P != '>') { next_char(); @@ -123,8 +123,8 @@ bool XMLParser::_parse_cdata() { return true; } - char *cDataBegin = P; - char *cDataEnd = nullptr; + const char *cDataBegin = P; + const char *cDataEnd = nullptr; // find end of CDATA while (*P && !cDataEnd) { @@ -152,9 +152,9 @@ void XMLParser::_parse_comment() { node_type = NODE_COMMENT; P += 1; - char *pEndOfInput = data + length; - char *pCommentBegin; - char *pCommentEnd; + const char *pEndOfInput = data + length; + const char *pCommentBegin; + const char *pCommentEnd; if (P + 1 < pEndOfInput && P[0] == '-' && P[1] == '-') { // Comment, use '-->' as end. @@ -293,7 +293,7 @@ void XMLParser::_parse_opening_xml_element() { } void XMLParser::_parse_current_node() { - char *start = P; + const char *start = P; node_offset = P - data; // more forward until '<' found @@ -458,15 +458,36 @@ bool XMLParser::is_empty() const { Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) { ERR_FAIL_COND_V(p_buffer.size() == 0, ERR_INVALID_DATA); - if (data) { - memdelete_arr(data); + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; } length = p_buffer.size(); - data = memnew_arr(char, length + 1); - memcpy(data, p_buffer.ptr(), length); - data[length] = 0; + data_copy = memnew_arr(char, length + 1); + memcpy(data_copy, p_buffer.ptr(), length); + data_copy[length] = 0; + data = data_copy; + P = data; + current_line = 0; + + return OK; +} + +Error XMLParser::_open_buffer(const uint8_t *p_buffer, size_t p_size) { + ERR_FAIL_COND_V(p_size == 0, ERR_INVALID_DATA); + ERR_FAIL_COND_V(!p_buffer, ERR_INVALID_DATA); + + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; + } + + length = p_size; + data = (const char *)p_buffer; P = data; + current_line = 0; + return OK; } @@ -479,13 +500,15 @@ Error XMLParser::open(const String &p_path) { length = file->get_length(); ERR_FAIL_COND_V(length < 1, ERR_FILE_CORRUPT); - if (data) { - memdelete_arr(data); + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; } - data = memnew_arr(char, length + 1); - file->get_buffer((uint8_t *)data, length); - data[length] = 0; + data_copy = memnew_arr(char, length + 1); + file->get_buffer((uint8_t *)data_copy, length); + data_copy[length] = 0; + data = data_copy; P = data; current_line = 0; @@ -512,8 +535,9 @@ void XMLParser::skip_section() { } void XMLParser::close() { - if (data) { + if (data_copy) { memdelete_arr(data); + data_copy = nullptr; } data = nullptr; length = 0; @@ -528,7 +552,8 @@ int XMLParser::get_current_line() const { } XMLParser::~XMLParser() { - if (data) { - memdelete_arr(data); + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; } } diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index aea252ddc7..be44f771dc 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -65,8 +65,9 @@ public: }; private: - char *data = nullptr; - char *P = nullptr; + char *data_copy = nullptr; + const char *data = nullptr; + const char *P = nullptr; uint64_t length = 0; uint64_t current_line = 0; String node_name; @@ -81,7 +82,7 @@ private: Vector<Attribute> attributes; - bool _set_text(char *start, char *end); + bool _set_text(const char *start, const char *end); void _parse_closing_xml_element(); void _ignore_definition(); bool _parse_cdata(); @@ -118,6 +119,7 @@ public: Error open(const String &p_path); Error open_buffer(const Vector<uint8_t> &p_buffer); + Error _open_buffer(const uint8_t *p_buffer, size_t p_size); void close(); diff --git a/core/math/expression.cpp b/core/math/expression.cpp index dcec3929fe..26b809e7f2 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -1420,7 +1420,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: Callable::CallError 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); + r_error_str = "Builtin call failed: " + Variant::get_call_error_text(bifunc->func, (const Variant **)argp.ptr(), argp.size(), ce); return true; } diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index afde6863a3..ac6ad0fdd2 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -1460,7 +1460,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con if (Engine::get_singleton()->has_singleton(p_class)) { c = Engine::get_singleton()->get_singleton_object(p_class); cleanup_c = false; - } else if (ClassDB::can_instantiate(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value. + } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value. c = ClassDB::instantiate(p_class); cleanup_c = true; } diff --git a/core/object/object.h b/core/object/object.h index 7bb88998a2..16ad7b8832 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -71,8 +71,6 @@ enum PropertyHint { PROPERTY_HINT_EXPRESSION, ///< used for string properties that can contain multiple lines PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color - PROPERTY_HINT_IMAGE_COMPRESS_LOSSY, - PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS, PROPERTY_HINT_OBJECT_ID, PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts) diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index c287a6f71a..9a2a176096 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -681,21 +681,15 @@ public: } } virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override { - Variant::Type type = Variant::Type::NIL; - if (native_info->get_property_list_func) { - uint32_t pcount; - const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount); - for (uint32_t i = 0; i < pcount; i++) { - if (p_name == *reinterpret_cast<StringName *>(pinfo->name)) { - type = Variant::Type(pinfo->type); - break; - } - } - if (native_info->free_property_list_func) { - native_info->free_property_list_func(instance, pinfo); + if (native_info->get_property_type_func) { + GDNativeBool is_valid = 0; + GDNativeVariantType type = native_info->get_property_type_func(instance, (const GDNativeStringNamePtr)&p_name, &is_valid); + if (r_is_valid) { + *r_is_valid = is_valid != 0; } + return Variant::Type(type); } - return type; + return Variant::NIL; } virtual bool property_can_revert(const StringName &p_name) const override { diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index aa66e86bc0..9f8a1de697 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -423,6 +423,10 @@ String UndoRedo::get_current_action_name() const { return actions[current_action].name; } +int UndoRedo::get_action_level() const { + return action_level; +} + bool UndoRedo::has_undo() const { return current_action >= 0; } diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index c7c58697c3..9c6d2d10ed 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -120,6 +120,7 @@ public: bool redo(); bool undo(); String get_current_action_name() const; + int get_action_level() const; int get_history_count(); int get_current_action(); diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp index b130c2fc79..2fb3b54e27 100644 --- a/core/string/optimized_translation.cpp +++ b/core/string/optimized_translation.cpp @@ -267,6 +267,39 @@ StringName OptimizedTranslation::get_message(const StringName &p_src_text, const } } +Vector<String> OptimizedTranslation::get_translated_message_list() const { + Vector<String> msgs; + + const int *htr = hash_table.ptr(); + const uint32_t *htptr = (const uint32_t *)&htr[0]; + const int *btr = bucket_table.ptr(); + const uint32_t *btptr = (const uint32_t *)&btr[0]; + const uint8_t *sr = strings.ptr(); + const char *sptr = (const char *)&sr[0]; + + for (int i = 0; i < hash_table.size(); i++) { + uint32_t p = htptr[i]; + if (p != 0xFFFFFFFF) { + const Bucket &bucket = *(const Bucket *)&btptr[p]; + for (int j = 0; j < bucket.size; j++) { + if (bucket.elem[j].comp_size == bucket.elem[j].uncomp_size) { + String rstr; + rstr.parse_utf8(&sptr[bucket.elem[j].str_offset], bucket.elem[j].uncomp_size); + msgs.push_back(rstr); + } else { + CharString uncomp; + uncomp.resize(bucket.elem[j].uncomp_size + 1); + smaz_decompress(&sptr[bucket.elem[j].str_offset], bucket.elem[j].comp_size, uncomp.ptrw(), bucket.elem[j].uncomp_size); + String rstr; + rstr.parse_utf8(uncomp.get_data()); + msgs.push_back(rstr); + } + } + } + } + return msgs; +} + StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const { // The use of plurals translation is not yet supported in OptimizedTranslation. return get_message(p_src_text, p_context); diff --git a/core/string/optimized_translation.h b/core/string/optimized_translation.h index f3dbfe8f5c..1cd12782d0 100644 --- a/core/string/optimized_translation.h +++ b/core/string/optimized_translation.h @@ -81,6 +81,7 @@ protected: public: virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override; + virtual Vector<String> get_translated_message_list() const override; void generate(const Ref<Translation> &p_from); OptimizedTranslation() {} diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 2bed3543dc..d1ac91957a 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -59,6 +59,18 @@ Vector<String> Translation::_get_message_list() const { return msgs; } +Vector<String> Translation::get_translated_message_list() const { + Vector<String> msgs; + msgs.resize(translation_map.size()); + int idx = 0; + for (const KeyValue<StringName, StringName> &E : translation_map) { + msgs.set(idx, E.value); + idx += 1; + } + + return msgs; +} + void Translation::_set_messages(const Dictionary &p_messages) { List<Variant> keys; p_messages.get_key_list(&keys); @@ -140,6 +152,7 @@ void Translation::_bind_methods() { ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL("")); ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list); + ClassDB::bind_method(D_METHOD("get_translated_message_list"), &Translation::get_translated_message_list); ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count); ClassDB::bind_method(D_METHOD("_set_messages", "messages"), &Translation::_set_messages); ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages); diff --git a/core/string/translation.h b/core/string/translation.h index 9a369b0b05..5e8344baac 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -64,6 +64,7 @@ public: virtual void erase_message(const StringName &p_src_text, const StringName &p_context = ""); virtual void get_message_list(List<StringName> *r_messages) const; virtual int get_message_count() const; + virtual Vector<String> get_translated_message_list() const; Translation() {} }; diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp index fa656b634d..724c1d42bc 100644 --- a/core/string/translation_po.cpp +++ b/core/string/translation_po.cpp @@ -103,6 +103,23 @@ void TranslationPO::_set_messages(const Dictionary &p_messages) { } } +Vector<String> TranslationPO::get_translated_message_list() const { + Vector<String> msgs; + for (const KeyValue<StringName, HashMap<StringName, Vector<StringName>>> &E : translation_map) { + if (E.key != StringName()) { + continue; + } + + for (const KeyValue<StringName, Vector<StringName>> &E2 : E.value) { + for (const StringName &E3 : E2.value) { + msgs.push_back(E3); + } + } + } + + return msgs; +} + Vector<String> TranslationPO::_get_message_list() const { // Return all keys in translation_map. diff --git a/core/string/translation_po.h b/core/string/translation_po.h index 7d63af2246..c50ea85744 100644 --- a/core/string/translation_po.h +++ b/core/string/translation_po.h @@ -70,6 +70,7 @@ protected: static void _bind_methods(); public: + Vector<String> get_translated_message_list() const override; void get_message_list(List<StringName> *r_messages) const override; int get_message_count() const override; void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "") override; diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index c6cc4cc4ac..8993f9667d 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1460,15 +1460,25 @@ String String::num(double p_num, int p_decimals) { fmt[5] = 'f'; fmt[6] = 0; } - char buf[256]; + // if we want to convert a double with as much decimal places as as + // DBL_MAX or DBL_MIN then we would theoretically need a buffer of at least + // DBL_MAX_10_EXP + 2 for DBL_MAX and DBL_MAX_10_EXP + 4 for DBL_MIN. + // BUT those values where still giving me exceptions, so I tested from + // DBL_MAX_10_EXP + 10 incrementing one by one and DBL_MAX_10_EXP + 17 (325) + // was the first buffer size not to throw an exception + char buf[325]; #if defined(__GNUC__) || defined(_MSC_VER) - snprintf(buf, 256, fmt, p_num); + // PLEASE NOTE that, albeit vcrt online reference states that snprintf + // should safely truncate the output to the given buffer size, we have + // found a case where this is not true, so we should create a buffer + // as big as needed + snprintf(buf, 325, fmt, p_num); #else sprintf(buf, fmt, p_num); #endif - buf[255] = 0; + buf[324] = 0; //destroy trailing zeroes { bool period = false; @@ -2829,7 +2839,7 @@ String String::substr(int p_from, int p_chars) const { return String(*this); } - String s = String(); + String s; s.copy_from_unchecked(&get_data()[p_from], p_chars); return s; } @@ -3912,7 +3922,6 @@ String String::c_unescape() const { escaped = escaped.replace("\\v", "\v"); escaped = escaped.replace("\\'", "\'"); escaped = escaped.replace("\\\"", "\""); - escaped = escaped.replace("\\?", "\?"); escaped = escaped.replace("\\\\", "\\"); return escaped; @@ -3929,7 +3938,6 @@ String String::c_escape() const { escaped = escaped.replace("\t", "\\t"); escaped = escaped.replace("\v", "\\v"); escaped = escaped.replace("\'", "\\'"); - escaped = escaped.replace("\?", "\\?"); escaped = escaped.replace("\"", "\\\""); return escaped; diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index b4528e67d1..c1166a0a14 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3609,16 +3609,16 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method, if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) { int errorarg = ce.argument; if (p_argptrs) { - err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + "."; + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)); } else { - err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + "."; + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)); } } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { - err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; + err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount); } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { - err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; + err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount); } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { - err_text = "Method not found."; + err_text = "Method not found"; } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) { err_text = "Instance is null"; } else if (ce.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) { diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 91af2bab85..a231a956bf 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2438,7 +2438,7 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0)); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0)); - Transform3D identity_transform = Transform3D(); + Transform3D identity_transform; Transform3D flip_x_transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); Transform3D flip_y_transform = Transform3D(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0); Transform3D flip_z_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0); @@ -2447,7 +2447,7 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Y", flip_y_transform); _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Z", flip_z_transform); - Basis identity_basis = Basis(); + Basis identity_basis; Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1); Basis flip_y_basis = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1); Basis flip_z_basis = Basis(1, 0, 0, 0, 1, 0, 0, 0, -1); diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index ae9727fe79..624a6f5e06 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -68,11 +68,13 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructor<int64_t, int64_t>>(sarray("from")); add_constructor<VariantConstructor<int64_t, double>>(sarray("from")); add_constructor<VariantConstructor<int64_t, bool>>(sarray("from")); + add_constructor<VariantConstructorFromString<int64_t>>(sarray("from")); add_constructor<VariantConstructNoArgs<double>>(sarray()); add_constructor<VariantConstructor<double, double>>(sarray("from")); add_constructor<VariantConstructor<double, int64_t>>(sarray("from")); add_constructor<VariantConstructor<double, bool>>(sarray("from")); + add_constructor<VariantConstructorFromString<double>>(sarray("from")); add_constructor<VariantConstructNoArgs<String>>(sarray()); add_constructor<VariantConstructor<String, String>>(sarray("from")); diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h index 34d228f4d2..f52cc43914 100644 --- a/core/variant/variant_construct.h +++ b/core/variant/variant_construct.h @@ -222,6 +222,64 @@ public: } }; +template <class T> +class VariantConstructorFromString { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::STRING; + return; + } + + VariantTypeChanger<T>::change(&r_ret); + const String &src_str = *VariantGetInternalPtr<String>::get_ptr(p_args[0]); + + if (r_ret.get_type() == Variant::Type::INT) { + r_ret = src_str.to_int(); + } else if (r_ret.get_type() == Variant::Type::FLOAT) { + r_ret = src_str.to_float(); + } + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<T>::change(r_ret); + const String &src_str = *VariantGetInternalPtr<String>::get_ptr(p_args[0]); + T ret = Variant(); + if (r_ret->get_type() == Variant::Type::INT) { + ret = src_str.to_int(); + } else if (r_ret->get_type() == Variant::Type::FLOAT) { + ret = src_str.to_float(); + } + *r_ret = ret; + } + + static void ptr_construct(void *base, const void **p_args) { + String src_str = PtrToArg<String>::convert(p_args[0]); + T dst_var = Variant(); + Variant type_test = Variant(dst_var); + if (type_test.get_type() == Variant::Type::INT) { + dst_var = src_str.to_int(); + } else if (type_test.get_type() == Variant::Type::FLOAT) { + dst_var = src_str.to_float(); + } + PtrConstruct<T>::construct(dst_var, base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::STRING; + } + + static Variant::Type get_base_type() { + return GetTypeInfo<T>::VARIANT_TYPE; + } +}; + class VariantConstructorCallableArgs { public: static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { |