summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/engine.cpp9
-rw-r--r--core/config/engine.h4
-rw-r--r--core/config/project_settings.cpp14
-rw-r--r--core/core_bind.cpp11
-rw-r--r--core/core_bind.h3
-rw-r--r--core/core_constants.cpp2
-rw-r--r--core/debugger/remote_debugger.cpp87
-rw-r--r--core/debugger/remote_debugger.h2
-rw-r--r--core/extension/gdnative_interface.h70
-rw-r--r--core/extension/native_extension.cpp4
-rw-r--r--core/input/input_event.cpp2
-rw-r--r--core/io/xml_parser.cpp69
-rw-r--r--core/io/xml_parser.h8
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/object/object.h2
-rw-r--r--core/object/undo_redo.cpp4
-rw-r--r--core/object/undo_redo.h1
-rw-r--r--core/string/optimized_translation.cpp33
-rw-r--r--core/string/optimized_translation.h1
-rw-r--r--core/string/translation.cpp13
-rw-r--r--core/string/translation.h1
-rw-r--r--core/string/translation_po.cpp17
-rw-r--r--core/string/translation_po.h1
-rw-r--r--core/string/ustring.cpp4
-rw-r--r--core/variant/variant.cpp10
-rw-r--r--core/variant/variant_call.cpp4
-rw-r--r--core/variant/variant_construct.cpp2
-rw-r--r--core/variant/variant_construct.h58
28 files changed, 273 insertions, 165 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 a361e40096..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,21 +297,28 @@ 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);
@@ -389,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);
@@ -455,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);
@@ -466,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.
@@ -537,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);
@@ -579,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/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/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/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 2ba389fc4d..8993f9667d 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -2839,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;
}
@@ -3922,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;
@@ -3939,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) {