summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub9
-rw-r--r--core/config/engine.cpp6
-rw-r--r--core/config/engine.h1
-rw-r--r--core/config/project_settings.cpp4
-rw-r--r--core/core_bind.cpp21
-rw-r--r--core/core_bind.h1
-rw-r--r--core/crypto/SCsub12
-rw-r--r--core/crypto/crypto.h14
-rw-r--r--core/extension/gdextension.cpp4
-rw-r--r--core/extension/gdextension.h8
-rw-r--r--core/input/input.cpp2
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/input/input_event.cpp2
-rw-r--r--core/input/input_map.cpp5
-rw-r--r--core/io/file_access.cpp7
-rw-r--r--core/io/file_access.h1
-rw-r--r--core/io/image.cpp2
-rw-r--r--core/io/image_loader.h8
-rw-r--r--core/io/json.h14
-rw-r--r--core/io/marshalls.cpp212
-rw-r--r--core/io/resource.cpp4
-rw-r--r--core/io/resource_format_binary.h28
-rw-r--r--core/io/resource_importer.h30
-rw-r--r--core/io/resource_loader.cpp2
-rw-r--r--core/io/translation_loader_po.h8
-rw-r--r--core/math/a_star.compat.inc59
-rw-r--r--core/math/a_star.cpp65
-rw-r--r--core/math/a_star.h25
-rw-r--r--core/math/a_star_grid_2d.compat.inc48
-rw-r--r--core/math/a_star_grid_2d.cpp34
-rw-r--r--core/math/a_star_grid_2d.h15
-rw-r--r--core/math/aabb.h2
-rw-r--r--core/math/basis.cpp2
-rw-r--r--core/math/basis.h2
-rw-r--r--core/math/bvh_abb.h2
-rw-r--r--core/math/bvh_debug.inc2
-rw-r--r--core/math/bvh_split.inc4
-rw-r--r--core/math/convex_hull.cpp10
-rw-r--r--core/math/delaunay_3d.h17
-rw-r--r--core/math/dynamic_bvh.h9
-rw-r--r--core/math/geometry_2d.h6
-rw-r--r--core/math/geometry_3d.h79
-rw-r--r--core/math/projection.cpp17
-rw-r--r--core/math/projection.h6
-rw-r--r--core/math/random_pcg.cpp2
-rw-r--r--core/math/rect2.h22
-rw-r--r--core/math/rect2i.h14
-rw-r--r--core/math/transform_interpolator.cpp76
-rw-r--r--core/math/transform_interpolator.h46
-rw-r--r--core/math/vector3.cpp4
-rw-r--r--core/object/object.cpp77
-rw-r--r--core/object/script_language.cpp19
-rw-r--r--core/object/script_language.h2
-rw-r--r--core/os/main_loop.h1
-rw-r--r--core/os/os.h4
-rw-r--r--core/os/pool_allocator.cpp5
-rw-r--r--core/string/translation.cpp4
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/ustring.cpp140
-rw-r--r--core/string/ustring.h11
-rw-r--r--core/templates/local_vector.h16
-rw-r--r--core/variant/type_info.h1
-rw-r--r--core/variant/variant.cpp119
-rw-r--r--core/variant/variant.h37
-rw-r--r--core/variant/variant_call.cpp2
-rw-r--r--core/variant/variant_op.cpp10
66 files changed, 962 insertions, 463 deletions
diff --git a/core/SCsub b/core/SCsub
index 7edf8ea88d..f7b733a221 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -3,6 +3,7 @@
Import("env")
import core_builders
+import methods
env.core_sources = []
@@ -35,10 +36,12 @@ if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
)
Exit(255)
-# NOTE: It is safe to generate this file here, since this is still executed serially
-with open("script_encryption_key.gen.cpp", "w", encoding="utf-8", newline="\n") as f:
- f.write('#include "core/config/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n")
+script_encryption_key_contents = (
+ '#include "core/config/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n"
+)
+
+methods.write_file_if_needed("script_encryption_key.gen.cpp", script_encryption_key_contents)
# Add required thirdparty code.
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index d714ec42c2..9f4bff3779 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -266,6 +266,12 @@ void Engine::print_header(const String &p_string) const {
}
}
+void Engine::print_header_rich(const String &p_string) const {
+ if (_print_header) {
+ print_line_rich(p_string);
+ }
+}
+
void Engine::add_singleton(const Singleton &p_singleton) {
ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), vformat("Can't register singleton '%s' because it already exists.", p_singleton.name));
singletons.push_back(p_singleton);
diff --git a/core/config/engine.h b/core/config/engine.h
index be7cd62f66..d1495b36c2 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -126,6 +126,7 @@ public:
void set_print_error_messages(bool p_enabled);
bool is_printing_error_messages() const;
void print_header(const String &p_string) const;
+ void print_header_rich(const String &p_string) const;
void set_frame_delay(uint32_t p_msec);
uint32_t get_frame_delay() const;
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index ce7fa1074b..352486bd09 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1438,6 +1438,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/run/disable_stdout", false);
GLOBAL_DEF("application/run/disable_stderr", false);
GLOBAL_DEF("application/run/print_header", true);
+ GLOBAL_DEF("application/run/enable_alt_space_menu", false);
GLOBAL_DEF_RST("application/config/use_hidden_project_data_directory", true);
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
@@ -1523,6 +1524,8 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("debug/settings/crash_handler/message.editor",
String("Please include this when reporting the bug on: https://github.com/godotengine/godot/issues"));
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), 2);
+ GLOBAL_DEF_RST("rendering/occlusion_culling/jitter_projection", true);
+
GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "internationalization/rendering/root_node_layout_direction", PROPERTY_HINT_ENUM, "Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale"), 0);
@@ -1536,6 +1539,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::BOOL, "rendering/rendering_device/pipeline_cache/enable"), true);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 6927db002b..8c85030783 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -283,8 +283,8 @@ String OS::read_string_from_stdin() {
int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
List<String> args;
- for (int i = 0; i < p_arguments.size(); i++) {
- args.push_back(p_arguments[i]);
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
}
String pipe;
int exitcode = 0;
@@ -296,10 +296,18 @@ int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r
return exitcode;
}
+Dictionary OS::execute_with_pipe(const String &p_path, const Vector<String> &p_arguments) {
+ List<String> args;
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
+ }
+ return ::OS::get_singleton()->execute_with_pipe(p_path, args);
+}
+
int OS::create_instance(const Vector<String> &p_arguments) {
List<String> args;
- for (int i = 0; i < p_arguments.size(); i++) {
- args.push_back(p_arguments[i]);
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
}
::OS::ProcessID pid = 0;
Error err = ::OS::get_singleton()->create_instance(args, &pid);
@@ -311,8 +319,8 @@ int OS::create_instance(const Vector<String> &p_arguments) {
int OS::create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console) {
List<String> args;
- for (int i = 0; i < p_arguments.size(); i++) {
- args.push_back(p_arguments[i]);
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
}
::OS::ProcessID pid = 0;
Error err = ::OS::get_singleton()->create_process(p_path, args, &pid, p_open_console);
@@ -587,6 +595,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin);
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::execute_with_pipe);
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill);
diff --git a/core/core_bind.h b/core/core_bind.h
index 305f616cef..d46321cf5c 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -156,6 +156,7 @@ public:
String get_executable_path() const;
String read_string_from_stdin();
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
+ Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
int create_instance(const Vector<String> &p_arguments);
Error kill(int p_pid);
diff --git a/core/crypto/SCsub b/core/crypto/SCsub
index ac79e10d19..a6defdfdab 100644
--- a/core/crypto/SCsub
+++ b/core/crypto/SCsub
@@ -21,9 +21,9 @@ if is_builtin or not has_module:
# to make a "light" build with only the necessary mbedtls files.
if not has_module:
# Minimal mbedTLS config file
- env_crypto.Append(
- CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_core_mbedtls_config.h\\"')]
- )
+ config_path = "thirdparty/mbedtls/include/godot_core_mbedtls_config.h"
+ config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
+ env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
# Build minimal mbedTLS library (MD5/SHA/Base64/AES).
env_thirdparty = env_crypto.Clone()
env_thirdparty.disable_warnings()
@@ -46,9 +46,9 @@ if not has_module:
env.core_sources += thirdparty_obj
elif is_builtin:
# Module mbedTLS config file
- env_crypto.Append(
- CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_module_mbedtls_config.h\\"')]
- )
+ config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
+ config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"'
+ env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
# Needed to force rebuilding the core files when the configuration file is updated.
thirdparty_obj = ["#thirdparty/mbedtls/include/godot_module_mbedtls_config.h"]
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 0248b04034..fbd01be86d 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -153,17 +153,17 @@ public:
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
public:
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual bool handles_type(const String &p_type) const override;
+ virtual String get_resource_type(const String &p_path) const override;
};
class ResourceFormatSaverCrypto : public ResourceFormatSaver {
public:
- virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
- virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
- virtual bool recognize(const Ref<Resource> &p_resource) const;
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
+ virtual bool recognize(const Ref<Resource> &p_resource) const override;
};
#endif // CRYPTO_H
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 5d43dceece..0ed4c3380c 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -735,7 +735,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
bool library_copied = false;
if (Engine::get_singleton()->is_editor_hint()) {
if (!FileAccess::exists(abs_path)) {
- ERR_PRINT("GDExtension library not found: " + library_path);
+ ERR_PRINT("GDExtension library not found: " + abs_path);
return ERR_FILE_NOT_FOUND;
}
@@ -750,7 +750,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
Error copy_err = DirAccess::copy_absolute(abs_path, copy_path);
if (copy_err) {
- ERR_PRINT("Error copying GDExtension library: " + library_path);
+ ERR_PRINT("Error copying GDExtension library: " + abs_path);
return ERR_CANT_CREATE;
}
FileAccess::set_hidden_attribute(copy_path, true);
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index a2b948a38a..2d0cb6a5ba 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -176,10 +176,10 @@ class GDExtensionResourceLoader : public ResourceFormatLoader {
public:
static Error load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension);
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual bool handles_type(const String &p_type) const override;
+ virtual String get_resource_type(const String &p_path) const override;
};
#ifdef TOOLS_ENABLED
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 3de0ed39ec..c24a59203f 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -894,7 +894,7 @@ void Input::action_press(const StringName &p_action, float p_strength) {
}
action_state.exact = true;
action_state.api_pressed = true;
- action_state.api_strength = p_strength;
+ action_state.api_strength = CLAMP(p_strength, 0.0f, 1.0f);
_update_action_cache(p_action, action_state);
}
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
index eabdefe543..ae848f4e7c 100644
--- a/core/input/input_builders.py
+++ b/core/input/input_builders.py
@@ -13,7 +13,7 @@ def make_default_controller_mappings(target, source, env):
# ensure mappings have a consistent order
platform_mappings: dict = OrderedDict()
for src_path in source:
- with open(str(src_path), "r") as f:
+ with open(str(src_path), "r", encoding="utf-8") as f:
# read mapping file and skip header
mapping_file_lines = f.readlines()[2:]
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index bd1fde5a85..bf1de8d3b2 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -132,6 +132,8 @@ void InputEvent::_bind_methods() {
ClassDB::bind_method(D_METHOD("xformed_by", "xform", "local_ofs"), &InputEvent::xformed_by, DEFVAL(Vector2()));
ADD_PROPERTY(PropertyInfo(Variant::INT, "device"), "set_device", "get_device");
+
+ BIND_CONSTANT(DEVICE_ID_EMULATION);
}
///////////////////////////////////
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 5d6de1ad9a..7fd1806b31 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -383,6 +383,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_text_select_all", TTRC("Select All") },
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
{ "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
+ { "ui_text_skip_selection_for_next_occurrence", TTRC("Skip Selection for Next Occurrence") },
{ "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") },
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
{ "ui_text_submit", TTRC("Submit Text") },
@@ -722,6 +723,10 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs);
inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
+ default_builtin_cache.insert("ui_text_skip_selection_for_next_occurrence", inputs);
+
+ inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
default_builtin_cache.insert("ui_text_clear_carets_and_selection", inputs);
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 55286277fa..d2a5103953 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -47,6 +47,7 @@ thread_local Error FileAccess::last_file_open_error = OK;
Ref<FileAccess> FileAccess::create(AccessType p_access) {
ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
+ ERR_FAIL_NULL_V(create_func[p_access], nullptr);
Ref<FileAccess> ret = create_func[p_access]();
ret->_set_access_type(p_access);
@@ -75,7 +76,8 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
ret = create(ACCESS_RESOURCES);
} else if (p_path.begins_with("user://")) {
ret = create(ACCESS_USERDATA);
-
+ } else if (p_path.begins_with("pipe://")) {
+ ret = create(ACCESS_PIPE);
} else {
ret = create(ACCESS_FILESYSTEM);
}
@@ -209,6 +211,9 @@ String FileAccess::fix_path(const String &p_path) const {
}
} break;
+ case ACCESS_PIPE: {
+ return r_path;
+ } break;
case ACCESS_FILESYSTEM: {
return r_path;
} break;
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 122ae3b190..0b631f68b1 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -50,6 +50,7 @@ public:
ACCESS_RESOURCES,
ACCESS_USERDATA,
ACCESS_FILESYSTEM,
+ ACCESS_PIPE,
ACCESS_MAX
};
diff --git a/core/io/image.cpp b/core/io/image.cpp
index c454f06d67..6096211cff 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -4114,7 +4114,7 @@ Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool
continue;
}
- image_metric_max = MAX(image_metric_max, i);
+ image_metric_max = i;
double x = i * hist[i];
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index e9b434522d..26af650344 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -103,10 +103,10 @@ public:
class ResourceFormatLoaderImage : public ResourceFormatLoader {
public:
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual bool handles_type(const String &p_type) const override;
+ virtual String get_resource_type(const String &p_path) const override;
};
#endif // IMAGE_LOADER_H
diff --git a/core/io/json.h b/core/io/json.h
index a21cc542fd..801fa29b4b 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -98,17 +98,17 @@ public:
class ResourceFormatLoaderJSON : public ResourceFormatLoader {
public:
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual bool handles_type(const String &p_type) const override;
+ virtual String get_resource_type(const String &p_path) const override;
};
class ResourceFormatSaverJSON : public ResourceFormatSaver {
public:
- virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
- virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
- virtual bool recognize(const Ref<Resource> &p_resource) const;
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
+ virtual bool recognize(const Ref<Resource> &p_resource) const override;
};
#endif // JSON_H
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index bc2493d360..b25fcccd7f 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -30,7 +30,10 @@
#include "marshalls.h"
+#include "core/core_string_names.h"
+#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
+#include "core/object/script_language.h"
#include "core/os/keyboard.h"
#include "core/string/print_string.h"
@@ -55,9 +58,22 @@ ObjectID EncodedObjectAsID::get_object_id() const {
#define ERR_FAIL_ADD_OF(a, b, err) ERR_FAIL_COND_V(((int32_t)(b)) < 0 || ((int32_t)(a)) < 0 || ((int32_t)(a)) > INT_MAX - ((int32_t)(b)), err)
#define ERR_FAIL_MUL_OF(a, b, err) ERR_FAIL_COND_V(((int32_t)(a)) < 0 || ((int32_t)(b)) <= 0 || ((int32_t)(a)) > INT_MAX / ((int32_t)(b)), err)
-#define ENCODE_MASK 0xFF
-#define ENCODE_FLAG_64 1 << 16
-#define ENCODE_FLAG_OBJECT_AS_ID 1 << 16
+// Byte 0: `Variant::Type`, byte 1: unused, bytes 2 and 3: additional data.
+#define HEADER_TYPE_MASK 0xFF
+
+// For `Variant::INT`, `Variant::FLOAT` and other math types.
+#define HEADER_DATA_FLAG_64 (1 << 16)
+
+// For `Variant::OBJECT`.
+#define HEADER_DATA_FLAG_OBJECT_AS_ID (1 << 16)
+
+// For `Variant::ARRAY`.
+// Occupies bits 16 and 17.
+#define HEADER_DATA_FIELD_TYPED_ARRAY_MASK (0b11 << 16)
+#define HEADER_DATA_FIELD_TYPED_ARRAY_NONE (0b00 << 16)
+#define HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN (0b01 << 16)
+#define HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME (0b10 << 16)
+#define HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT (0b11 << 16)
static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r_string) {
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
@@ -101,9 +117,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
- uint32_t type = decode_uint32(buf);
+ uint32_t header = decode_uint32(buf);
- ERR_FAIL_COND_V((type & ENCODE_MASK) >= Variant::VARIANT_MAX, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V((header & HEADER_TYPE_MASK) >= Variant::VARIANT_MAX, ERR_INVALID_DATA);
buf += 4;
len -= 4;
@@ -114,7 +130,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
// Note: We cannot use sizeof(real_t) for decoding, in case a different size is encoded.
// Decoding math types always checks for the encoded size, while encoding always uses compilation setting.
// This does lead to some code duplication for decoding, but compatibility is the priority.
- switch (type & ENCODE_MASK) {
+ switch (header & HEADER_TYPE_MASK) {
case Variant::NIL: {
r_variant = Variant();
} break;
@@ -127,7 +143,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
} break;
case Variant::INT: {
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA);
int64_t val = decode_uint64(buf);
r_variant = val;
@@ -146,7 +162,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::FLOAT: {
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double), ERR_INVALID_DATA);
double val = decode_double(buf);
r_variant = val;
@@ -176,7 +192,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
// math types
case Variant::VECTOR2: {
Vector2 val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 2, ERR_INVALID_DATA);
val.x = decode_double(&buf[0]);
val.y = decode_double(&buf[sizeof(double)]);
@@ -210,7 +226,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::RECT2: {
Rect2 val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA);
val.position.x = decode_double(&buf[0]);
val.position.y = decode_double(&buf[sizeof(double)]);
@@ -250,7 +266,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::VECTOR3: {
Vector3 val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 3, ERR_INVALID_DATA);
val.x = decode_double(&buf[0]);
val.y = decode_double(&buf[sizeof(double)]);
@@ -287,7 +303,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::VECTOR4: {
Vector4 val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA);
val.x = decode_double(&buf[0]);
val.y = decode_double(&buf[sizeof(double)]);
@@ -327,7 +343,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::TRANSFORM2D: {
Transform2D val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
@@ -355,7 +371,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::PLANE: {
Plane val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA);
val.normal.x = decode_double(&buf[0]);
val.normal.y = decode_double(&buf[sizeof(double)]);
@@ -381,7 +397,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::QUATERNION: {
Quaternion val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA);
val.x = decode_double(&buf[0]);
val.y = decode_double(&buf[sizeof(double)]);
@@ -407,7 +423,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::AABB: {
AABB val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA);
val.position.x = decode_double(&buf[0]);
val.position.y = decode_double(&buf[sizeof(double)]);
@@ -437,7 +453,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::BASIS: {
Basis val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 9, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
@@ -465,7 +481,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::TRANSFORM3D: {
Transform3D val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 12, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
@@ -499,7 +515,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::PROJECTION: {
Projection val;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 16, ERR_INVALID_DATA);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
@@ -560,12 +576,12 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
uint32_t namecount = strlen &= 0x7FFFFFFF;
uint32_t subnamecount = decode_uint32(buf + 4);
- uint32_t flags = decode_uint32(buf + 8);
+ uint32_t np_flags = decode_uint32(buf + 8);
len -= 12;
buf += 12;
- if (flags & 2) { // Obsolete format with property separate from subpath
+ if (np_flags & 2) { // Obsolete format with property separate from subpath.
subnamecount++;
}
@@ -589,7 +605,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
}
- r_variant = NodePath(names, subnames, flags & 1);
+ r_variant = NodePath(names, subnames, np_flags & 1);
} else {
//old format, just a string
@@ -608,8 +624,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
r_variant = RID::from_uint64(id);
} break;
case Variant::OBJECT: {
- if (type & ENCODE_FLAG_OBJECT_AS_ID) {
- //this _is_ allowed
+ if (header & HEADER_DATA_FLAG_OBJECT_AS_ID) {
+ // This _is_ allowed.
ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA);
ObjectID val = ObjectID(decode_uint64(buf));
if (r_len) {
@@ -625,7 +641,6 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
r_variant = obj_as_id;
}
-
} else {
ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);
@@ -672,7 +687,16 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
(*r_len) += used;
}
- obj->set(str, value);
+ if (str == "script") {
+ ERR_FAIL_COND_V_MSG(value.get_type() != Variant::STRING, ERR_INVALID_DATA, "Invalid value for \"script\" property, expected script path as String.");
+ String path = value;
+ ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'.");
+ Ref<Script> script = ResourceLoader::load(path, "Script");
+ ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'.");
+ obj->set_script(script);
+ } else {
+ obj->set(str, value);
+ }
}
if (Object::cast_to<RefCounted>(obj)) {
@@ -747,7 +771,60 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::ARRAY: {
+ Variant::Type builtin_type = Variant::VARIANT_MAX;
+ StringName class_name;
+ Ref<Script> script;
+
+ switch (header & HEADER_DATA_FIELD_TYPED_ARRAY_MASK) {
+ case HEADER_DATA_FIELD_TYPED_ARRAY_NONE:
+ break; // Untyped array.
+ case HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN: {
+ ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
+
+ int32_t bt = decode_uint32(buf);
+ buf += 4;
+ len -= 4;
+ if (r_len) {
+ (*r_len) += 4;
+ }
+
+ ERR_FAIL_INDEX_V(bt, Variant::VARIANT_MAX, ERR_INVALID_DATA);
+ builtin_type = (Variant::Type)bt;
+ ERR_FAIL_COND_V(!p_allow_objects && builtin_type == Variant::OBJECT, ERR_UNAUTHORIZED);
+ } break;
+ case HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME: {
+ ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);
+
+ String str;
+ Error err = _decode_string(buf, len, r_len, str);
+ if (err) {
+ return err;
+ }
+
+ builtin_type = Variant::OBJECT;
+ class_name = str;
+ } break;
+ case HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT: {
+ ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);
+
+ String path;
+ Error err = _decode_string(buf, len, r_len, path);
+ if (err) {
+ return err;
+ }
+ ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'.");
+ script = ResourceLoader::load(path, "Script");
+ ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'.");
+
+ builtin_type = Variant::OBJECT;
+ class_name = script->get_instance_base_type();
+ } break;
+ default:
+ ERR_FAIL_V(ERR_INVALID_DATA); // Future proofing.
+ }
+
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
+
int32_t count = decode_uint32(buf);
// bool shared = count&0x80000000;
count &= 0x7FFFFFFF;
@@ -760,6 +837,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
Array varr;
+ if (builtin_type != Variant::VARIANT_MAX) {
+ varr.set_typed(builtin_type, class_name, script);
+ }
for (int i = 0; i < count; i++) {
int used = 0;
@@ -936,7 +1016,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
Vector<Vector2> varray;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_MUL_OF(count, sizeof(double) * 2, ERR_INVALID_DATA);
ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 2 > (size_t)len, ERR_INVALID_DATA);
@@ -996,7 +1076,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
Vector<Vector3> varray;
- if (type & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
ERR_FAIL_MUL_OF(count, sizeof(double) * 3, ERR_INVALID_DATA);
ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 3 > (size_t)len, ERR_INVALID_DATA);
@@ -1122,20 +1202,20 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len = 0;
- uint32_t flags = 0;
+ uint32_t header = p_variant.get_type();
switch (p_variant.get_type()) {
case Variant::INT: {
int64_t val = p_variant;
if (val > (int64_t)INT_MAX || val < (int64_t)INT_MIN) {
- flags |= ENCODE_FLAG_64;
+ header |= HEADER_DATA_FLAG_64;
}
} break;
case Variant::FLOAT: {
double d = p_variant;
float f = d;
if (double(f) != d) {
- flags |= ENCODE_FLAG_64;
+ header |= HEADER_DATA_FLAG_64;
}
} break;
case Variant::OBJECT: {
@@ -1151,7 +1231,23 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
if (!p_full_objects) {
- flags |= ENCODE_FLAG_OBJECT_AS_ID;
+ header |= HEADER_DATA_FLAG_OBJECT_AS_ID;
+ }
+ } break;
+ case Variant::ARRAY: {
+ Array array = p_variant;
+ if (array.is_typed()) {
+ Ref<Script> script = array.get_typed_script();
+ if (script.is_valid()) {
+ ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE);
+ header |= HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT;
+ } else if (array.get_typed_class_name() != StringName()) {
+ ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE);
+ header |= HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME;
+ } else {
+ ERR_FAIL_COND_V(!p_full_objects && array.get_typed_builtin() == Variant::OBJECT, ERR_UNAVAILABLE);
+ header |= HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN;
+ }
}
} break;
#ifdef REAL_T_IS_DOUBLE
@@ -1168,7 +1264,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
case Variant::BASIS:
case Variant::RECT2:
case Variant::AABB: {
- flags |= ENCODE_FLAG_64;
+ header |= HEADER_DATA_FLAG_64;
} break;
#endif // REAL_T_IS_DOUBLE
default: {
@@ -1176,7 +1272,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
if (buf) {
- encode_uint32(p_variant.get_type() | flags, buf);
+ encode_uint32(header, buf);
buf += 4;
}
r_len += 4;
@@ -1194,7 +1290,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} break;
case Variant::INT: {
- if (flags & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
//64 bits
if (buf) {
encode_uint64(p_variant.operator int64_t(), buf);
@@ -1210,7 +1306,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
} break;
case Variant::FLOAT: {
- if (flags & ENCODE_FLAG_64) {
+ if (header & HEADER_DATA_FLAG_64) {
if (buf) {
encode_double(p_variant.operator double(), buf);
}
@@ -1523,8 +1619,21 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
_encode_string(E.name, buf, r_len);
+ Variant value;
+
+ if (E.name == CoreStringNames::get_singleton()->_script) {
+ Ref<Script> script = obj->get_script();
+ if (script.is_valid()) {
+ String path = script->get_path();
+ ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script.");
+ value = path;
+ }
+ } else {
+ value = obj->get(E.name);
+ }
+
int len;
- Error err = encode_variant(obj->get(E.name), buf, len, p_full_objects, p_depth + 1);
+ Error err = encode_variant(value, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
@@ -1594,24 +1703,41 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} break;
case Variant::ARRAY: {
- Array v = p_variant;
+ Array array = p_variant;
+
+ if (array.is_typed()) {
+ Variant variant = array.get_typed_script();
+ Ref<Script> script = variant;
+ if (script.is_valid()) {
+ String path = script->get_path();
+ ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script for an array type.");
+ _encode_string(path, buf, r_len);
+ } else if (array.get_typed_class_name() != StringName()) {
+ _encode_string(array.get_typed_class_name(), buf, r_len);
+ } else {
+ if (buf) {
+ encode_uint32(array.get_typed_builtin(), buf);
+ buf += 4;
+ }
+ r_len += 4;
+ }
+ }
if (buf) {
- encode_uint32(uint32_t(v.size()), buf);
+ encode_uint32(uint32_t(array.size()), buf);
buf += 4;
}
-
r_len += 4;
- for (int i = 0; i < v.size(); i++) {
+ for (int i = 0; i < array.size(); i++) {
int len;
- Error err = encode_variant(v.get(i), buf, len, p_full_objects, p_depth + 1);
+ Error err = encode_variant(array.get(i), buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
- r_len += len;
if (buf) {
buf += len;
}
+ r_len += len;
}
} break;
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 5edb045760..74f18ceee1 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -214,6 +214,7 @@ Error Resource::copy_from(const Ref<Resource> &p_resource) {
}
return OK;
}
+
void Resource::reload_from_file() {
String path = get_path();
if (!path.is_resource_file()) {
@@ -423,8 +424,7 @@ RID Resource::get_rid() const {
}
}
if (_get_extension() && _get_extension()->get_rid) {
- RID ret;
- ret.from_uint64(_get_extension()->get_rid(_get_extension_instance()));
+ RID ret = RID::from_uint64(_get_extension()->get_rid(_get_extension_instance()));
if (ret.is_valid()) {
return ret;
}
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index e01c5fa467..222e633e58 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -110,16 +110,16 @@ public:
class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public:
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
- virtual String get_resource_script_class(const String &p_path) const;
- virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
- virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
- virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
- virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual bool handles_type(const String &p_type) const override;
+ virtual String get_resource_type(const String &p_path) const override;
+ virtual String get_resource_script_class(const String &p_path) const override;
+ virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override;
+ virtual ResourceUID::ID get_resource_uid(const String &p_path) const override;
+ virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override;
+ virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) override;
};
class ResourceFormatSaverBinaryInstance {
@@ -181,10 +181,10 @@ public:
class ResourceFormatSaverBinary : public ResourceFormatSaver {
public:
static ResourceFormatSaverBinary *singleton;
- virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
- virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid);
- virtual bool recognize(const Ref<Resource> &p_resource) const;
- virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
+ virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override;
+ virtual bool recognize(const Ref<Resource> &p_resource) const override;
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
ResourceFormatSaverBinary();
};
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index e17644058a..dbd9e70d16 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -59,22 +59,22 @@ class ResourceFormatImporter : public ResourceFormatLoader {
public:
static ResourceFormatImporter *get_singleton() { return singleton; }
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
- virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
- virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const override;
+ virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const override;
+ virtual bool handles_type(const String &p_type) const override;
+ virtual String get_resource_type(const String &p_path) const override;
+ virtual ResourceUID::ID get_resource_uid(const String &p_path) const override;
virtual Variant get_resource_metadata(const String &p_path) const;
- virtual bool is_import_valid(const String &p_path) const;
- virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
- virtual bool is_imported(const String &p_path) const { return recognize_path(p_path); }
- virtual String get_import_group_file(const String &p_path) const;
- virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
- virtual bool exists(const String &p_path) const;
-
- virtual int get_import_order(const String &p_path) const;
+ virtual bool is_import_valid(const String &p_path) const override;
+ virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override;
+ virtual bool is_imported(const String &p_path) const override { return recognize_path(p_path); }
+ virtual String get_import_group_file(const String &p_path) const override;
+ virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override;
+ virtual bool exists(const String &p_path) const override;
+
+ virtual int get_import_order(const String &p_path) const override;
Error get_import_order_threads_and_importer(const String &p_path, int &r_order, bool &r_can_threads, String &r_importer) const;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index ff563a35b2..191abee315 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -402,7 +402,7 @@ static String _validate_local_path(const String &p_path) {
if (uid != ResourceUID::INVALID_ID) {
return ResourceUID::get_singleton()->get_id_path(uid);
} else if (p_path.is_relative_path()) {
- return "res://" + p_path;
+ return ("res://" + p_path).simplify_path();
} else {
return ProjectSettings::get_singleton()->localize_path(p_path);
}
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index 16e7c28cbe..a695826e59 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -38,10 +38,10 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
static Ref<Resource> load_translation(Ref<FileAccess> f, Error *r_error = nullptr);
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+ virtual bool handles_type(const String &p_type) const override;
+ virtual String get_resource_type(const String &p_path) const override;
TranslationLoaderPO() {}
};
diff --git a/core/math/a_star.compat.inc b/core/math/a_star.compat.inc
new file mode 100644
index 0000000000..664d7ffd5e
--- /dev/null
+++ b/core/math/a_star.compat.inc
@@ -0,0 +1,59 @@
+/**************************************************************************/
+/* a_star.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+Vector<int64_t> AStar3D::_get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
+ return get_id_path(p_from_id, p_to_id, false);
+}
+
+Vector<Vector3> AStar3D::_get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
+ return get_point_path(p_from_id, p_to_id, false);
+}
+
+void AStar3D::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar3D::_get_id_path_bind_compat_88047);
+ ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar3D::_get_point_path_bind_compat_88047);
+}
+
+Vector<int64_t> AStar2D::_get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
+ return get_id_path(p_from_id, p_to_id, false);
+}
+
+Vector<Vector2> AStar2D::_get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
+ return get_point_path(p_from_id, p_to_id, false);
+}
+
+void AStar2D::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar2D::_get_id_path_bind_compat_88047);
+ ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar2D::_get_point_path_bind_compat_88047);
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index fb54058bd9..4497604947 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "a_star.h"
+#include "a_star.compat.inc"
#include "core/math/geometry_3d.h"
#include "core/object/script_language.h"
@@ -319,6 +320,7 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const {
}
bool AStar3D::_solve(Point *begin_point, Point *end_point) {
+ last_closest_point = nullptr;
pass++;
if (!end_point->enabled) {
@@ -332,11 +334,18 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) {
begin_point->g_score = 0;
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
+ begin_point->abs_g_score = 0;
+ begin_point->abs_f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
while (!open_list.is_empty()) {
Point *p = open_list[0]; // The currently processed point.
+ // Find point closer to end_point, or same distance to end_point but closer to begin_point.
+ if (last_closest_point == nullptr || last_closest_point->abs_f_score > p->abs_f_score || (last_closest_point->abs_f_score >= p->abs_f_score && last_closest_point->abs_g_score > p->abs_g_score)) {
+ last_closest_point = p;
+ }
+
if (p == end_point) {
found_route = true;
break;
@@ -368,6 +377,8 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) {
e->prev_point = p;
e->g_score = tentative_g_score;
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
+ e->abs_g_score = tentative_g_score;
+ e->abs_f_score = e->f_score - e->g_score;
if (new_point) { // The position of the new points is already known.
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr());
@@ -414,7 +425,7 @@ real_t AStar3D::_compute_cost(int64_t p_from_id, int64_t p_to_id) {
return from_point->pos.distance_to(to_point->pos);
}
-Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
+Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
Point *a = nullptr;
bool from_exists = points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id));
@@ -434,7 +445,12 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
- return Vector<Vector3>();
+ if (!p_allow_partial_path || last_closest_point == nullptr) {
+ return Vector<Vector3>();
+ }
+
+ // Use closest point instead.
+ end_point = last_closest_point;
}
Point *p = end_point;
@@ -463,7 +479,7 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
return path;
}
-Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
+Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
Point *a = nullptr;
bool from_exists = points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id));
@@ -483,7 +499,12 @@ Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
- return Vector<int64_t>();
+ if (!p_allow_partial_path || last_closest_point == nullptr) {
+ return Vector<int64_t>();
+ }
+
+ // Use closest point instead.
+ end_point = last_closest_point;
}
Point *p = end_point;
@@ -555,8 +576,8 @@ void AStar3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar3D::get_closest_point, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar3D::get_closest_position_in_segment);
- ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar3D::get_point_path);
- ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar3D::get_id_path);
+ ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStar3D::get_point_path, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStar3D::get_id_path, DEFVAL(false));
GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
@@ -688,7 +709,7 @@ real_t AStar2D::_compute_cost(int64_t p_from_id, int64_t p_to_id) {
return from_point->pos.distance_to(to_point->pos);
}
-Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
+Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
AStar3D::Point *a = nullptr;
bool from_exists = astar.points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id));
@@ -707,7 +728,12 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
- return Vector<Vector2>();
+ if (!p_allow_partial_path || astar.last_closest_point == nullptr) {
+ return Vector<Vector2>();
+ }
+
+ // Use closest point instead.
+ end_point = astar.last_closest_point;
}
AStar3D::Point *p = end_point;
@@ -736,7 +762,7 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
return path;
}
-Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
+Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
AStar3D::Point *a = nullptr;
bool from_exists = astar.points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id));
@@ -756,7 +782,12 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
- return Vector<int64_t>();
+ if (!p_allow_partial_path || astar.last_closest_point == nullptr) {
+ return Vector<int64_t>();
+ }
+
+ // Use closest point instead.
+ end_point = astar.last_closest_point;
}
AStar3D::Point *p = end_point;
@@ -786,6 +817,7 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
}
bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
+ astar.last_closest_point = nullptr;
astar.pass++;
if (!end_point->enabled) {
@@ -799,11 +831,18 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
begin_point->g_score = 0;
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
+ begin_point->abs_g_score = 0;
+ begin_point->abs_f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
while (!open_list.is_empty()) {
AStar3D::Point *p = open_list[0]; // The currently processed point.
+ // Find point closer to end_point, or same distance to end_point but closer to begin_point.
+ if (astar.last_closest_point == nullptr || astar.last_closest_point->abs_f_score > p->abs_f_score || (astar.last_closest_point->abs_f_score >= p->abs_f_score && astar.last_closest_point->abs_g_score > p->abs_g_score)) {
+ astar.last_closest_point = p;
+ }
+
if (p == end_point) {
found_route = true;
break;
@@ -835,6 +874,8 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
e->prev_point = p;
e->g_score = tentative_g_score;
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
+ e->abs_g_score = tentative_g_score;
+ e->abs_f_score = e->f_score - e->g_score;
if (new_point) { // The position of the new points is already known.
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr());
@@ -874,8 +915,8 @@ void AStar2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar2D::get_closest_point, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar2D::get_closest_position_in_segment);
- ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar2D::get_point_path);
- ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar2D::get_id_path);
+ ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStar2D::get_point_path, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStar2D::get_id_path, DEFVAL(false));
GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
diff --git a/core/math/a_star.h b/core/math/a_star.h
index 0758500c8a..8e054c4789 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -60,6 +60,10 @@ class AStar3D : public RefCounted {
real_t f_score = 0;
uint64_t open_pass = 0;
uint64_t closed_pass = 0;
+
+ // Used for getting closest_point_of_last_pathing_call.
+ real_t abs_g_score = 0;
+ real_t abs_f_score = 0;
};
struct SortPoints {
@@ -109,6 +113,7 @@ class AStar3D : public RefCounted {
OAHashMap<int64_t, Point *> points;
HashSet<Segment, Segment> segments;
+ Point *last_closest_point = nullptr;
bool _solve(Point *begin_point, Point *end_point);
@@ -121,6 +126,12 @@ protected:
GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t)
GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t)
+#ifndef DISABLE_DEPRECATED
+ Vector<int64_t> _get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
+ Vector<Vector3> _get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
+ static void _bind_compatibility_methods();
+#endif
+
public:
int64_t get_available_point_id() const;
@@ -149,8 +160,8 @@ public:
int64_t get_closest_point(const Vector3 &p_point, bool p_include_disabled = false) const;
Vector3 get_closest_position_in_segment(const Vector3 &p_point) const;
- Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id);
- Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id);
+ Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
+ Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
AStar3D() {}
~AStar3D();
@@ -171,6 +182,12 @@ protected:
GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t)
GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t)
+#ifndef DISABLE_DEPRECATED
+ Vector<int64_t> _get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
+ Vector<Vector2> _get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
+ static void _bind_compatibility_methods();
+#endif
+
public:
int64_t get_available_point_id() const;
@@ -199,8 +216,8 @@ public:
int64_t get_closest_point(const Vector2 &p_point, bool p_include_disabled = false) const;
Vector2 get_closest_position_in_segment(const Vector2 &p_point) const;
- Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id);
- Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id);
+ Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
+ Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
AStar2D() {}
~AStar2D() {}
diff --git a/core/math/a_star_grid_2d.compat.inc b/core/math/a_star_grid_2d.compat.inc
new file mode 100644
index 0000000000..e7124c2477
--- /dev/null
+++ b/core/math/a_star_grid_2d.compat.inc
@@ -0,0 +1,48 @@
+/**************************************************************************/
+/* a_star_grid_2d.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+#include "core/variant/typed_array.h"
+
+TypedArray<Vector2i> AStarGrid2D::_get_id_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ return get_id_path(p_from_id, p_to_id, false);
+}
+
+Vector<Vector2> AStarGrid2D::_get_point_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ return get_point_path(p_from_id, p_to_id, false);
+}
+
+void AStarGrid2D::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::_get_id_path_bind_compat_88047);
+ ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::_get_point_path_bind_compat_88047);
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index d17f465ab8..f272407869 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "a_star_grid_2d.h"
+#include "a_star_grid_2d.compat.inc"
#include "core/variant/typed_array.h"
@@ -446,6 +447,7 @@ void AStarGrid2D::_get_nbors(Point *p_point, LocalVector<Point *> &r_nbors) {
}
bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
+ last_closest_point = nullptr;
pass++;
if (p_end_point->solid) {
@@ -459,12 +461,19 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
p_begin_point->g_score = 0;
p_begin_point->f_score = _estimate_cost(p_begin_point->id, p_end_point->id);
+ p_begin_point->abs_g_score = 0;
+ p_begin_point->abs_f_score = _estimate_cost(p_begin_point->id, p_end_point->id);
open_list.push_back(p_begin_point);
end = p_end_point;
while (!open_list.is_empty()) {
Point *p = open_list[0]; // The currently processed point.
+ // Find point closer to end_point, or same distance to end_point but closer to begin_point.
+ if (last_closest_point == nullptr || last_closest_point->abs_f_score > p->abs_f_score || (last_closest_point->abs_f_score >= p->abs_f_score && last_closest_point->abs_g_score > p->abs_g_score)) {
+ last_closest_point = p;
+ }
+
if (p == p_end_point) {
found_route = true;
break;
@@ -508,6 +517,9 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
e->g_score = tentative_g_score;
e->f_score = e->g_score + _estimate_cost(e->id, p_end_point->id);
+ e->abs_g_score = tentative_g_score;
+ e->abs_f_score = e->f_score - e->g_score;
+
if (new_point) { // The position of the new points is already known.
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr());
} else {
@@ -546,7 +558,7 @@ Vector2 AStarGrid2D::get_point_position(const Vector2i &p_id) const {
return _get_point_unchecked(p_id)->pos;
}
-Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id, bool p_allow_partial_path) {
ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point %s out of bounds %s.", p_from_id, region));
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point %s out of bounds %s.", p_to_id, region));
@@ -565,7 +577,12 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
- return Vector<Vector2>();
+ if (!p_allow_partial_path || last_closest_point == nullptr) {
+ return Vector<Vector2>();
+ }
+
+ // Use closest point instead.
+ end_point = last_closest_point;
}
Point *p = end_point;
@@ -594,7 +611,7 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
return path;
}
-TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id, bool p_allow_partial_path) {
ERR_FAIL_COND_V_MSG(dirty, TypedArray<Vector2i>(), "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point %s out of bounds %s.", p_from_id, region));
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point %s out of bounds %s.", p_to_id, region));
@@ -613,7 +630,12 @@ TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const V
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
- return TypedArray<Vector2i>();
+ if (!p_allow_partial_path || last_closest_point == nullptr) {
+ return TypedArray<Vector2i>();
+ }
+
+ // Use closest point instead.
+ end_point = last_closest_point;
}
Point *p = end_point;
@@ -672,8 +694,8 @@ void AStarGrid2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear);
ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStarGrid2D::get_point_position);
- ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::get_point_path);
- ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::get_id_path);
+ ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStarGrid2D::get_point_path, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStarGrid2D::get_id_path, DEFVAL(false));
GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
index 69cb77dd3e..1a9f6dcc11 100644
--- a/core/math/a_star_grid_2d.h
+++ b/core/math/a_star_grid_2d.h
@@ -89,6 +89,10 @@ private:
uint64_t open_pass = 0;
uint64_t closed_pass = 0;
+ // Used for getting last_closest_point.
+ real_t abs_g_score = 0;
+ real_t abs_f_score = 0;
+
Point() {}
Point(const Vector2i &p_id, const Vector2 &p_pos) :
@@ -109,6 +113,7 @@ private:
LocalVector<LocalVector<Point>> points;
Point *end = nullptr;
+ Point *last_closest_point = nullptr;
uint64_t pass = 1;
@@ -152,6 +157,12 @@ protected:
GDVIRTUAL2RC(real_t, _estimate_cost, Vector2i, Vector2i)
GDVIRTUAL2RC(real_t, _compute_cost, Vector2i, Vector2i)
+#ifndef DISABLE_DEPRECATED
+ TypedArray<Vector2i> _get_id_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to);
+ Vector<Vector2> _get_point_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to);
+ static void _bind_compatibility_methods();
+#endif
+
public:
void set_region(const Rect2i &p_region);
Rect2i get_region() const;
@@ -198,8 +209,8 @@ public:
void clear();
Vector2 get_point_position(const Vector2i &p_id) const;
- Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to);
- TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
+ Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false);
+ TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false);
};
VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode);
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 7927c431eb..48a883e64c 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -101,7 +101,7 @@ struct _NO_DISCARD_ AABB {
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
- return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
+ return AABB(position + size.min(Vector3()), size.abs());
}
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 3ebd13b9fe..84ac878172 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -278,7 +278,7 @@ Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const {
return m;
}
-float Basis::get_uniform_scale() const {
+real_t Basis::get_uniform_scale() const {
return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f;
}
diff --git a/core/math/basis.h b/core/math/basis.h
index 1fc08e95e1..79f3bda8f8 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -99,7 +99,7 @@ struct _NO_DISCARD_ Basis {
void scale_orthogonal(const Vector3 &p_scale);
Basis scaled_orthogonal(const Vector3 &p_scale) const;
- float get_uniform_scale() const;
+ real_t get_uniform_scale() const;
Vector3 get_scale() const;
Vector3 get_scale_abs() const;
diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h
index cec3dc90db..3d32c250c9 100644
--- a/core/math/bvh_abb.h
+++ b/core/math/bvh_abb.h
@@ -258,7 +258,7 @@ struct BVH_ABB {
}
// Actually surface area metric.
- float get_area() const {
+ real_t get_area() const {
POINT d = calculate_size();
return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x);
}
diff --git a/core/math/bvh_debug.inc b/core/math/bvh_debug.inc
index 1964f2fa83..a1fdf78c98 100644
--- a/core/math/bvh_debug.inc
+++ b/core/math/bvh_debug.inc
@@ -10,7 +10,7 @@ String _debug_aabb_to_string(const BVHABB_CLASS &aabb) const {
POINT size = aabb.calculate_size();
String sz;
- float vol = 0.0;
+ real_t vol = 0.0;
for (int i = 0; i < POINT::AXIS_COUNT; ++i) {
sz += "(";
diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc
index 2c85a63575..6da89bd027 100644
--- a/core/math/bvh_split.inc
+++ b/core/math/bvh_split.inc
@@ -150,7 +150,7 @@ void _split_leaf_sort_groups(int &num_a, int &num_b, uint16_t *group_a, uint16_t
BVHABB_CLASS rest_aabb;
- float best_size = FLT_MAX;
+ real_t best_size = FLT_MAX;
int best_candidate = -1;
// find most likely from a to move into b
@@ -171,7 +171,7 @@ void _split_leaf_sort_groups(int &num_a, int &num_b, uint16_t *group_a, uint16_t
groupb_aabb_new.merge(temp_bounds[group_a[check]]);
// now compare the sizes
- float size = groupb_aabb_new.get_area() + rest_aabb.get_area();
+ real_t size = groupb_aabb_new.get_area() + rest_aabb.get_area();
if (size < best_size) {
best_size = size;
best_candidate = check;
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index 478fde3a64..80662c1b07 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -77,15 +77,17 @@ subject to the following restrictions:
#ifdef DEBUG_ENABLED
#define CHULL_ASSERT(m_cond) \
- do { \
+ if constexpr (true) { \
if (unlikely(!(m_cond))) { \
ERR_PRINT("Assertion \"" _STR(m_cond) "\" failed."); \
} \
- } while (0)
+ } else \
+ ((void)0)
#else
#define CHULL_ASSERT(m_cond) \
- do { \
- } while (0)
+ if constexpr (true) { \
+ } else \
+ ((void)0)
#endif
#if defined(DEBUG_CONVEX_HULL) || defined(SHOW_ITERATIONS)
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 7df8c37e3c..45571fb570 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -233,7 +233,7 @@ public:
points[i] = (points[i] - rect.position) / rect.size;
}
- float delta_max = Math::sqrt(2.0) * 20.0;
+ const real_t delta_max = Math::sqrt(2.0) * 20.0;
Vector3 center = Vector3(0.5, 0.5, 0.5);
// any simplex that contains everything is good
@@ -281,9 +281,7 @@ public:
}
Vector3i grid_pos = Vector3i(points[i] * ACCEL_GRID_SIZE);
- grid_pos.x = CLAMP(grid_pos.x, 0, ACCEL_GRID_SIZE - 1);
- grid_pos.y = CLAMP(grid_pos.y, 0, ACCEL_GRID_SIZE - 1);
- grid_pos.z = CLAMP(grid_pos.z, 0, ACCEL_GRID_SIZE - 1);
+ grid_pos = grid_pos.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1));
for (List<Simplex *>::Element *E = acceleration_grid[grid_pos.x][grid_pos.y][grid_pos.z].front(); E;) {
List<Simplex *>::Element *N = E->next(); //may be deleted
@@ -334,17 +332,12 @@ public:
center.y = double(new_simplex->circum_center_y);
center.z = double(new_simplex->circum_center_z);
- float radius2 = Math::sqrt(double(new_simplex->circum_r2));
- radius2 += 0.0001; //
+ const real_t radius2 = Math::sqrt(double(new_simplex->circum_r2)) + 0.0001;
Vector3 extents = Vector3(radius2, radius2, radius2);
Vector3i from = Vector3i((center - extents) * ACCEL_GRID_SIZE);
Vector3i to = Vector3i((center + extents) * ACCEL_GRID_SIZE);
- from.x = CLAMP(from.x, 0, ACCEL_GRID_SIZE - 1);
- from.y = CLAMP(from.y, 0, ACCEL_GRID_SIZE - 1);
- from.z = CLAMP(from.z, 0, ACCEL_GRID_SIZE - 1);
- to.x = CLAMP(to.x, 0, ACCEL_GRID_SIZE - 1);
- to.y = CLAMP(to.y, 0, ACCEL_GRID_SIZE - 1);
- to.z = CLAMP(to.z, 0, ACCEL_GRID_SIZE - 1);
+ from = from.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1));
+ to = to.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1));
for (int32_t x = from.x; x <= to.x; x++) {
for (int32_t y = from.y; y <= to.y; y++) {
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
index f586b845c3..26fc517f7f 100644
--- a/core/math/dynamic_bvh.h
+++ b/core/math/dynamic_bvh.h
@@ -376,13 +376,8 @@ void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Ve
volume.min = p_points[0];
volume.max = p_points[0];
} else {
- volume.min.x = MIN(volume.min.x, p_points[i].x);
- volume.min.y = MIN(volume.min.y, p_points[i].y);
- volume.min.z = MIN(volume.min.z, p_points[i].z);
-
- volume.max.x = MAX(volume.max.x, p_points[i].x);
- volume.max.y = MAX(volume.max.y, p_points[i].y);
- volume.max.z = MAX(volume.max.z, p_points[i].z);
+ volume.min = volume.min.min(p_points[i]);
+ volume.max = volume.max.max(p_points[i]);
}
}
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index fbcaa018a8..1502b2807c 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -377,10 +377,8 @@ public:
Vector2 further_away_opposite(1e20, 1e20);
for (int i = 0; i < c; i++) {
- further_away.x = MAX(p[i].x, further_away.x);
- further_away.y = MAX(p[i].y, further_away.y);
- further_away_opposite.x = MIN(p[i].x, further_away_opposite.x);
- further_away_opposite.y = MIN(p[i].y, further_away_opposite.y);
+ further_away = further_away.max(p[i]);
+ further_away_opposite = further_away_opposite.min(p[i]);
}
// Make point outside that won't intersect with points in segment from p_point.
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index d9788d036f..ff39d82595 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -594,7 +594,7 @@ public:
max = x2; \
}
- _FORCE_INLINE_ static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) {
+ _FORCE_INLINE_ static bool planeBoxOverlap(Vector3 normal, real_t d, Vector3 maxbox) {
int q;
Vector3 vmin, vmax;
for (q = 0; q <= 2; q++) {
@@ -678,8 +678,7 @@ public:
return false; \
}
- /*======================== Z-tests ========================*/
-
+/*======================== Z-tests ========================*/
#define AXISTEST_Z12(a, b, fa, fb) \
p1 = a * v1.x - b * v1.y; \
p2 = a * v2.x - b * v2.y; \
@@ -718,21 +717,19 @@ public:
/* 2) normal of the triangle */
/* 3) crossproduct(edge from tri, {x,y,z}-directin) */
/* this gives 3x3=9 more tests */
- Vector3 v0, v1, v2;
- float min, max, d, p0, p1, p2, rad, fex, fey, fez;
- Vector3 normal, e0, e1, e2;
+ real_t min, max, p0, p1, p2, rad, fex, fey, fez;
/* This is the fastest branch on Sun */
/* move everything so that the boxcenter is in (0,0,0) */
- v0 = triverts[0] - boxcenter;
- v1 = triverts[1] - boxcenter;
- v2 = triverts[2] - boxcenter;
+ const Vector3 v0 = triverts[0] - boxcenter;
+ const Vector3 v1 = triverts[1] - boxcenter;
+ const Vector3 v2 = triverts[2] - boxcenter;
/* compute triangle edges */
- e0 = v1 - v0; /* tri edge 0 */
- e1 = v2 - v1; /* tri edge 1 */
- e2 = v0 - v2; /* tri edge 2 */
+ const Vector3 e0 = v1 - v0; /* tri edge 0 */
+ const Vector3 e1 = v2 - v1; /* tri edge 1 */
+ const Vector3 e2 = v0 - v2; /* tri edge 2 */
/* Bullet 3: */
/* test the 9 tests first (this was faster) */
@@ -784,8 +781,8 @@ public:
/* Bullet 2: */
/* test if the box intersects the plane of the triangle */
/* compute plane equation of triangle: normal*x+d=0 */
- normal = e0.cross(e1);
- d = -normal.dot(v0); /* plane eq: normal.x+d=0 */
+ const Vector3 normal = e0.cross(e1);
+ const real_t d = -normal.dot(v0); /* plane eq: normal.x+d=0 */
return planeBoxOverlap(normal, d, boxhalfsize); /* if true, box and triangle overlaps */
}
@@ -793,51 +790,51 @@ public:
static Vector<int8_t> generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative);
static Vector3 triangle_get_barycentric_coords(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector3 &p_pos) {
- Vector3 v0 = p_b - p_a;
- Vector3 v1 = p_c - p_a;
- Vector3 v2 = p_pos - p_a;
-
- float d00 = v0.dot(v0);
- float d01 = v0.dot(v1);
- float d11 = v1.dot(v1);
- float d20 = v2.dot(v0);
- float d21 = v2.dot(v1);
- float denom = (d00 * d11 - d01 * d01);
+ const Vector3 v0 = p_b - p_a;
+ const Vector3 v1 = p_c - p_a;
+ const Vector3 v2 = p_pos - p_a;
+
+ const real_t d00 = v0.dot(v0);
+ const real_t d01 = v0.dot(v1);
+ const real_t d11 = v1.dot(v1);
+ const real_t d20 = v2.dot(v0);
+ const real_t d21 = v2.dot(v1);
+ const real_t denom = (d00 * d11 - d01 * d01);
if (denom == 0) {
return Vector3(); //invalid triangle, return empty
}
- float v = (d11 * d20 - d01 * d21) / denom;
- float w = (d00 * d21 - d01 * d20) / denom;
- float u = 1.0f - v - w;
+ const real_t v = (d11 * d20 - d01 * d21) / denom;
+ const real_t w = (d00 * d21 - d01 * d20) / denom;
+ const real_t u = 1.0f - v - w;
return Vector3(u, v, w);
}
static Color tetrahedron_get_barycentric_coords(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector3 &p_d, const Vector3 &p_pos) {
- Vector3 vap = p_pos - p_a;
- Vector3 vbp = p_pos - p_b;
+ const Vector3 vap = p_pos - p_a;
+ const Vector3 vbp = p_pos - p_b;
- Vector3 vab = p_b - p_a;
- Vector3 vac = p_c - p_a;
- Vector3 vad = p_d - p_a;
+ const Vector3 vab = p_b - p_a;
+ const Vector3 vac = p_c - p_a;
+ const Vector3 vad = p_d - p_a;
- Vector3 vbc = p_c - p_b;
- Vector3 vbd = p_d - p_b;
+ const Vector3 vbc = p_c - p_b;
+ const Vector3 vbd = p_d - p_b;
// ScTP computes the scalar triple product
#define STP(m_a, m_b, m_c) ((m_a).dot((m_b).cross((m_c))))
- float va6 = STP(vbp, vbd, vbc);
- float vb6 = STP(vap, vac, vad);
- float vc6 = STP(vap, vad, vab);
- float vd6 = STP(vap, vab, vac);
- float v6 = 1 / STP(vab, vac, vad);
+ const real_t va6 = STP(vbp, vbd, vbc);
+ const real_t vb6 = STP(vap, vac, vad);
+ const real_t vc6 = STP(vap, vad, vab);
+ const real_t vd6 = STP(vap, vab, vac);
+ const real_t v6 = 1 / STP(vab, vac, vad);
return Color(va6 * v6, vb6 * v6, vc6 * v6, vd6 * v6);
#undef STP
}
_FORCE_INLINE_ static Vector3 octahedron_map_decode(const Vector2 &p_uv) {
// https://twitter.com/Stubbesaurus/status/937994790553227264
- Vector2 f = p_uv * 2.0f - Vector2(1.0f, 1.0f);
+ const Vector2 f = p_uv * 2.0f - Vector2(1.0f, 1.0f);
Vector3 n = Vector3(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y));
- float t = CLAMP(-n.z, 0.0f, 1.0f);
+ const real_t t = CLAMP(-n.z, 0.0f, 1.0f);
n.x += n.x >= 0 ? -t : t;
n.y += n.y >= 0 ? -t : t;
return n.normalized();
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index 9d5dc8b4d6..d0ca7c5684 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -37,7 +37,7 @@
#include "core/math/transform_3d.h"
#include "core/string/ustring.h"
-float Projection::determinant() const {
+real_t Projection::determinant() const {
return columns[0][3] * columns[1][2] * columns[2][1] * columns[3][0] - columns[0][2] * columns[1][3] * columns[2][1] * columns[3][0] -
columns[0][3] * columns[1][1] * columns[2][2] * columns[3][0] + columns[0][1] * columns[1][3] * columns[2][2] * columns[3][0] +
columns[0][2] * columns[1][1] * columns[2][3] * columns[3][0] - columns[0][1] * columns[1][2] * columns[2][3] * columns[3][0] -
@@ -719,7 +719,8 @@ Projection Projection::operator*(const Projection &p_matrix) const {
return new_matrix;
}
-void Projection::set_depth_correction(bool p_flip_y) {
+void Projection::set_depth_correction(bool p_flip_y, bool p_reverse_z, bool p_remap_z) {
+ // p_remap_z is used to convert from OpenGL-style clip space (-1 - 1) to Vulkan style (0 - 1).
real_t *m = &columns[0][0];
m[0] = 1;
@@ -732,11 +733,11 @@ void Projection::set_depth_correction(bool p_flip_y) {
m[7] = 0.0;
m[8] = 0.0;
m[9] = 0.0;
- m[10] = 0.5;
+ m[10] = p_remap_z ? (p_reverse_z ? -0.5 : 0.5) : (p_reverse_z ? -1.0 : 1.0);
m[11] = 0.0;
m[12] = 0.0;
m[13] = 0.0;
- m[14] = 0.5;
+ m[14] = p_remap_z ? 0.5 : 0.0;
m[15] = 1.0;
}
@@ -831,13 +832,13 @@ real_t Projection::get_fov() const {
}
}
-float Projection::get_lod_multiplier() const {
+real_t Projection::get_lod_multiplier() const {
if (is_orthogonal()) {
return get_viewport_half_extents().x;
} else {
- float zn = get_z_near();
- float width = get_viewport_half_extents().x * 2.0;
- return 1.0 / (zn / width);
+ const real_t zn = get_z_near();
+ const real_t width = get_viewport_half_extents().x * 2.0f;
+ return 1.0f / (zn / width);
}
// Usage is lod_size / (lod_distance * multiplier) < threshold
diff --git a/core/math/projection.h b/core/math/projection.h
index b98f636344..f3ed9d7b1c 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -65,11 +65,11 @@ struct _NO_DISCARD_ Projection {
return columns[p_axis];
}
- float determinant() const;
+ real_t determinant() const;
void set_identity();
void set_zero();
void set_light_bias();
- void set_depth_correction(bool p_flip_y = true);
+ void set_depth_correction(bool p_flip_y = true, bool p_reverse_z = true, bool p_remap_z = true);
void set_light_atlas_rect(const Rect2 &p_rect);
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
@@ -148,7 +148,7 @@ struct _NO_DISCARD_ Projection {
return !(*this == p_cam);
}
- float get_lod_multiplier() const;
+ real_t get_lod_multiplier() const;
Projection();
Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w);
diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp
index e083820494..55787a0b57 100644
--- a/core/math/random_pcg.cpp
+++ b/core/math/random_pcg.cpp
@@ -52,7 +52,7 @@ int64_t RandomPCG::rand_weighted(const Vector<float> &p_weights) {
weights_sum += weights[i];
}
- float remaining_distance = Math::randf() * weights_sum;
+ float remaining_distance = randf() * weights_sum;
for (int64_t i = 0; i < weights_size; ++i) {
remaining_distance -= weights[i];
if (remaining_distance < 0) {
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 0f874d4857..7f410feb1c 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -152,14 +152,12 @@ struct _NO_DISCARD_ Rect2 {
return Rect2();
}
- new_rect.position.x = MAX(p_rect.position.x, position.x);
- new_rect.position.y = MAX(p_rect.position.y, position.y);
+ new_rect.position = p_rect.position.max(position);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
- new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x;
- new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y;
+ new_rect.size = p_rect_end.min(end) - new_rect.position;
return new_rect;
}
@@ -172,11 +170,9 @@ struct _NO_DISCARD_ Rect2 {
#endif
Rect2 new_rect;
- new_rect.position.x = MIN(p_rect.position.x, position.x);
- new_rect.position.y = MIN(p_rect.position.y, position.y);
+ new_rect.position = p_rect.position.min(position);
- new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
- new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
+ new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -282,7 +278,7 @@ struct _NO_DISCARD_ Rect2 {
}
_FORCE_INLINE_ Rect2 abs() const {
- return Rect2(Point2(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0)), size.abs());
+ return Rect2(position + size.min(Point2()), size.abs());
}
_FORCE_INLINE_ Rect2 round() const {
@@ -311,14 +307,14 @@ struct _NO_DISCARD_ Rect2 {
i_f = i;
Vector2 r = (b - a);
- float l = r.length();
+ const real_t l = r.length();
if (l == 0.0f) {
continue;
}
// Check inside.
Vector2 tg = r.orthogonal();
- float s = tg.dot(center) - tg.dot(a);
+ const real_t s = tg.dot(center) - tg.dot(a);
if (s < 0.0f) {
side_plus++;
} else {
@@ -334,8 +330,8 @@ struct _NO_DISCARD_ Rect2 {
Vector2 t13 = (position - a) * ir;
Vector2 t24 = (end - a) * ir;
- float tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y));
- float tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y));
+ const real_t tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y));
+ const real_t tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y));
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
if (tmax < 0 || tmin > tmax || tmin >= l) {
diff --git a/core/math/rect2i.h b/core/math/rect2i.h
index 205b2c7198..64806414c7 100644
--- a/core/math/rect2i.h
+++ b/core/math/rect2i.h
@@ -95,14 +95,12 @@ struct _NO_DISCARD_ Rect2i {
return Rect2i();
}
- new_rect.position.x = MAX(p_rect.position.x, position.x);
- new_rect.position.y = MAX(p_rect.position.y, position.y);
+ new_rect.position = p_rect.position.max(position);
Point2i p_rect_end = p_rect.position + p_rect.size;
Point2i end = position + size;
- new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x;
- new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y;
+ new_rect.size = p_rect_end.min(end) - new_rect.position;
return new_rect;
}
@@ -115,11 +113,9 @@ struct _NO_DISCARD_ Rect2i {
#endif
Rect2i new_rect;
- new_rect.position.x = MIN(p_rect.position.x, position.x);
- new_rect.position.y = MIN(p_rect.position.y, position.y);
+ new_rect.position = p_rect.position.min(position);
- new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
- new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
+ new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -217,7 +213,7 @@ struct _NO_DISCARD_ Rect2i {
}
_FORCE_INLINE_ Rect2i abs() const {
- return Rect2i(Point2i(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
+ return Rect2i(position + size.min(Point2i()), size.abs());
}
_FORCE_INLINE_ void set_end(const Vector2i &p_end) {
diff --git a/core/math/transform_interpolator.cpp b/core/math/transform_interpolator.cpp
new file mode 100644
index 0000000000..7cfe880b5a
--- /dev/null
+++ b/core/math/transform_interpolator.cpp
@@ -0,0 +1,76 @@
+/**************************************************************************/
+/* transform_interpolator.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/**************************************************************************/
+
+#include "transform_interpolator.h"
+
+#include "core/math/transform_2d.h"
+
+void TransformInterpolator::interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction) {
+ // Extract parameters.
+ Vector2 p1 = p_prev.get_origin();
+ Vector2 p2 = p_curr.get_origin();
+
+ // Special case for physics interpolation, if flipping, don't interpolate basis.
+ // If the determinant polarity changes, the handedness of the coordinate system changes.
+ if (_sign(p_prev.determinant()) != _sign(p_curr.determinant())) {
+ r_result.columns[0] = p_curr.columns[0];
+ r_result.columns[1] = p_curr.columns[1];
+ r_result.set_origin(p1.lerp(p2, p_fraction));
+ return;
+ }
+
+ real_t r1 = p_prev.get_rotation();
+ real_t r2 = p_curr.get_rotation();
+
+ Size2 s1 = p_prev.get_scale();
+ Size2 s2 = p_curr.get_scale();
+
+ // Slerp rotation.
+ Vector2 v1(Math::cos(r1), Math::sin(r1));
+ Vector2 v2(Math::cos(r2), Math::sin(r2));
+
+ real_t dot = v1.dot(v2);
+
+ dot = CLAMP(dot, -1, 1);
+
+ Vector2 v;
+
+ if (dot > 0.9995f) {
+ v = v1.lerp(v2, p_fraction).normalized(); // Linearly interpolate to avoid numerical precision issues.
+ } else {
+ real_t angle = p_fraction * Math::acos(dot);
+ Vector2 v3 = (v2 - v1 * dot).normalized();
+ v = v1 * Math::cos(angle) + v3 * Math::sin(angle);
+ }
+
+ // Construct matrix.
+ r_result = Transform2D(Math::atan2(v.y, v.x), p1.lerp(p2, p_fraction));
+ r_result.scale_basis(s1.lerp(s2, p_fraction));
+}
diff --git a/core/math/transform_interpolator.h b/core/math/transform_interpolator.h
new file mode 100644
index 0000000000..a9bce2bd7f
--- /dev/null
+++ b/core/math/transform_interpolator.h
@@ -0,0 +1,46 @@
+/**************************************************************************/
+/* transform_interpolator.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/**************************************************************************/
+
+#ifndef TRANSFORM_INTERPOLATOR_H
+#define TRANSFORM_INTERPOLATOR_H
+
+#include "core/math/math_defs.h"
+
+struct Transform2D;
+
+class TransformInterpolator {
+private:
+ static bool _sign(real_t p_val) { return p_val >= 0; }
+
+public:
+ static void interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction);
+};
+
+#endif // TRANSFORM_INTERPOLATOR_H
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index be494705ff..fad5f2c0fb 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -101,14 +101,14 @@ Vector2 Vector3::octahedron_encode() const {
Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f);
Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y));
- float t = CLAMP(-n.z, 0.0f, 1.0f);
+ const real_t t = CLAMP(-n.z, 0.0f, 1.0f);
n.x += n.x >= 0 ? -t : t;
n.y += n.y >= 0 ? -t : t;
return n.normalized();
}
Vector2 Vector3::octahedron_tangent_encode(float p_sign) const {
- const float bias = 1.0f / 32767.0f;
+ const real_t bias = 1.0f / (real_t)32767.0f;
Vector2 res = octahedron_encode();
res.y = MAX(res.y, bias);
res.y = res.y * 0.5f + 0.5f;
diff --git a/core/object/object.cpp b/core/object/object.cpp
index e0a1ddcce0..8b6fd587e0 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -1100,11 +1100,6 @@ bool Object::_has_user_signal(const StringName &p_name) const {
return signal_map[p_name].user.name.length() > 0;
}
-struct _ObjectSignalDisconnectData {
- StringName signal;
- Callable callable;
-};
-
Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (unlikely(p_argcount < 1)) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -1153,26 +1148,43 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
// which is needed in certain edge cases; e.g., https://github.com/godotengine/godot/issues/73889.
Ref<RefCounted> rc = Ref<RefCounted>(Object::cast_to<RefCounted>(this));
- List<_ObjectSignalDisconnectData> disconnect_data;
-
// Ensure that disconnecting the signal or even deleting the object
// will not affect the signal calling.
- LocalVector<Connection> slot_conns;
- slot_conns.resize(s->slot_map.size());
- {
- uint32_t idx = 0;
- for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
- slot_conns[idx++] = slot_kv.value.conn;
+ Callable *slot_callables = (Callable *)alloca(sizeof(Callable) * s->slot_map.size());
+ uint32_t *slot_flags = (uint32_t *)alloca(sizeof(uint32_t) * s->slot_map.size());
+ uint32_t slot_count = 0;
+
+ for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
+ memnew_placement(&slot_callables[slot_count], Callable(slot_kv.value.conn.callable));
+ slot_flags[slot_count] = slot_kv.value.conn.flags;
+ ++slot_count;
+ }
+
+ DEV_ASSERT(slot_count == s->slot_map.size());
+
+ // Disconnect all one-shot connections before emitting to prevent recursion.
+ for (uint32_t i = 0; i < slot_count; ++i) {
+ bool disconnect = slot_flags[i] & CONNECT_ONE_SHOT;
+#ifdef TOOLS_ENABLED
+ if (disconnect && (slot_flags[i] & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
+ // This signal was connected from the editor, and is being edited. Just don't disconnect for now.
+ disconnect = false;
+ }
+#endif
+ if (disconnect) {
+ _disconnect(p_name, slot_callables[i]);
}
- DEV_ASSERT(idx == s->slot_map.size());
}
OBJ_DEBUG_LOCK
Error err = OK;
- for (const Connection &c : slot_conns) {
- if (!c.callable.is_valid()) {
+ for (uint32_t i = 0; i < slot_count; ++i) {
+ const Callable &callable = slot_callables[i];
+ const uint32_t &flags = slot_flags[i];
+
+ if (!callable.is_valid()) {
// Target might have been deleted during signal callback, this is expected and OK.
continue;
}
@@ -1180,51 +1192,34 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
const Variant **args = p_args;
int argc = p_argcount;
- if (c.flags & CONNECT_DEFERRED) {
- MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true);
+ if (flags & CONNECT_DEFERRED) {
+ MessageQueue::get_singleton()->push_callablep(callable, args, argc, true);
} else {
Callable::CallError ce;
_emitting = true;
Variant ret;
- c.callable.callp(args, argc, ret, ce);
+ callable.callp(args, argc, ret, ce);
_emitting = false;
if (ce.error != Callable::CallError::CALL_OK) {
#ifdef DEBUG_ENABLED
- if (c.flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) {
+ if (flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) {
continue;
}
#endif
- Object *target = c.callable.get_object();
+ Object *target = callable.get_object();
if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && target && !ClassDB::class_exists(target->get_class_name())) {
//most likely object is not initialized yet, do not throw error.
} else {
- ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc, ce) + ".");
+ ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(callable, args, argc, ce) + ".");
err = ERR_METHOD_NOT_FOUND;
}
}
}
-
- bool disconnect = c.flags & CONNECT_ONE_SHOT;
-#ifdef TOOLS_ENABLED
- if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
- //this signal was connected from the editor, and is being edited. just don't disconnect for now
- disconnect = false;
- }
-#endif
- if (disconnect) {
- _ObjectSignalDisconnectData dd;
- dd.signal = p_name;
- dd.callable = c.callable;
- disconnect_data.push_back(dd);
- }
}
- while (!disconnect_data.is_empty()) {
- const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
-
- _disconnect(dd.signal, dd.callable);
- disconnect_data.pop_front();
+ for (uint32_t i = 0; i < slot_count; ++i) {
+ slot_callables[i].~Callable();
}
return err;
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 1196c2f787..73da0ba2af 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -34,6 +34,7 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/io/resource_loader.h"
#include <stdint.h>
@@ -170,6 +171,24 @@ void Script::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_source_code", "get_source_code");
}
+void Script::reload_from_file() {
+#ifdef TOOLS_ENABLED
+ // Replicates how the ScriptEditor reloads script resources, which generally handles it.
+ // However, when scripts are to be reloaded but aren't open in the internal editor, we go through here instead.
+ const Ref<Script> rel = ResourceLoader::load(ResourceLoader::path_remap(get_path()), get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ if (rel.is_null()) {
+ return;
+ }
+
+ set_source_code(rel->get_source_code());
+ set_last_modified_time(rel->get_last_modified_time());
+
+ reload();
+#else
+ Resource::reload_from_file();
+#endif
+}
+
void ScriptServer::set_scripting_enabled(bool p_enabled) {
scripting_enabled = p_enabled;
}
diff --git a/core/object/script_language.h b/core/object/script_language.h
index be50e58d79..c6c6f3de9f 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -125,6 +125,8 @@ protected:
Dictionary _get_script_constant_map();
public:
+ virtual void reload_from_file() override;
+
virtual bool can_instantiate() const = 0;
virtual Ref<Script> get_base_script() const = 0; //for script inheritance
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index b45eb38aeb..e48541d074 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -62,6 +62,7 @@ public:
};
virtual void initialize();
+ virtual void iteration_prepare() {}
virtual bool physics_process(double p_time);
virtual bool process(double p_time);
virtual void finalize();
diff --git a/core/os/os.h b/core/os/os.h
index e0dda0b155..370e724c53 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -56,7 +56,8 @@ class OS {
bool _verbose_stdout = false;
bool _debug_stdout = false;
String _local_clipboard;
- int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure
+ // Assume success by default, all failure cases need to set EXIT_FAILURE explicitly.
+ int _exit_code = EXIT_SUCCESS;
bool _allow_hidpi = false;
bool _allow_layered = false;
bool _stdout_enabled = true;
@@ -169,6 +170,7 @@ public:
virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const { return Vector<String>(); };
virtual String get_executable_path() const;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0;
+ virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) { return Dictionary(); }
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0;
virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) { return create_process(get_executable_path(), p_arguments, r_child_id); };
virtual Error kill(const ProcessID &p_pid) = 0;
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index acbaed4ce8..9a993cd14f 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -36,12 +36,13 @@
#include "core/string/print_string.h"
#define COMPACT_CHUNK(m_entry, m_to_pos) \
- do { \
+ if constexpr (true) { \
void *_dst = &((unsigned char *)pool)[m_to_pos]; \
void *_src = &((unsigned char *)pool)[(m_entry).pos]; \
memmove(_dst, _src, aligned((m_entry).len)); \
(m_entry).pos = m_to_pos; \
- } while (0);
+ } else \
+ ((void)0)
void PoolAllocator::mt_lock() const {
}
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 0a0052d6cb..613edd11cd 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -776,9 +776,9 @@ void TranslationServer::set_property_translation(const Ref<Translation> &p_trans
property_translation = p_translation;
}
-StringName TranslationServer::property_translate(const StringName &p_message) const {
+StringName TranslationServer::property_translate(const StringName &p_message, const StringName &p_context) const {
if (property_translation.is_valid()) {
- StringName r = property_translation->get_message(p_message);
+ StringName r = property_translation->get_message(p_message, p_context);
if (r) {
return r;
}
diff --git a/core/string/translation.h b/core/string/translation.h
index 470ba88232..78d6721347 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -183,7 +183,7 @@ public:
StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const;
StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
void set_property_translation(const Ref<Translation> &p_translation);
- StringName property_translate(const StringName &p_message) const;
+ StringName property_translate(const StringName &p_message, const StringName &p_context = "") const;
void set_doc_translation(const Ref<Translation> &p_translation);
StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const;
StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index a7e12138f2..2b62b72a51 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -927,52 +927,49 @@ static _FORCE_INLINE_ signed char natural_cmp_common(const char32_t *&r_this_str
return 0;
}
-signed char String::naturalcasecmp_to(const String &p_str) const {
- const char32_t *this_str = get_data();
- const char32_t *that_str = p_str.get_data();
-
- if (this_str && that_str) {
- while (*this_str == '.' || *that_str == '.') {
- if (*this_str++ != '.') {
+static _FORCE_INLINE_ signed char naturalcasecmp_to_base(const char32_t *p_this_str, const char32_t *p_that_str) {
+ if (p_this_str && p_that_str) {
+ while (*p_this_str == '.' || *p_that_str == '.') {
+ if (*p_this_str++ != '.') {
return 1;
}
- if (*that_str++ != '.') {
+ if (*p_that_str++ != '.') {
return -1;
}
- if (!*that_str) {
+ if (!*p_that_str) {
return 1;
}
- if (!*this_str) {
+ if (!*p_this_str) {
return -1;
}
}
- while (*this_str) {
- if (!*that_str) {
+ while (*p_this_str) {
+ if (!*p_that_str) {
return 1;
- } else if (is_digit(*this_str)) {
- if (!is_digit(*that_str)) {
+ } else if (is_digit(*p_this_str)) {
+ if (!is_digit(*p_that_str)) {
return -1;
}
- signed char ret = natural_cmp_common(this_str, that_str);
+ signed char ret = natural_cmp_common(p_this_str, p_that_str);
if (ret) {
return ret;
}
- } else if (is_digit(*that_str)) {
+ } else if (is_digit(*p_that_str)) {
return 1;
} else {
- if (*this_str < *that_str) { // If current character in this is less, we are less.
+ if (*p_this_str < *p_that_str) { // If current character in this is less, we are less.
return -1;
- } else if (*this_str > *that_str) { // If current character in this is greater, we are greater.
+ } else if (*p_this_str > *p_that_str) { // If current character in this is greater, we are greater.
return 1;
}
- this_str++;
- that_str++;
+ p_this_str++;
+ p_that_str++;
}
}
- if (*that_str) {
+ if (*p_that_str) {
return -1;
}
}
@@ -980,52 +977,56 @@ signed char String::naturalcasecmp_to(const String &p_str) const {
return 0;
}
-signed char String::naturalnocasecmp_to(const String &p_str) const {
+signed char String::naturalcasecmp_to(const String &p_str) const {
const char32_t *this_str = get_data();
const char32_t *that_str = p_str.get_data();
- if (this_str && that_str) {
- while (*this_str == '.' || *that_str == '.') {
- if (*this_str++ != '.') {
+ return naturalcasecmp_to_base(this_str, that_str);
+}
+
+static _FORCE_INLINE_ signed char naturalnocasecmp_to_base(const char32_t *p_this_str, const char32_t *p_that_str) {
+ if (p_this_str && p_that_str) {
+ while (*p_this_str == '.' || *p_that_str == '.') {
+ if (*p_this_str++ != '.') {
return 1;
}
- if (*that_str++ != '.') {
+ if (*p_that_str++ != '.') {
return -1;
}
- if (!*that_str) {
+ if (!*p_that_str) {
return 1;
}
- if (!*this_str) {
+ if (!*p_this_str) {
return -1;
}
}
- while (*this_str) {
- if (!*that_str) {
+ while (*p_this_str) {
+ if (!*p_that_str) {
return 1;
- } else if (is_digit(*this_str)) {
- if (!is_digit(*that_str)) {
+ } else if (is_digit(*p_this_str)) {
+ if (!is_digit(*p_that_str)) {
return -1;
}
- signed char ret = natural_cmp_common(this_str, that_str);
+ signed char ret = natural_cmp_common(p_this_str, p_that_str);
if (ret) {
return ret;
}
- } else if (is_digit(*that_str)) {
+ } else if (is_digit(*p_that_str)) {
return 1;
} else {
- if (_find_upper(*this_str) < _find_upper(*that_str)) { // If current character in this is less, we are less.
+ if (_find_upper(*p_this_str) < _find_upper(*p_that_str)) { // If current character in this is less, we are less.
return -1;
- } else if (_find_upper(*this_str) > _find_upper(*that_str)) { // If current character in this is greater, we are greater.
+ } else if (_find_upper(*p_this_str) > _find_upper(*p_that_str)) { // If current character in this is greater, we are greater.
return 1;
}
- this_str++;
- that_str++;
+ p_this_str++;
+ p_that_str++;
}
}
- if (*that_str) {
+ if (*p_that_str) {
return -1;
}
}
@@ -1033,6 +1034,53 @@ signed char String::naturalnocasecmp_to(const String &p_str) const {
return 0;
}
+signed char String::naturalnocasecmp_to(const String &p_str) const {
+ const char32_t *this_str = get_data();
+ const char32_t *that_str = p_str.get_data();
+
+ return naturalnocasecmp_to_base(this_str, that_str);
+}
+
+static _FORCE_INLINE_ signed char file_cmp_common(const char32_t *&r_this_str, const char32_t *&r_that_str) {
+ // Compare leading `_` sequences.
+ while ((*r_this_str == '_' && *r_that_str) || (*r_this_str && *r_that_str == '_')) {
+ // Sort `_` lower than everything except `.`
+ if (*r_this_str != '_') {
+ return *r_this_str == '.' ? -1 : 1;
+ } else if (*r_that_str != '_') {
+ return *r_that_str == '.' ? 1 : -1;
+ }
+ r_this_str++;
+ r_that_str++;
+ }
+
+ return 0;
+}
+
+signed char String::filecasecmp_to(const String &p_str) const {
+ const char32_t *this_str = get_data();
+ const char32_t *that_str = p_str.get_data();
+
+ signed char ret = file_cmp_common(this_str, that_str);
+ if (ret) {
+ return ret;
+ }
+
+ return naturalcasecmp_to_base(this_str, that_str);
+}
+
+signed char String::filenocasecmp_to(const String &p_str) const {
+ const char32_t *this_str = get_data();
+ const char32_t *that_str = p_str.get_data();
+
+ signed char ret = file_cmp_common(this_str, that_str);
+ if (ret) {
+ return ret;
+ }
+
+ return naturalnocasecmp_to_base(this_str, that_str);
+}
+
const char32_t *String::get_data() const {
static const char32_t zero = 0;
return size() ? &operator[](0) : &zero;
@@ -1822,7 +1870,7 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) {
bool decode_failed = false;
{
const char *ptrtmp = p_utf8;
- const char *ptrtmp_limit = &p_utf8[p_len];
+ const char *ptrtmp_limit = p_len >= 0 ? &p_utf8[p_len] : nullptr;
int skip = 0;
uint8_t c_start = 0;
while (ptrtmp != ptrtmp_limit && *ptrtmp) {
@@ -2062,12 +2110,12 @@ CharString String::utf8() const {
String String::utf16(const char16_t *p_utf16, int p_len) {
String ret;
- ret.parse_utf16(p_utf16, p_len);
+ ret.parse_utf16(p_utf16, p_len, true);
return ret;
}
-Error String::parse_utf16(const char16_t *p_utf16, int p_len) {
+Error String::parse_utf16(const char16_t *p_utf16, int p_len, bool p_default_little_endian) {
if (!p_utf16) {
return ERR_INVALID_DATA;
}
@@ -2077,8 +2125,12 @@ Error String::parse_utf16(const char16_t *p_utf16, int p_len) {
int cstr_size = 0;
int str_size = 0;
+#ifdef BIG_ENDIAN_ENABLED
+ bool byteswap = p_default_little_endian;
+#else
+ bool byteswap = !p_default_little_endian;
+#endif
/* HANDLE BOM (Byte Order Mark) */
- bool byteswap = false; // assume correct endianness if no BOM found
if (p_len < 0 || p_len >= 1) {
bool has_bom = false;
if (uint16_t(p_utf16[0]) == 0xfeff) { // correct BOM, read as is
@@ -2099,7 +2151,7 @@ Error String::parse_utf16(const char16_t *p_utf16, int p_len) {
bool decode_error = false;
{
const char16_t *ptrtmp = p_utf16;
- const char16_t *ptrtmp_limit = &p_utf16[p_len];
+ const char16_t *ptrtmp_limit = p_len >= 0 ? &p_utf16[p_len] : nullptr;
uint32_t c_prev = 0;
bool skip = false;
while (ptrtmp != ptrtmp_limit && *ptrtmp) {
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 0fb72fccd2..693df6dcba 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -265,6 +265,9 @@ public:
signed char nocasecmp_to(const String &p_str) const;
signed char naturalcasecmp_to(const String &p_str) const;
signed char naturalnocasecmp_to(const String &p_str) const;
+ // Special sorting for file names. Names starting with `_` are put before all others except those starting with `.`, otherwise natural comparison is used.
+ signed char filecasecmp_to(const String &p_str) const;
+ signed char filenocasecmp_to(const String &p_str) const;
const char32_t *get_data() const;
/* standard size stuff */
@@ -390,7 +393,7 @@ public:
static String utf8(const char *p_utf8, int p_len = -1);
Char16String utf16() const;
- Error parse_utf16(const char16_t *p_utf16, int p_len = -1);
+ Error parse_utf16(const char16_t *p_utf16, int p_len = -1, bool p_default_little_endian = true);
static String utf16(const char16_t *p_utf16, int p_len = -1);
static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */
@@ -499,6 +502,12 @@ struct NaturalNoCaseComparator {
}
};
+struct FileNoCaseComparator {
+ bool operator()(const String &p_a, const String &p_b) const {
+ return p_a.filenocasecmp_to(p_b) < 0;
+ }
+};
+
template <typename L, typename R>
_FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
while (true) {
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 6478297fd1..e0047e0782 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -104,6 +104,22 @@ public:
return false;
}
+ U erase_multiple_unordered(const T &p_val) {
+ U from = 0;
+ U occurrences = 0;
+ while (true) {
+ int64_t idx = find(p_val, from);
+
+ if (idx == -1) {
+ break;
+ }
+ remove_at_unordered(idx);
+ from = idx;
+ occurrences++;
+ }
+ return occurrences;
+ }
+
void invert() {
for (U i = 0; i < count / 2; i++) {
SWAP(data[i], data[count - i - 1]);
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index 32c410463b..9c52db3345 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -296,6 +296,7 @@ public:
_FORCE_INLINE_ constexpr BitField(T p_value) { value = (int64_t)p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
+ _FORCE_INLINE_ BitField<T> operator^(const BitField<T> &p_b) const { return BitField<T>(value ^ p_b.value); }
};
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 89c22c05dd..155a5b2781 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1417,7 +1417,7 @@ void Variant::_clear_internal() {
}
}
-Variant::operator signed int() const {
+Variant::operator int64_t() const {
switch (type) {
case NIL:
return 0;
@@ -1435,7 +1435,7 @@ Variant::operator signed int() const {
}
}
-Variant::operator unsigned int() const {
+Variant::operator int32_t() const {
switch (type) {
case NIL:
return 0;
@@ -1453,7 +1453,7 @@ Variant::operator unsigned int() const {
}
}
-Variant::operator int64_t() const {
+Variant::operator int16_t() const {
switch (type) {
case NIL:
return 0;
@@ -1471,7 +1471,7 @@ Variant::operator int64_t() const {
}
}
-Variant::operator uint64_t() const {
+Variant::operator int8_t() const {
switch (type) {
case NIL:
return 0;
@@ -1489,18 +1489,7 @@ Variant::operator uint64_t() const {
}
}
-Variant::operator ObjectID() const {
- if (type == INT) {
- return ObjectID(_data._int);
- } else if (type == OBJECT) {
- return _get_obj().id;
- } else {
- return ObjectID();
- }
-}
-
-#ifdef NEED_LONG_INT
-Variant::operator signed long() const {
+Variant::operator uint64_t() const {
switch (type) {
case NIL:
return 0;
@@ -1516,11 +1505,9 @@ Variant::operator signed long() const {
return 0;
}
}
-
- return 0;
}
-Variant::operator unsigned long() const {
+Variant::operator uint32_t() const {
switch (type) {
case NIL:
return 0;
@@ -1536,12 +1523,9 @@ Variant::operator unsigned long() const {
return 0;
}
}
-
- return 0;
}
-#endif
-Variant::operator signed short() const {
+Variant::operator uint16_t() const {
switch (type) {
case NIL:
return 0;
@@ -1559,7 +1543,7 @@ Variant::operator signed short() const {
}
}
-Variant::operator unsigned short() const {
+Variant::operator uint8_t() const {
switch (type) {
case NIL:
return 0;
@@ -1577,44 +1561,18 @@ Variant::operator unsigned short() const {
}
}
-Variant::operator signed char() const {
- switch (type) {
- case NIL:
- return 0;
- case BOOL:
- return _data._bool ? 1 : 0;
- case INT:
- return _data._int;
- case FLOAT:
- return _data._float;
- case STRING:
- return operator String().to_int();
- default: {
- return 0;
- }
- }
-}
-
-Variant::operator unsigned char() const {
- switch (type) {
- case NIL:
- return 0;
- case BOOL:
- return _data._bool ? 1 : 0;
- case INT:
- return _data._int;
- case FLOAT:
- return _data._float;
- case STRING:
- return operator String().to_int();
- default: {
- return 0;
- }
+Variant::operator ObjectID() const {
+ if (type == INT) {
+ return ObjectID(_data._int);
+ } else if (type == OBJECT) {
+ return _get_obj().id;
+ } else {
+ return ObjectID();
}
}
Variant::operator char32_t() const {
- return operator unsigned int();
+ return operator uint32_t();
}
Variant::operator float() const {
@@ -2420,57 +2378,44 @@ Variant::Variant(bool p_bool) {
_data._bool = p_bool;
}
-Variant::Variant(signed int p_int) {
+Variant::Variant(int64_t p_int64) {
type = INT;
- _data._int = p_int;
+ _data._int = p_int64;
}
-Variant::Variant(unsigned int p_int) {
+Variant::Variant(int32_t p_int32) {
type = INT;
- _data._int = p_int;
+ _data._int = p_int32;
}
-#ifdef NEED_LONG_INT
-
-Variant::Variant(signed long p_int) {
- type = INT;
- _data._int = p_int;
-}
-
-Variant::Variant(unsigned long p_int) {
- type = INT;
- _data._int = p_int;
-}
-#endif
-
-Variant::Variant(int64_t p_int) {
+Variant::Variant(int16_t p_int16) {
type = INT;
- _data._int = p_int;
+ _data._int = p_int16;
}
-Variant::Variant(uint64_t p_int) {
+Variant::Variant(int8_t p_int8) {
type = INT;
- _data._int = p_int;
+ _data._int = p_int8;
}
-Variant::Variant(signed short p_short) {
+Variant::Variant(uint64_t p_uint64) {
type = INT;
- _data._int = p_short;
+ _data._int = p_uint64;
}
-Variant::Variant(unsigned short p_short) {
+Variant::Variant(uint32_t p_uint32) {
type = INT;
- _data._int = p_short;
+ _data._int = p_uint32;
}
-Variant::Variant(signed char p_char) {
+Variant::Variant(uint16_t p_uint16) {
type = INT;
- _data._int = p_char;
+ _data._int = p_uint16;
}
-Variant::Variant(unsigned char p_char) {
+Variant::Variant(uint8_t p_uint8) {
type = INT;
- _data._int = p_char;
+ _data._int = p_uint8;
}
Variant::Variant(float p_float) {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index e8eec8171b..fc4030ac5a 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -355,19 +355,14 @@ public:
const Variant &operator[](const Variant &p_key) const = delete;
operator bool() const;
- operator signed int() const;
- operator unsigned int() const; // this is the real one
- operator signed short() const;
- operator unsigned short() const;
- operator signed char() const;
- operator unsigned char() const;
- //operator long unsigned int() const;
operator int64_t() const;
+ operator int32_t() const;
+ operator int16_t() const;
+ operator int8_t() const;
operator uint64_t() const;
-#ifdef NEED_LONG_INT
- operator signed long() const;
- operator unsigned long() const;
-#endif
+ operator uint32_t() const;
+ operator uint16_t() const;
+ operator uint8_t() const;
operator ObjectID() const;
@@ -430,18 +425,14 @@ public:
Object *get_validated_object_with_check(bool &r_previously_freed) const;
Variant(bool p_bool);
- Variant(signed int p_int); // real one
- Variant(unsigned int p_int);
-#ifdef NEED_LONG_INT
- Variant(signed long p_long); // real one
- Variant(unsigned long p_long);
-#endif
- Variant(signed short p_short); // real one
- Variant(unsigned short p_short);
- Variant(signed char p_char); // real one
- Variant(unsigned char p_char);
- Variant(int64_t p_int); // real one
- Variant(uint64_t p_int);
+ Variant(int64_t p_int64);
+ Variant(int32_t p_int32);
+ Variant(int16_t p_int16);
+ Variant(int8_t p_int8);
+ Variant(uint64_t p_uint64);
+ Variant(uint32_t p_uint32);
+ Variant(uint16_t p_uint16);
+ Variant(uint8_t p_uint8);
Variant(float p_float);
Variant(double p_double);
Variant(const ObjectID &p_id);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 5f04c42536..ba7c44e405 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1644,6 +1644,8 @@ static void _register_variant_builtin_methods() {
bind_string_method(nocasecmp_to, sarray("to"), varray());
bind_string_method(naturalcasecmp_to, sarray("to"), varray());
bind_string_method(naturalnocasecmp_to, sarray("to"), varray());
+ bind_string_method(filecasecmp_to, sarray("to"), varray());
+ bind_string_method(filenocasecmp_to, sarray("to"), varray());
bind_string_method(length, sarray(), varray());
bind_string_method(substr, sarray("from", "len"), varray(-1));
bind_string_method(get_slice, sarray("delimiter", "slice"), varray());
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 60ae09c6f1..dcf4b287d1 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -230,18 +230,20 @@ public:
};
#define register_string_op(m_op_type, m_op_code) \
- do { \
+ if constexpr (true) { \
register_op<m_op_type<String, String>>(m_op_code, Variant::STRING, Variant::STRING); \
register_op<m_op_type<String, StringName>>(m_op_code, Variant::STRING, Variant::STRING_NAME); \
register_op<m_op_type<StringName, String>>(m_op_code, Variant::STRING_NAME, Variant::STRING); \
register_op<m_op_type<StringName, StringName>>(m_op_code, Variant::STRING_NAME, Variant::STRING_NAME); \
- } while (false)
+ } else \
+ ((void)0)
#define register_string_modulo_op(m_class, m_type) \
- do { \
+ if constexpr (true) { \
register_op<OperatorEvaluatorStringFormat<String, m_class>>(Variant::OP_MODULE, Variant::STRING, m_type); \
register_op<OperatorEvaluatorStringFormat<StringName, m_class>>(Variant::OP_MODULE, Variant::STRING_NAME, m_type); \
- } while (false)
+ } else \
+ ((void)0)
void Variant::_register_variant_operators() {
memset(operator_return_type_table, 0, sizeof(operator_return_type_table));