summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/engine.cpp50
-rw-r--r--core/config/engine.h15
-rw-r--r--core/config/project_settings.cpp63
-rw-r--r--core/config/project_settings.h5
-rw-r--r--core/core_bind.cpp168
-rw-r--r--core/core_bind.h40
-rw-r--r--core/core_constants.cpp2
-rw-r--r--core/extension/extension_api_dump.cpp16
-rw-r--r--core/extension/gdnative_interface.h10
-rw-r--r--core/extension/native_extension.cpp6
-rw-r--r--core/input/godotcontrollerdb.txt50
-rw-r--r--core/input/input.cpp11
-rw-r--r--core/input/input.h20
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/input/input_event.cpp14
-rw-r--r--core/input/input_event.h2
-rw-r--r--core/input/input_map.cpp9
-rw-r--r--core/input/input_map.h7
-rw-r--r--core/io/dir_access.cpp14
-rw-r--r--core/io/dir_access.h2
-rw-r--r--core/io/file_access.cpp4
-rw-r--r--core/io/file_access.h1
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/http_client_tcp.cpp4
-rw-r--r--core/io/image_loader.cpp6
-rw-r--r--core/io/image_loader.h9
-rw-r--r--core/io/ip.cpp17
-rw-r--r--core/io/ip.h9
-rw-r--r--core/io/json.cpp23
-rw-r--r--core/io/json.h3
-rw-r--r--core/io/resource.cpp40
-rw-r--r--core/io/resource.h1
-rw-r--r--core/io/resource_format_binary.cpp6
-rw-r--r--core/io/resource_importer.cpp2
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/io/resource_uid.cpp2
-rw-r--r--core/math/a_star.cpp6
-rw-r--r--core/math/a_star.h4
-rw-r--r--core/math/a_star_grid_2d.cpp589
-rw-r--r--core/math/a_star_grid_2d.h178
-rw-r--r--core/math/audio_frame.h2
-rw-r--r--core/math/basis.cpp61
-rw-r--r--core/math/basis.h3
-rw-r--r--core/math/math_funcs.h99
-rw-r--r--core/math/projection.cpp8
-rw-r--r--core/math/projection.h2
-rw-r--r--core/math/quaternion.cpp56
-rw-r--r--core/math/quaternion.h1
-rw-r--r--core/math/transform_3d.cpp13
-rw-r--r--core/math/transform_3d.h1
-rw-r--r--core/math/vector2.h8
-rw-r--r--core/math/vector3.cpp16
-rw-r--r--core/math/vector3.h11
-rw-r--r--core/math/vector4.cpp9
-rw-r--r--core/math/vector4.h1
-rw-r--r--core/object/class_db.cpp4
-rw-r--r--core/object/object.cpp90
-rw-r--r--core/object/object.h69
-rw-r--r--core/object/ref_counted.cpp3
-rw-r--r--core/object/script_language.cpp13
-rw-r--r--core/object/script_language.h14
-rw-r--r--core/object/script_language_extension.cpp1
-rw-r--r--core/object/script_language_extension.h13
-rw-r--r--core/os/keyboard.h44
-rw-r--r--core/os/os.cpp50
-rw-r--r--core/os/os.h8
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--core/string/translation.cpp8
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/ustring.cpp193
-rw-r--r--core/string/ustring.h7
-rw-r--r--core/variant/variant.cpp8
-rw-r--r--core/variant/variant_call.cpp11
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_utility.cpp65
75 files changed, 1662 insertions, 649 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index e1da9eb44e..94db3612b4 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -33,7 +33,10 @@
#include "core/authors.gen.h"
#include "core/config/project_settings.h"
#include "core/donors.gen.h"
+#include "core/io/json.h"
#include "core/license.gen.h"
+#include "core/os/os.h"
+#include "core/variant/typed_array.h"
#include "core/version.h"
void Engine::set_physics_ticks_per_second(int p_ips) {
@@ -134,8 +137,8 @@ Dictionary Engine::get_author_info() const {
return dict;
}
-Array Engine::get_copyright_info() const {
- Array components;
+TypedArray<Dictionary> Engine::get_copyright_info() const {
+ TypedArray<Dictionary> components;
for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) {
const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index];
Dictionary component_dict;
@@ -188,11 +191,11 @@ String Engine::get_architecture_name() const {
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
return "x86_32";
-#elif defined(__aarch64__) || defined(_M_ARM64)
+#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
return "arm64";
-#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__)
- return "armv7";
+#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__) || defined(_M_ARM)
+ return "arm32";
#elif defined(__riscv)
#if __riscv_xlen == 8
@@ -307,6 +310,43 @@ Engine::Engine() {
singleton = this;
}
+void Engine::startup_begin() {
+ startup_benchmark_total_from = OS::get_singleton()->get_ticks_usec();
+}
+
+void Engine::startup_benchmark_begin_measure(const String &p_what) {
+ startup_benchmark_section = p_what;
+ startup_benchmark_from = OS::get_singleton()->get_ticks_usec();
+}
+void Engine::startup_benchmark_end_measure() {
+ uint64_t total = OS::get_singleton()->get_ticks_usec() - startup_benchmark_from;
+ double total_f = double(total) / double(1000000);
+
+ startup_benchmark_json[startup_benchmark_section] = total_f;
+}
+
+void Engine::startup_dump(const String &p_to_file) {
+ uint64_t total = OS::get_singleton()->get_ticks_usec() - startup_benchmark_total_from;
+ double total_f = double(total) / double(1000000);
+ startup_benchmark_json["total_time"] = total_f;
+
+ if (!p_to_file.is_empty()) {
+ Ref<FileAccess> f = FileAccess::open(p_to_file, FileAccess::WRITE);
+ if (f.is_valid()) {
+ Ref<JSON> json;
+ json.instantiate();
+ f->store_string(json->stringify(startup_benchmark_json, "\t", false, true));
+ }
+ } else {
+ List<Variant> keys;
+ startup_benchmark_json.get_key_list(&keys);
+ print_line("STARTUP BENCHMARK:");
+ for (const Variant &K : keys) {
+ print_line("\t-", K, ": ", startup_benchmark_json[K], +" sec.");
+ }
+ }
+}
+
Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) :
name(p_name),
ptr(p_ptr),
diff --git a/core/config/engine.h b/core/config/engine.h
index 649be23717..121fd4d541 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -36,6 +36,9 @@
#include "core/templates/list.h"
#include "core/templates/vector.h"
+template <typename T>
+class TypedArray;
+
class Engine {
public:
struct Singleton {
@@ -79,6 +82,11 @@ private:
String write_movie_path;
String shader_cache_path;
+ Dictionary startup_benchmark_json;
+ String startup_benchmark_section;
+ uint64_t startup_benchmark_from = 0;
+ uint64_t startup_benchmark_total_from = 0;
+
public:
static Engine *get_singleton();
@@ -134,7 +142,7 @@ public:
Dictionary get_version_info() const;
Dictionary get_author_info() const;
- Array get_copyright_info() const;
+ TypedArray<Dictionary> get_copyright_info() const;
Dictionary get_donor_info() const;
Dictionary get_license_info() const;
String get_license_text() const;
@@ -151,6 +159,11 @@ public:
bool is_validation_layers_enabled() const;
int32_t get_gpu_index() const;
+ void startup_begin();
+ void startup_benchmark_begin_measure(const String &p_what);
+ void startup_benchmark_end_measure();
+ void startup_dump(const String &p_to_file);
+
Engine();
virtual ~Engine() {}
};
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 5c4bcc687a..74c06123e1 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -72,7 +72,7 @@ String ProjectSettings::get_safe_project_name() const {
}
String ProjectSettings::get_imported_files_path() const {
- return get_project_data_path().plus_file("imported");
+ return get_project_data_path().path_join("imported");
}
// Returns the features that a project must have when opened with this build of Godot.
@@ -157,12 +157,12 @@ String ProjectSettings::localize_path(const String &p_path) const {
// in an absolute path that just happens to contain this string but points to a
// different folder (e.g. "/my/project" as resource_path would be contained in
// "/my/project_data", even though the latter is not part of res://.
- // `plus_file("")` is an easy way to ensure we have a trailing '/'.
- const String res_path = resource_path.plus_file("");
+ // `path_join("")` is an easy way to ensure we have a trailing '/'.
+ const String res_path = resource_path.path_join("");
// DirAccess::get_current_dir() is not guaranteed to return a path that with a trailing '/',
// so we must make sure we have it as well in order to compare with 'res_path'.
- cwd = cwd.plus_file("");
+ cwd = cwd.path_join("");
if (!cwd.begins_with(res_path)) {
return p_path;
@@ -442,6 +442,15 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
* If nothing was found, error out.
*/
Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
+ if (!OS::get_singleton()->get_resource_dir().is_empty()) {
+ // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
+ // If the OS would rather use a specific location, then it will not be empty.
+ resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
+ if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
+ resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
+ }
+ }
+
// If looking for files in a network client, use it directly
if (FileAccessNetworkClient::get_singleton()) {
@@ -463,7 +472,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (err == OK && !p_ignore_override) {
// Load override from location of the main pack
// Optional, we don't mind if it fails
- _load_settings_text(p_main_pack.get_base_dir().plus_file("override.cfg"));
+ _load_settings_text(p_main_pack.get_base_dir().path_join("override.cfg"));
}
return err;
}
@@ -491,14 +500,14 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
#ifdef MACOS_ENABLED
if (!found) {
// Attempt to load PCK from macOS .app bundle resources.
- found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_filename + ".pck"));
+ found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"));
}
#endif
if (!found) {
// Try to load data pack at the location of the executable.
// As mentioned above, we have two potential names to attempt.
- found = _load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"));
+ found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck")) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"));
}
if (!found) {
@@ -514,7 +523,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Load overrides from the PCK and the executable location.
// Optional, we don't mind if either fails.
_load_settings_text("res://override.cfg");
- _load_settings_text(exec_path.get_base_dir().plus_file("override.cfg"));
+ _load_settings_text(exec_path.get_base_dir().path_join("override.cfg"));
}
return err;
}
@@ -524,13 +533,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// (Only Android -when reading from pck- and iOS use this.)
if (!OS::get_singleton()->get_resource_dir().is_empty()) {
- // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
- // If the OS would rather use a specific location, then it will not be empty.
- resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
- if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
- resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
- }
-
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
@@ -554,10 +556,10 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Set the resource path early so things can be resolved when loading.
resource_path = current_dir;
resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
- err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
+ err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary"));
if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
- _load_settings_text(current_dir.plus_file("override.cfg"));
+ _load_settings_text(current_dir.path_join("override.cfg"));
found = true;
break;
}
@@ -683,7 +685,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
// If we're loading a project.godot from source code, we can operate some
// ProjectSettings conversions if need be.
_convert_to_last_version(config_version);
- last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
return OK;
}
ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
@@ -762,9 +764,9 @@ void ProjectSettings::clear(const String &p_name) {
}
Error ProjectSettings::save() {
- Error error = save_custom(get_resource_path().plus_file("project.godot"));
+ Error error = save_custom(get_resource_path().path_join("project.godot"));
if (error == OK) {
- last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
}
return error;
}
@@ -909,7 +911,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
// Check for the existence of a csproj file.
- if (FileAccess::exists(get_resource_path().plus_file(get_safe_project_name() + ".csproj"))) {
+ if (FileAccess::exists(get_resource_path().path_join(get_safe_project_name() + ".csproj"))) {
// If there is a csproj file, add the C# feature if it doesn't already exist.
if (!project_features.has("C#")) {
project_features.append("C#");
@@ -1070,7 +1072,7 @@ bool ProjectSettings::is_using_datapack() const {
return using_datapack;
}
-bool ProjectSettings::property_can_revert(const String &p_name) {
+bool ProjectSettings::_property_can_revert(const StringName &p_name) const {
if (!props.has(p_name)) {
return false;
}
@@ -1078,12 +1080,13 @@ bool ProjectSettings::property_can_revert(const String &p_name) {
return props[p_name].initial != props[p_name].variant;
}
-Variant ProjectSettings::property_get_revert(const String &p_name) {
+bool ProjectSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (!props.has(p_name)) {
- return Variant();
+ return false;
}
- return props[p_name].initial;
+ r_property = props[p_name].initial;
+ return true;
}
void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) {
@@ -1134,8 +1137,6 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save);
ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::_load_resource_pack, DEFVAL(true), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ProjectSettings::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ProjectSettings::property_get_revert);
ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
}
@@ -1183,10 +1184,14 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
- GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1024);
+ // The default window size is tuned to:
+ // - Have a 16:9 aspect ratio,
+ // - Have both dimensions divisible by 8 to better play along with video recording,
+ // - Be displayable correctly in windowed mode on a 1366×768 display (tested on Windows 10 with default settings).
+ GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1152);
custom_prop_info["display/window/size/viewport_width"] = PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
- GLOBAL_DEF_BASIC("display/window/size/viewport_height", 600);
+ GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index c3992a4db2..c845120a26 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -102,6 +102,8 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
static ProjectSettings *singleton;
@@ -147,9 +149,6 @@ public:
void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
bool get_ignore_value_in_docs(const String &p_name) const;
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
-
String get_project_data_dir_name() const;
String get_project_data_path() const;
String get_resource_path() const;
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 630bd68e65..9daf58cb71 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -39,6 +39,7 @@
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
#include "core/os/keyboard.h"
+#include "core/variant/typed_array.h"
namespace core_bind {
@@ -436,118 +437,6 @@ bool OS::is_stdout_verbose() const {
return ::OS::get_singleton()->is_stdout_verbose();
}
-void OS::dump_memory_to_file(const String &p_file) {
- ::OS::get_singleton()->dump_memory_to_file(p_file.utf8().get_data());
-}
-
-struct OSCoreBindImg {
- String path;
- Size2 size;
- int fmt = 0;
- ObjectID id;
- int vram = 0;
- bool operator<(const OSCoreBindImg &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; }
-};
-
-void OS::print_all_textures_by_size() {
- List<OSCoreBindImg> imgs;
- uint64_t total = 0;
- {
- List<Ref<Resource>> rsrc;
- ResourceCache::get_cached_resources(&rsrc);
-
- for (Ref<Resource> &res : rsrc) {
- if (!res->is_class("Texture")) {
- continue;
- }
-
- Size2 size = res->call("get_size");
- int fmt = res->call("get_format");
-
- OSCoreBindImg img;
- img.size = size;
- img.fmt = fmt;
- img.path = res->get_path();
- img.vram = Image::get_image_data_size(img.size.width, img.size.height, Image::Format(img.fmt));
- img.id = res->get_instance_id();
- total += img.vram;
- imgs.push_back(img);
- }
- }
-
- imgs.sort();
-
- if (imgs.size() == 0) {
- print_line("No textures seem used in this project.");
- } else {
- print_line("Textures currently in use, sorted by VRAM usage:\n"
- "Path - VRAM usage (Dimensions)");
- }
-
- for (const OSCoreBindImg &img : imgs) {
- print_line(vformat("%s - %s %s",
- img.path,
- String::humanize_size(img.vram),
- img.size));
- }
-
- print_line(vformat("Total VRAM usage: %s.", String::humanize_size(total)));
-}
-
-void OS::print_resources_by_type(const Vector<String> &p_types) {
- ERR_FAIL_COND_MSG(p_types.size() == 0,
- "At least one type should be provided to print resources by type.");
-
- print_line(vformat("Resources currently in use for the following types: %s", p_types));
-
- RBMap<String, int> type_count;
- List<Ref<Resource>> resources;
- ResourceCache::get_cached_resources(&resources);
-
- for (const Ref<Resource> &r : resources) {
- bool found = false;
-
- for (int i = 0; i < p_types.size(); i++) {
- if (r->is_class(p_types[i])) {
- found = true;
- }
- }
- if (!found) {
- continue;
- }
-
- if (!type_count.has(r->get_class())) {
- type_count[r->get_class()] = 0;
- }
-
- type_count[r->get_class()]++;
-
- print_line(vformat("%s: %s", r->get_class(), r->get_path()));
-
- List<StringName> metas;
- r->get_meta_list(&metas);
- for (const StringName &meta : metas) {
- print_line(vformat(" %s: %s", meta, r->get_meta(meta)));
- }
- }
-
- for (const KeyValue<String, int> &E : type_count) {
- print_line(vformat("%s count: %d", E.key, E.value));
- }
-}
-
-void OS::print_all_resources(const String &p_to_file) {
- ::OS::get_singleton()->print_all_resources(p_to_file);
-}
-
-void OS::print_resources_in_use(bool p_short) {
- ::OS::get_singleton()->print_resources_in_use(p_short);
-}
-
-void OS::dump_resources_to_file(const String &p_file) {
- ::OS::get_singleton()->dump_resources_to_file(p_file.utf8().get_data());
-}
-
Error OS::move_to_trash(const String &p_path) const {
return ::OS::get_singleton()->move_to_trash(p_path);
}
@@ -666,11 +555,6 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_debug_build"), &OS::is_debug_build);
- ClassDB::bind_method(D_METHOD("dump_memory_to_file", "file"), &OS::dump_memory_to_file);
- ClassDB::bind_method(D_METHOD("dump_resources_to_file", "file"), &OS::dump_resources_to_file);
- ClassDB::bind_method(D_METHOD("print_resources_in_use", "short"), &OS::print_resources_in_use, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("print_all_resources", "tofile"), &OS::print_all_resources, DEFVAL(""));
-
ClassDB::bind_method(D_METHOD("get_static_memory_usage"), &OS::get_static_memory_usage);
ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &OS::get_static_memory_peak_usage);
@@ -682,9 +566,6 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cache_dir"), &OS::get_cache_dir);
ClassDB::bind_method(D_METHOD("get_unique_id"), &OS::get_unique_id);
- ClassDB::bind_method(D_METHOD("print_all_textures_by_size"), &OS::print_all_textures_by_size);
- ClassDB::bind_method(D_METHOD("print_resources_by_type", "types"), &OS::print_resources_by_type);
-
ClassDB::bind_method(D_METHOD("get_keycode_string", "code"), &OS::get_keycode_string);
ClassDB::bind_method(D_METHOD("is_keycode_unicode", "code"), &OS::is_keycode_unicode);
ClassDB::bind_method(D_METHOD("find_keycode_from_string", "string"), &OS::find_keycode_from_string);
@@ -818,7 +699,7 @@ Vector<Point2> Geometry2D::convex_hull(const Vector<Point2> &p_points) {
return ::Geometry2D::convex_hull(p_points);
}
-Array Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::merge_polygons(p_polygon_a, p_polygon_b);
Array ret;
@@ -829,10 +710,10 @@ Array Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vecto
return ret;
}
-Array Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::clip_polygons(p_polygon_a, p_polygon_b);
- Array ret;
+ TypedArray<PackedVector2Array> ret;
for (int i = 0; i < polys.size(); ++i) {
ret.push_back(polys[i]);
@@ -840,7 +721,7 @@ Array Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector
return ret;
}
-Array Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polygons(p_polygon_a, p_polygon_b);
Array ret;
@@ -851,7 +732,7 @@ Array Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const V
return ret;
}
-Array Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::exclude_polygons(p_polygon_a, p_polygon_b);
Array ret;
@@ -862,7 +743,7 @@ Array Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vec
return ret;
}
-Array Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+TypedArray<PackedVector2Array> Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
Vector<Vector<Point2>> polys = ::Geometry2D::clip_polyline_with_polygon(p_polyline, p_polygon);
Array ret;
@@ -873,7 +754,7 @@ Array Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline,
return ret;
}
-Array Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+TypedArray<PackedVector2Array> Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polyline_with_polygon(p_polyline, p_polygon);
Array ret;
@@ -884,7 +765,7 @@ Array Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyl
return ret;
}
-Array Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
+TypedArray<PackedVector2Array> Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
Vector<Vector<Point2>> polys = ::Geometry2D::offset_polygon(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type));
Array ret;
@@ -895,7 +776,7 @@ Array Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delt
return ret;
}
-Array Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
+TypedArray<PackedVector2Array> Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
Vector<Vector<Point2>> polys = ::Geometry2D::offset_polyline(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type), ::Geometry2D::PolyEndType(p_end_type));
Array ret;
@@ -988,16 +869,19 @@ Geometry3D *Geometry3D::get_singleton() {
return singleton;
}
-Vector<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
- return ::Geometry3D::build_box_planes(p_extents);
+TypedArray<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
+ Variant ret = ::Geometry3D::build_box_planes(p_extents);
+ return ret;
}
-Vector<Plane> Geometry3D::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) {
- return ::Geometry3D::build_cylinder_planes(p_radius, p_height, p_sides, p_axis);
+TypedArray<Plane> Geometry3D::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) {
+ Variant ret = ::Geometry3D::build_cylinder_planes(p_radius, p_height, p_sides, p_axis);
+ return ret;
}
-Vector<Plane> Geometry3D::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
- return ::Geometry3D::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis);
+TypedArray<Plane> Geometry3D::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
+ Variant ret = ::Geometry3D::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis);
+ return ret;
}
Vector<Vector3> Geometry3D::get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2) {
@@ -2022,10 +1906,10 @@ Dictionary ClassDB::get_signal(StringName p_class, StringName p_signal) const {
}
}
-Array ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const {
List<MethodInfo> signals;
::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : signals) {
ret.push_back(E.operator Dictionary());
@@ -2034,10 +1918,10 @@ Array ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const
return ret;
}
-Array ClassDB::get_property_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::get_property_list(StringName p_class, bool p_no_inheritance) const {
List<PropertyInfo> plist;
::ClassDB::get_property_list(p_class, &plist, p_no_inheritance);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const PropertyInfo &E : plist) {
ret.push_back(E.operator Dictionary());
}
@@ -2066,10 +1950,10 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe
return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
}
-Array ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const {
List<MethodInfo> methods;
::ClassDB::get_method_list(p_class, &methods, p_no_inheritance);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : methods) {
#ifdef DEBUG_METHODS_ENABLED
@@ -2254,7 +2138,7 @@ Dictionary Engine::get_author_info() const {
return ::Engine::get_singleton()->get_author_info();
}
-Array Engine::get_copyright_info() const {
+TypedArray<Dictionary> Engine::get_copyright_info() const {
return ::Engine::get_singleton()->get_copyright_info();
}
diff --git a/core/core_bind.h b/core/core_bind.h
index 79230bd685..cd382d2915 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -45,6 +45,8 @@
#include "core/templates/safe_refcount.h"
class MainLoop;
+template <typename T>
+class TypedArray;
namespace core_bind {
@@ -199,14 +201,6 @@ public:
String get_model_name() const;
- void dump_memory_to_file(const String &p_file);
- void dump_resources_to_file(const String &p_file);
-
- void print_resources_in_use(bool p_short = false);
- void print_all_resources(const String &p_to_file);
- void print_all_textures_by_size();
- void print_resources_by_type(const Vector<String> &p_types);
-
bool is_debug_build() const;
String get_unique_id() const;
@@ -301,14 +295,14 @@ public:
OPERATION_XOR
};
// 2D polygon boolean operations.
- Array merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
- Array clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
- Array intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
- Array exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
+ TypedArray<PackedVector2Array> merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
+ TypedArray<PackedVector2Array> clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
+ TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
+ TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
// 2D polyline vs polygon operations.
- Array clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
- Array intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
+ TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
+ TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
// 2D offset polygons/polylines.
enum PolyJoinType {
@@ -323,8 +317,8 @@ public:
END_SQUARE,
END_ROUND
};
- Array offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
- Array offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
+ TypedArray<PackedVector2Array> offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
+ TypedArray<PackedVector2Array> offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
Dictionary make_atlas(const Vector<Size2> &p_rects);
@@ -341,9 +335,9 @@ protected:
public:
static Geometry3D *get_singleton();
- Vector<Plane> build_box_planes(const Vector3 &p_extents);
- Vector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
- Vector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
+ TypedArray<Plane> build_box_planes(const Vector3 &p_extents);
+ TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
+ TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2);
Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
@@ -602,15 +596,15 @@ public:
bool has_signal(StringName p_class, StringName p_signal) const;
Dictionary get_signal(StringName p_class, StringName p_signal) const;
- Array get_signal_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> get_signal_list(StringName p_class, bool p_no_inheritance = false) const;
- Array get_property_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> get_property_list(StringName p_class, bool p_no_inheritance = false) const;
Variant get_property(Object *p_object, const StringName &p_property) const;
Error set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
bool has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false) const;
- Array get_method_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> get_method_list(StringName p_class, bool p_no_inheritance = false) const;
PackedStringArray get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
bool has_integer_constant(const StringName &p_class, const StringName &p_name) const;
@@ -661,7 +655,7 @@ public:
Dictionary get_version_info() const;
Dictionary get_author_info() const;
- Array get_copyright_info() const;
+ TypedArray<Dictionary> get_copyright_info() const;
Dictionary get_donor_info() const;
Dictionary get_license_info() const;
String get_license_text() const;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index dc0ab72a86..c4d83d4765 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -612,6 +612,8 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE);
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 867b1fc637..5cf951a93c 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -52,6 +52,9 @@ static String get_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_BITFIELD))) {
return String("bitfield::") + String(p_info.class_name);
}
+ if (p_info.type == Variant::INT && (p_info.usage & PROPERTY_USAGE_ARRAY)) {
+ return "int";
+ }
if (p_info.class_name != StringName()) {
return p_info.class_name;
}
@@ -88,6 +91,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
}
const uint32_t vec3_elems = 3;
+ const uint32_t vec4_elems = 4;
const uint32_t ptrsize_32 = 4;
const uint32_t ptrsize_64 = 8;
static const char *build_config_name[4] = { "float_32", "float_64", "double_32", "double_64" };
@@ -138,7 +142,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
{ Variant::AABB, (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(double), (vec3_elems * 2) * sizeof(double) },
{ Variant::BASIS, (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
{ Variant::TRANSFORM3D, (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(double), (vec3_elems * 4) * sizeof(double) },
- { Variant::PROJECTION, 4 * 4 * sizeof(float), 4 * 4 * sizeof(float), 4 * 4 * sizeof(double), 4 * 4 * sizeof(double) },
+ { Variant::PROJECTION, (vec4_elems * 4) * sizeof(float), (vec4_elems * 4) * sizeof(float), (vec4_elems * 4) * sizeof(double), (vec4_elems * 4) * sizeof(double) },
{ Variant::COLOR, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float) },
{ Variant::STRING_NAME, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::NODE_PATH, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
@@ -284,6 +288,10 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
{ Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) },
{ Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 },
{ Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
+ { Variant::PROJECTION, "x", 0, 0, 0, 0 },
+ { Variant::PROJECTION, "y", vec4_elems * sizeof(float), vec4_elems * sizeof(float), vec4_elems * sizeof(double), vec4_elems * sizeof(double) },
+ { Variant::PROJECTION, "z", vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(double), vec4_elems * 2 * sizeof(double) },
+ { Variant::PROJECTION, "w", vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(double), vec4_elems * 3 * sizeof(double) },
{ Variant::COLOR, "r", 0, 0, 0, 0 },
{ Variant::COLOR, "g", sizeof(float), sizeof(float), sizeof(float), sizeof(float) },
{ Variant::COLOR, "b", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) },
@@ -840,12 +848,16 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
List<PropertyInfo> property_list;
ClassDB::get_property_list(class_name, &property_list, true);
for (const PropertyInfo &F : property_list) {
- if (F.usage & PROPERTY_USAGE_CATEGORY || F.usage & PROPERTY_USAGE_GROUP || F.usage & PROPERTY_USAGE_SUBGROUP) {
+ if (F.usage & PROPERTY_USAGE_CATEGORY || F.usage & PROPERTY_USAGE_GROUP || F.usage & PROPERTY_USAGE_SUBGROUP || (F.type == Variant::NIL && F.usage & PROPERTY_USAGE_ARRAY)) {
continue; //not real properties
}
if (F.name.begins_with("_")) {
continue; //hidden property
}
+ if (F.name.find("/") >= 0) {
+ // Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector.
+ continue;
+ }
StringName property_name = F.name;
Dictionary d2;
d2["type"] = get_type_name(F);
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 041a6e5112..cb2adcb562 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -222,6 +222,8 @@ typedef struct {
typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list);
+typedef GDNativeBool (*GDNativeExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name);
+typedef GDNativeBool (*GDNativeExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr p_out);
typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
@@ -237,6 +239,8 @@ typedef struct {
GDNativeExtensionClassGet get_func;
GDNativeExtensionClassGetPropertyList get_property_list_func;
GDNativeExtensionClassFreePropertyList free_property_list_func;
+ GDNativeExtensionClassPropertyCanRevert property_can_revert_func;
+ GDNativeExtensionClassPropertyGetRevert property_get_revert_func;
GDNativeExtensionClassNotification notification_func;
GDNativeExtensionClassToString to_string_func;
GDNativeExtensionClassReference reference_func;
@@ -309,6 +313,9 @@ typedef const GDNativePropertyInfo *(*GDNativeExtensionScriptInstanceGetProperty
typedef void (*GDNativeExtensionScriptInstanceFreePropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativePropertyInfo *p_list);
typedef GDNativeVariantType (*GDNativeExtensionScriptInstanceGetPropertyType)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeBool *r_is_valid);
+typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyCanRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name);
+typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyGetRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
+
typedef GDNativeObjectPtr (*GDNativeExtensionScriptInstanceGetOwner)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef void (*GDNativeExtensionScriptInstancePropertyStateAdd)(const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value, void *p_userdata);
typedef void (*GDNativeExtensionScriptInstanceGetPropertyState)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeExtensionScriptInstancePropertyStateAdd p_add_func, void *p_userdata);
@@ -343,6 +350,9 @@ typedef struct {
GDNativeExtensionScriptInstanceFreePropertyList free_property_list_func;
GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
+ GDNativeExtensionScriptInstancePropertyCanRevert property_can_revert_func;
+ GDNativeExtensionScriptInstancePropertyGetRevert property_get_revert_func;
+
GDNativeExtensionScriptInstanceGetOwner get_owner_func;
GDNativeExtensionScriptInstanceGetPropertyState get_property_state_func;
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index a085df874e..6418da2235 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -36,7 +36,7 @@
#include "core/os/os.h"
String NativeExtension::get_extension_list_config_file() {
- return ProjectSettings::get_singleton()->get_project_data_path().plus_file("extension_list.cfg");
+ return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
}
class NativeExtensionMethodBind : public MethodBind {
@@ -156,6 +156,8 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
extension->native_extension.get = p_extension_funcs->get_func;
extension->native_extension.get_property_list = p_extension_funcs->get_property_list_func;
extension->native_extension.free_property_list = p_extension_funcs->free_property_list_func;
+ extension->native_extension.property_can_revert = p_extension_funcs->property_can_revert_func;
+ extension->native_extension.property_get_revert = p_extension_funcs->property_get_revert_func;
extension->native_extension.notification = p_extension_funcs->notification_func;
extension->native_extension.to_string = p_extension_funcs->to_string_func;
extension->native_extension.reference = p_extension_funcs->reference_func;
@@ -419,7 +421,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
}
if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
- library_path = p_path.get_base_dir().plus_file(library_path);
+ library_path = p_path.get_base_dir().path_join(library_path);
}
Ref<NativeExtension> lib;
diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index 7f3570729a..b2a6160c6c 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -7,31 +7,31 @@ __XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftst
# Android
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
-# Javascript
-standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a6,righttrigger:a7,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Javascript,
-Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Javascript,
-Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Javascript,
-MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript
-Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Javascript
-Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript
-Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript
-Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript
-Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Javascript
+# Web
+standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a6,righttrigger:a7,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Web,
+Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Web,
+Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Web,
+MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
+Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Web
+Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
+Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
+Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
+Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
# UWP
__UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 617e31d008..1390a0a7fa 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -766,9 +766,6 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con
return rel_warped;
}
-void Input::iteration(float p_step) {
-}
-
void Input::action_press(const StringName &p_action, float p_strength) {
Action action;
@@ -973,11 +970,9 @@ void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
if (map.type == TYPE_BUTTON) {
bool pressed = map.value > 0.5;
- if (pressed == joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) {
- // Button already pressed or released; so ignore.
- return;
+ if (pressed != joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) {
+ _button_event(p_device, (JoyButton)map.index, pressed);
}
- _button_event(p_device, (JoyButton)map.index, pressed);
// Ensure opposite D-Pad button is also released.
switch ((JoyButton)map.index) {
@@ -1128,7 +1123,7 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, J
value = -value;
}
if (binding.input.axis.range == FULL_AXIS ||
- (binding.input.axis.range == POSITIVE_HALF_AXIS && value > 0) ||
+ (binding.input.axis.range == POSITIVE_HALF_AXIS && value >= 0) ||
(binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) {
event.type = binding.outputType;
float shifted_positive_value = 0;
diff --git a/core/input/input.h b/core/input/input.h
index 3ad8c91ddf..a07174b887 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -114,6 +114,15 @@ private:
int mouse_from_touch_index = -1;
+ struct VibrationInfo {
+ float weak_magnitude;
+ float strong_magnitude;
+ float duration; // Duration in seconds
+ uint64_t timestamp;
+ };
+
+ HashMap<int, VibrationInfo> joy_vibration;
+
struct VelocityTrack {
uint64_t last_tick = 0;
Vector2 velocity;
@@ -226,15 +235,6 @@ private:
EventDispatchFunc event_dispatch_function = nullptr;
protected:
- struct VibrationInfo {
- float weak_magnitude;
- float strong_magnitude;
- float duration; // Duration in seconds
- uint64_t timestamp;
- };
-
- HashMap<int, VibrationInfo> joy_vibration;
-
static void _bind_methods();
public:
@@ -295,8 +295,6 @@ public:
void action_press(const StringName &p_action, float p_strength = 1.f);
void action_release(const StringName &p_action);
- void iteration(float p_step);
-
void set_emulate_touch_from_mouse(bool p_emulate);
bool is_emulating_touch_from_mouse() const;
void ensure_touch_mouse_raised();
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
index c0dac26f02..16f125ff38 100644
--- a/core/input/input_builders.py
+++ b/core/input/input_builders.py
@@ -50,7 +50,7 @@ def make_default_controller_mappings(target, source, env):
"Mac OS X": "#ifdef MACOS_ENABLED",
"Android": "#if defined(__ANDROID__)",
"iOS": "#ifdef IOS_ENABLED",
- "Javascript": "#ifdef JAVASCRIPT_ENABLED",
+ "Web": "#ifdef WEB_ENABLED",
"UWP": "#ifdef UWP_ENABLED",
}
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 8ad2193fca..3f02d80c26 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -274,24 +274,24 @@ void InputEventWithModifiers::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_pressed"), "set_command_pressed", "is_command_pressed");
}
-void InputEventWithModifiers::_validate_property(PropertyInfo &property) const {
+void InputEventWithModifiers::_validate_property(PropertyInfo &p_property) const {
if (store_command) {
// If we only want to Store "Command".
#ifdef APPLE_STYLE_KEYS
// Don't store "Meta" on Mac.
- if (property.name == "meta_pressed") {
- property.usage ^= PROPERTY_USAGE_STORAGE;
+ if (p_property.name == "meta_pressed") {
+ p_property.usage ^= PROPERTY_USAGE_STORAGE;
}
#else
// Don't store "Ctrl".
- if (property.name == "ctrl_pressed") {
- property.usage ^= PROPERTY_USAGE_STORAGE;
+ if (p_property.name == "ctrl_pressed") {
+ p_property.usage ^= PROPERTY_USAGE_STORAGE;
}
#endif
} else {
// We don't want to store command, only ctrl or meta (on mac).
- if (property.name == "command_pressed") {
- property.usage ^= PROPERTY_USAGE_STORAGE;
+ if (p_property.name == "command_pressed") {
+ p_property.usage ^= PROPERTY_USAGE_STORAGE;
}
}
}
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 59a2df497c..6cfc031c8a 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -128,7 +128,7 @@ class InputEventWithModifiers : public InputEventFromWindow {
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_store_command(bool p_enabled);
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 942c5248df..702e257fb4 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -34,6 +34,7 @@
#include "core/input/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
+#include "core/variant/typed_array.h"
InputMap *InputMap::singleton = nullptr;
@@ -99,8 +100,8 @@ void InputMap::erase_action(const StringName &p_action) {
input_map.erase(p_action);
}
-Array InputMap::_get_actions() {
- Array ret;
+TypedArray<StringName> InputMap::_get_actions() {
+ TypedArray<StringName> ret;
List<StringName> actions = get_actions();
if (actions.is_empty()) {
return ret;
@@ -190,8 +191,8 @@ void InputMap::action_erase_events(const StringName &p_action) {
input_map[p_action].inputs.clear();
}
-Array InputMap::_action_get_events(const StringName &p_action) {
- Array ret;
+TypedArray<InputEvent> InputMap::_action_get_events(const StringName &p_action) {
+ TypedArray<InputEvent> ret;
const List<Ref<InputEvent>> *al = action_get_events(p_action);
if (al) {
for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) {
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 2400a4a3f7..414a06b2f1 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -36,6 +36,9 @@
#include "core/object/object.h"
#include "core/templates/hash_map.h"
+template <typename T>
+class TypedArray;
+
class InputMap : public Object {
GDCLASS(InputMap, Object);
@@ -60,8 +63,8 @@ private:
List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const;
- Array _action_get_events(const StringName &p_action);
- Array _get_actions();
+ TypedArray<InputEvent> _action_get_events(const StringName &p_action);
+ TypedArray<StringName> _get_actions();
protected:
static void _bind_methods();
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index f82d6f077f..bed41b8d89 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -106,7 +106,7 @@ static Error _erase_recursive(DirAccess *da) {
if (err) {
return err;
}
- err = da->remove(da->get_current_dir().plus_file(E));
+ err = da->remove(da->get_current_dir().path_join(E));
if (err) {
return err;
}
@@ -116,7 +116,7 @@ static Error _erase_recursive(DirAccess *da) {
}
for (const String &E : files) {
- Error err = da->remove(da->get_current_dir().plus_file(E));
+ Error err = da->remove(da->get_current_dir().path_join(E));
if (err) {
return err;
}
@@ -138,7 +138,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
if (p_dir.is_relative_path()) {
//append current
- full_dir = get_current_dir().plus_file(p_dir);
+ full_dir = get_current_dir().path_join(p_dir);
} else {
full_dir = p_dir;
@@ -172,7 +172,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
String curpath = base;
for (int i = 0; i < subdirs.size(); i++) {
- curpath = curpath.plus_file(subdirs[i]);
+ curpath = curpath.path_join(subdirs[i]);
Error err = make_dir(curpath);
if (err != OK && err != ERR_ALREADY_EXISTS) {
ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath);
@@ -354,8 +354,8 @@ Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod
String n = get_next();
while (!n.is_empty()) {
if (n != "." && n != "..") {
- if (p_copy_links && is_link(get_current_dir().plus_file(n))) {
- create_link(read_link(get_current_dir().plus_file(n)), p_to + n);
+ if (p_copy_links && is_link(get_current_dir().path_join(n))) {
+ create_link(read_link(get_current_dir().path_join(n)), p_to + n);
} else if (current_is_dir()) {
dirs.push_back(n);
} else {
@@ -364,7 +364,7 @@ Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod
list_dir_end();
return ERR_BUG;
}
- Error err = copy(get_current_dir().plus_file(n), p_to + rel_path, p_chmod_flags);
+ Error err = copy(get_current_dir().path_join(n), p_to + rel_path, p_chmod_flags);
if (err) {
list_dir_end();
return err;
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index d5318dfb45..2469c2a080 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -55,7 +55,7 @@ private:
protected:
String _get_root_path() const;
- String _get_root_string() const;
+ virtual String _get_root_string() const;
AccessType get_access_type() const;
String fix_path(String p_path) const;
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 8ed3d40c22..72c00bd678 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -115,6 +115,10 @@ FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) {
return create_func[p_access];
}
+FileAccess::AccessType FileAccess::get_access_type() const {
+ return _access_type;
+}
+
String FileAccess::fix_path(const String &p_path) const {
//helper used by file accesses that use a single filesystem
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 3386800686..fc0eb95d44 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -60,6 +60,7 @@ public:
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
protected:
+ AccessType get_access_type() const;
String fix_path(const String &p_path) const;
virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file
virtual uint64_t _get_modified_time(const String &p_file) = 0;
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 595a6e9873..adae0db0f4 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -520,7 +520,7 @@ String DirAccessPack::get_current_dir(bool p_include_drive) const {
while (pd->parent) {
pd = pd->parent;
- p = pd->name.plus_file(p);
+ p = pd->name.path_join(p);
}
return "res://" + p;
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index d983d86b99..9499a6f8e3 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "http_client_tcp.h"
@@ -788,4 +788,4 @@ HTTPClientTCP::HTTPClientTCP() {
HTTPClient *(*HTTPClient::_create)() = HTTPClientTCP::_create_func;
-#endif // #ifndef JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 9cf7c9caba..d09697b951 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -44,7 +44,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
return false;
}
-Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, bool p_force_linear, float p_scale) {
+Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, uint32_t p_flags, float p_scale) {
ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "It's not a reference to a valid Image object.");
Ref<FileAccess> f = p_custom;
@@ -60,7 +60,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess>
if (!loader[i]->recognize(extension)) {
continue;
}
- Error err = loader[i]->load_image(p_image, f, p_force_linear, p_scale);
+ Error err = loader[i]->load_image(p_image, f, p_flags, p_scale);
if (err != OK) {
ERR_PRINT("Error loading image: " + p_file);
}
@@ -152,7 +152,7 @@ Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::loader[idx]->load_image(image, f, false, 1.0);
+ Error err = ImageLoader::loader[idx]->load_image(image, f);
if (err != OK) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index c91d382c25..cb64d2310e 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -44,11 +44,16 @@ class ImageFormatLoader {
friend class ResourceFormatLoaderImage;
protected:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) = 0;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags = (uint32_t)FLAG_NONE, float p_scale = 1.0) = 0;
virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
bool recognize(const String &p_extension) const;
public:
+ enum LoaderFlags {
+ FLAG_NONE = 0,
+ FLAG_FORCE_LINEAR = 1,
+ };
+
virtual ~ImageFormatLoader() {}
};
@@ -58,7 +63,7 @@ class ImageLoader {
protected:
public:
- static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), bool p_force_linear = false, float p_scale = 1.0);
+ static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), uint32_t p_flags = (uint32_t)ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
static void get_recognized_extensions(List<String> *p_extensions);
static ImageFormatLoader *recognize(const String &p_extension);
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 25e3bef5fc..a4d8dc3d5b 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -33,6 +33,7 @@
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/hash_map.h"
+#include "core/variant/typed_array.h"
VARIANT_ENUM_CAST(IP::ResolverStatus);
@@ -124,11 +125,11 @@ struct _IP_ResolverPrivate {
};
IPAddress IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
- const Array addresses = resolve_hostname_addresses(p_hostname, p_type);
- return addresses.size() ? addresses[0].operator IPAddress() : IPAddress();
+ const PackedStringArray addresses = resolve_hostname_addresses(p_hostname, p_type);
+ return addresses.size() ? (IPAddress)addresses[0] : IPAddress();
}
-Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
+PackedStringArray IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
List<IPAddress> res;
String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
@@ -148,7 +149,7 @@ Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
}
resolver->mutex.unlock();
- Array result;
+ PackedStringArray result;
for (int i = 0; i < res.size(); ++i) {
result.push_back(String(res[i]));
}
@@ -254,8 +255,8 @@ void IP::clear_cache(const String &p_hostname) {
}
}
-Array IP::_get_local_addresses() const {
- Array addresses;
+PackedStringArray IP::_get_local_addresses() const {
+ PackedStringArray addresses;
List<IPAddress> ip_addresses;
get_local_addresses(&ip_addresses);
for (const IPAddress &E : ip_addresses) {
@@ -265,8 +266,8 @@ Array IP::_get_local_addresses() const {
return addresses;
}
-Array IP::_get_local_interfaces() const {
- Array results;
+TypedArray<Dictionary> IP::_get_local_interfaces() const {
+ TypedArray<Dictionary> results;
HashMap<String, Interface_Info> interfaces;
get_local_interfaces(&interfaces);
for (KeyValue<String, Interface_Info> &E : interfaces) {
diff --git a/core/io/ip.h b/core/io/ip.h
index 4d83515e2b..f2d93a454d 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -34,6 +34,9 @@
#include "core/io/ip_address.h"
#include "core/os/os.h"
+template <typename T>
+class TypedArray;
+
struct _IP_ResolverPrivate;
class IP : public Object {
@@ -68,8 +71,8 @@ protected:
static IP *singleton;
static void _bind_methods();
- Array _get_local_addresses() const;
- Array _get_local_interfaces() const;
+ PackedStringArray _get_local_addresses() const;
+ TypedArray<Dictionary> _get_local_interfaces() const;
static IP *(*_create)();
@@ -82,7 +85,7 @@ public:
};
IPAddress resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
- Array resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY);
+ PackedStringArray resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY);
// async resolver hostname
ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 4c4d91f851..91500ff3d5 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -528,11 +528,6 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
return err;
}
-String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
- HashSet<const void *> markers;
- return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
-}
-
Error JSON::parse(const String &p_json_string) {
Error err = _parse_string(p_json_string, data, err_str, err_line);
if (err == Error::OK) {
@@ -541,8 +536,24 @@ Error JSON::parse(const String &p_json_string) {
return err;
}
+String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
+ Ref<JSON> jason;
+ jason.instantiate();
+ HashSet<const void *> markers;
+ return jason->_stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
+}
+
+Variant JSON::parse_string(const String &p_json_string) {
+ Ref<JSON> jason;
+ jason.instantiate();
+ Error error = jason->parse(p_json_string);
+ ERR_FAIL_COND_V_MSG(error != Error::OK, Variant(), vformat("Parse JSON failed. Error at line %d: %s", jason->get_error_line(), jason->get_error_message()));
+ return jason->get_data();
+}
+
void JSON::_bind_methods() {
- ClassDB::bind_method(D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_static_method("JSON", D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_static_method("JSON", D_METHOD("parse_string", "json_string"), &JSON::parse_string);
ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse);
ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
diff --git a/core/io/json.h b/core/io/json.h
index 6ba0a8c76b..840b1cc08a 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -81,8 +81,9 @@ protected:
static void _bind_methods();
public:
- String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
Error parse(const String &p_json_string);
+ static String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
+ static Variant parse_string(const String &p_json_string);
inline Variant get_data() const { return data; }
inline int get_error_line() const { return err_line; }
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index fec5ca5c7b..d117f86f39 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -543,43 +543,3 @@ int ResourceCache::get_cached_resource_count() {
return rc;
}
-
-void ResourceCache::dump(const char *p_file, bool p_short) {
-#ifdef DEBUG_ENABLED
- lock.lock();
-
- HashMap<String, int> type_count;
-
- Ref<FileAccess> f;
- if (p_file) {
- f = FileAccess::open(String::utf8(p_file), FileAccess::WRITE);
- ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file at path '" + String::utf8(p_file) + "'.");
- }
-
- for (KeyValue<String, Resource *> &E : resources) {
- Resource *r = E.value;
-
- if (!type_count.has(r->get_class())) {
- type_count[r->get_class()] = 0;
- }
-
- type_count[r->get_class()]++;
-
- if (!p_short) {
- if (f.is_valid()) {
- f->store_line(r->get_class() + ": " + r->get_path());
- }
- }
- }
-
- for (const KeyValue<String, int> &E : type_count) {
- if (f.is_valid()) {
- f->store_line(E.key + " count: " + itos(E.value));
- }
- }
-
- lock.unlock();
-#else
- WARN_PRINT("ResourceCache::dump only with in debug builds.");
-#endif
-}
diff --git a/core/io/resource.h b/core/io/resource.h
index a2cde87990..a76a3920be 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -167,7 +167,6 @@ public:
static void reload_externals();
static bool has(const String &p_path);
static Ref<Resource> get_ref(const String &p_path);
- static void dump(const char *p_file = nullptr, bool p_short = false);
static void get_cached_resources(List<Ref<Resource>> *p_resources);
static int get_cached_resource_count();
};
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index b731608b4f..4f1204fc48 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -421,7 +421,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().path_join(path));
}
if (remaps.find(path)) {
@@ -683,7 +683,7 @@ Error ResourceLoaderBinary::load() {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(path.get_base_dir().plus_file(external_resources[i].path));
+ path = ProjectSettings::get_singleton()->localize_path(path.get_base_dir().path_join(external_resources[i].path));
}
external_resources.write[i].path = path; //remap happens here, not on load because on load it can actually be used for filesystem dock resource remap
@@ -1329,7 +1329,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
bool relative = false;
if (!path.begins_with("res://")) {
- path = local_path.plus_file(path).simplify_path();
+ path = local_path.path_join(path).simplify_path();
relative = true;
}
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index e059fc842b..aa7f96a047 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -421,7 +421,7 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const St
}
String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const {
- return ProjectSettings::get_singleton()->get_imported_files_path().plus_file(p_for_file.get_file() + "-" + p_for_file.md5_text());
+ return ProjectSettings::get_singleton()->get_imported_files_path().path_join(p_for_file.get_file() + "-" + p_for_file.md5_text());
}
bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const {
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 274316f058..386ccb78e9 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -70,7 +70,7 @@ void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resou
}
void ResourceFormatSaver::_bind_methods() {
- GDVIRTUAL_BIND(_save, "path", "resource", "flags");
+ GDVIRTUAL_BIND(_save, "resource", "path", "flags");
GDVIRTUAL_BIND(_recognize, "resource");
GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
}
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index fc324a26da..5324c5dd84 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -39,7 +39,7 @@ static constexpr uint32_t char_count = ('z' - 'a');
static constexpr uint32_t base = char_count + ('9' - '0');
String ResourceUID::get_cache_file() {
- return ProjectSettings::get_singleton()->get_project_data_path().plus_file("uid_cache.bin");
+ return ProjectSettings::get_singleton()->get_project_data_path().path_join("uid_cache.bin");
}
String ResourceUID::id_to_text(ID p_id) const {
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 41a0848d01..b4281820e2 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -209,8 +209,8 @@ bool AStar3D::has_point(int64_t p_id) const {
return points.has(p_id);
}
-Array AStar3D::get_point_ids() {
- Array point_list;
+PackedInt64Array AStar3D::get_point_ids() {
+ PackedInt64Array point_list;
for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) {
point_list.push_back(*(it.key));
@@ -605,7 +605,7 @@ Vector<int64_t> AStar2D::get_point_connections(int64_t p_id) {
return astar.get_point_connections(p_id);
}
-Array AStar2D::get_point_ids() {
+PackedInt64Array AStar2D::get_point_ids() {
return astar.get_point_ids();
}
diff --git a/core/math/a_star.h b/core/math/a_star.h
index c1497d133f..a9e2a62bb2 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -133,7 +133,7 @@ public:
void remove_point(int64_t p_id);
bool has_point(int64_t p_id) const;
Vector<int64_t> get_point_connections(int64_t p_id);
- Array get_point_ids();
+ PackedInt64Array get_point_ids();
void set_point_disabled(int64_t p_id, bool p_disabled = true);
bool is_point_disabled(int64_t p_id) const;
@@ -183,7 +183,7 @@ public:
void remove_point(int64_t p_id);
bool has_point(int64_t p_id) const;
Vector<int64_t> get_point_connections(int64_t p_id);
- Array get_point_ids();
+ PackedInt64Array get_point_ids();
void set_point_disabled(int64_t p_id, bool p_disabled = true);
bool is_point_disabled(int64_t p_id) const;
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
new file mode 100644
index 0000000000..8db33bde6f
--- /dev/null
+++ b/core/math/a_star_grid_2d.cpp
@@ -0,0 +1,589 @@
+/*************************************************************************/
+/* a_star_grid_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "a_star_grid_2d.h"
+
+static real_t heuristic_manhattan(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ return dx + dy;
+}
+
+static real_t heuristic_euclidian(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ return (real_t)Math::sqrt(dx * dx + dy * dy);
+}
+
+static real_t heuristic_octile(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ real_t F = Math_SQRT2 - 1;
+ return (dx < dy) ? F * dx + dy : F * dy + dx;
+}
+
+static real_t heuristic_chebyshev(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ return MAX(dx, dy);
+}
+
+static real_t (*heuristics[AStarGrid2D::HEURISTIC_MAX])(const Vector2i &, const Vector2i &) = { heuristic_manhattan, heuristic_euclidian, heuristic_octile, heuristic_chebyshev };
+
+void AStarGrid2D::set_size(const Vector2i &p_size) {
+ ERR_FAIL_COND(p_size.x < 0 || p_size.y < 0);
+ if (p_size != size) {
+ size = p_size;
+ dirty = true;
+ }
+}
+
+Vector2i AStarGrid2D::get_size() const {
+ return size;
+}
+
+void AStarGrid2D::set_offset(const Vector2 &p_offset) {
+ if (!offset.is_equal_approx(p_offset)) {
+ offset = p_offset;
+ dirty = true;
+ }
+}
+
+Vector2 AStarGrid2D::get_offset() const {
+ return offset;
+}
+
+void AStarGrid2D::set_cell_size(const Vector2 &p_cell_size) {
+ if (!cell_size.is_equal_approx(p_cell_size)) {
+ cell_size = p_cell_size;
+ dirty = true;
+ }
+}
+
+Vector2 AStarGrid2D::get_cell_size() const {
+ return cell_size;
+}
+
+void AStarGrid2D::update() {
+ points.clear();
+ for (int64_t y = 0; y < size.y; y++) {
+ LocalVector<Point> line;
+ for (int64_t x = 0; x < size.x; x++) {
+ line.push_back(Point(Vector2i(x, y), offset + Vector2(x, y) * cell_size));
+ }
+ points.push_back(line);
+ }
+ dirty = false;
+}
+
+bool AStarGrid2D::is_in_bounds(int p_x, int p_y) const {
+ return p_x >= 0 && p_x < size.width && p_y >= 0 && p_y < size.height;
+}
+
+bool AStarGrid2D::is_in_boundsv(const Vector2i &p_id) const {
+ return p_id.x >= 0 && p_id.x < size.width && p_id.y >= 0 && p_id.y < size.height;
+}
+
+bool AStarGrid2D::is_dirty() const {
+ return dirty;
+}
+
+void AStarGrid2D::set_jumping_enabled(bool p_enabled) {
+ jumping_enabled = p_enabled;
+}
+
+bool AStarGrid2D::is_jumping_enabled() const {
+ return jumping_enabled;
+}
+
+void AStarGrid2D::set_diagonal_mode(DiagonalMode p_diagonal_mode) {
+ ERR_FAIL_INDEX((int)p_diagonal_mode, (int)DIAGONAL_MODE_MAX);
+ diagonal_mode = p_diagonal_mode;
+}
+
+AStarGrid2D::DiagonalMode AStarGrid2D::get_diagonal_mode() const {
+ return diagonal_mode;
+}
+
+void AStarGrid2D::set_default_heuristic(Heuristic p_heuristic) {
+ ERR_FAIL_INDEX((int)p_heuristic, (int)HEURISTIC_MAX);
+ default_heuristic = p_heuristic;
+}
+
+AStarGrid2D::Heuristic AStarGrid2D::get_default_heuristic() const {
+ return default_heuristic;
+}
+
+void AStarGrid2D::set_point_solid(const Vector2i &p_id, bool p_solid) {
+ ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set if point is disabled. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ points[p_id.y][p_id.x].solid = p_solid;
+}
+
+bool AStarGrid2D::is_point_solid(const Vector2i &p_id) const {
+ ERR_FAIL_COND_V_MSG(dirty, false, "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), false, vformat("Can't get if point is disabled. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ return points[p_id.y][p_id.x].solid;
+}
+
+AStarGrid2D::Point *AStarGrid2D::_jump(Point *p_from, Point *p_to) {
+ if (!p_to || p_to->solid) {
+ return nullptr;
+ }
+ if (p_to == end) {
+ return p_to;
+ }
+
+ int64_t from_x = p_from->id.x;
+ int64_t from_y = p_from->id.y;
+
+ int64_t to_x = p_to->id.x;
+ int64_t to_y = p_to->id.y;
+
+ int64_t dx = to_x - from_x;
+ int64_t dy = to_y - from_y;
+
+ if (diagonal_mode == DIAGONAL_MODE_ALWAYS || diagonal_mode == DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE) {
+ if (dx != 0 && dy != 0) {
+ if ((_is_walkable(to_x - dx, to_y + dy) && !_is_walkable(to_x - dx, to_y)) || (_is_walkable(to_x + dx, to_y - dy) && !_is_walkable(to_x, to_y - dy))) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x + dx, to_y)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y + dy)) != nullptr) {
+ return p_to;
+ }
+ } else {
+ if (dx != 0) {
+ if ((_is_walkable(to_x + dx, to_y + 1) && !_is_walkable(to_x, to_y + 1)) || (_is_walkable(to_x + dx, to_y - 1) && !_is_walkable(to_x, to_y - 1))) {
+ return p_to;
+ }
+ } else {
+ if ((_is_walkable(to_x + 1, to_y + dy) && !_is_walkable(to_x + 1, to_y)) || (_is_walkable(to_x - 1, to_y + dy) && !_is_walkable(to_x - 1, to_y))) {
+ return p_to;
+ }
+ }
+ }
+ if (_is_walkable(to_x + dx, to_y + dy) && (diagonal_mode == DIAGONAL_MODE_ALWAYS || (_is_walkable(to_x + dx, to_y) || _is_walkable(to_x, to_y + dy)))) {
+ return _jump(p_to, _get_point(to_x + dx, to_y + dy));
+ }
+ } else if (diagonal_mode == DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES) {
+ if (dx != 0 && dy != 0) {
+ if ((_is_walkable(to_x + dx, to_y + dy) && !_is_walkable(to_x, to_y + dy)) || !_is_walkable(to_x + dx, to_y)) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x + dx, to_y)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y + dy)) != nullptr) {
+ return p_to;
+ }
+ } else {
+ if (dx != 0) {
+ if ((_is_walkable(to_x, to_y + 1) && !_is_walkable(to_x - dx, to_y + 1)) || (_is_walkable(to_x, to_y - 1) && !_is_walkable(to_x - dx, to_y - 1))) {
+ return p_to;
+ }
+ } else {
+ if ((_is_walkable(to_x + 1, to_y) && !_is_walkable(to_x + 1, to_y - dy)) || (_is_walkable(to_x - 1, to_y) && !_is_walkable(to_x - 1, to_y - dy))) {
+ return p_to;
+ }
+ }
+ }
+ if (_is_walkable(to_x + dx, to_y + dy) && _is_walkable(to_x + dx, to_y) && _is_walkable(to_x, to_y + dy)) {
+ return _jump(p_to, _get_point(to_x + dx, to_y + dy));
+ }
+ } else { // DIAGONAL_MODE_NEVER
+ if (dx != 0) {
+ if (!_is_walkable(to_x + dx, to_y)) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y + 1)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y - 1)) != nullptr) {
+ return p_to;
+ }
+ } else {
+ if (!_is_walkable(to_x, to_y + dy)) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x + 1, to_y)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x - 1, to_y)) != nullptr) {
+ return p_to;
+ }
+ }
+ if (_is_walkable(to_x + dx, to_y + dy) && _is_walkable(to_x + dx, to_y) && _is_walkable(to_x, to_y + dy)) {
+ return _jump(p_to, _get_point(to_x + dx, to_y + dy));
+ }
+ }
+ return nullptr;
+}
+
+void AStarGrid2D::_get_nbors(Point *p_point, List<Point *> &r_nbors) {
+ bool ts0 = false, td0 = false,
+ ts1 = false, td1 = false,
+ ts2 = false, td2 = false,
+ ts3 = false, td3 = false;
+
+ Point *left = nullptr;
+ Point *right = nullptr;
+ Point *top = nullptr;
+ Point *bottom = nullptr;
+
+ Point *top_left = nullptr;
+ Point *top_right = nullptr;
+ Point *bottom_left = nullptr;
+ Point *bottom_right = nullptr;
+
+ {
+ bool has_left = false;
+ bool has_right = false;
+
+ if (p_point->id.x - 1 >= 0) {
+ left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y);
+ has_left = true;
+ }
+ if (p_point->id.x + 1 < size.width) {
+ right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y);
+ has_right = true;
+ }
+ if (p_point->id.y - 1 >= 0) {
+ top = _get_point_unchecked(p_point->id.x, p_point->id.y - 1);
+ if (has_left) {
+ top_left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y - 1);
+ }
+ if (has_right) {
+ top_right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y - 1);
+ }
+ }
+ if (p_point->id.y + 1 < size.height) {
+ bottom = _get_point_unchecked(p_point->id.x, p_point->id.y + 1);
+ if (has_left) {
+ bottom_left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y + 1);
+ }
+ if (has_right) {
+ bottom_right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y + 1);
+ }
+ }
+ }
+
+ if (top && !top->solid) {
+ r_nbors.push_back(top);
+ ts0 = true;
+ }
+ if (right && !right->solid) {
+ r_nbors.push_back(right);
+ ts1 = true;
+ }
+ if (bottom && !bottom->solid) {
+ r_nbors.push_back(bottom);
+ ts2 = true;
+ }
+ if (left && !left->solid) {
+ r_nbors.push_back(left);
+ ts3 = true;
+ }
+
+ switch (diagonal_mode) {
+ case DIAGONAL_MODE_ALWAYS: {
+ td0 = true;
+ td1 = true;
+ td2 = true;
+ td3 = true;
+ } break;
+ case DIAGONAL_MODE_NEVER: {
+ } break;
+ case DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE: {
+ td0 = ts3 || ts0;
+ td1 = ts0 || ts1;
+ td2 = ts1 || ts2;
+ td3 = ts2 || ts3;
+ } break;
+ case DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES: {
+ td0 = ts3 && ts0;
+ td1 = ts0 && ts1;
+ td2 = ts1 && ts2;
+ td3 = ts2 && ts3;
+ } break;
+ default:
+ break;
+ }
+
+ if (td0 && (top_left && !top_left->solid)) {
+ r_nbors.push_back(top_left);
+ }
+ if (td1 && (top_right && !top_right->solid)) {
+ r_nbors.push_back(top_right);
+ }
+ if (td2 && (bottom_right && !bottom_right->solid)) {
+ r_nbors.push_back(bottom_right);
+ }
+ if (td3 && (bottom_left && !bottom_left->solid)) {
+ r_nbors.push_back(bottom_left);
+ }
+}
+
+bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
+ pass++;
+
+ if (p_end_point->solid) {
+ return false;
+ }
+
+ bool found_route = false;
+
+ Vector<Point *> open_list;
+ SortArray<Point *, SortPoints> sorter;
+
+ p_begin_point->g_score = 0;
+ p_begin_point->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.
+
+ if (p == p_end_point) {
+ found_route = true;
+ break;
+ }
+
+ sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list.
+ open_list.remove_at(open_list.size() - 1);
+ p->closed_pass = pass; // Mark the point as closed.
+
+ List<Point *> nbors;
+ _get_nbors(p, nbors);
+ for (List<Point *>::Element *E = nbors.front(); E; E = E->next()) {
+ Point *e = E->get(); // The neighbour point.
+ if (jumping_enabled) {
+ e = _jump(p, e);
+ if (!e || e->closed_pass == pass) {
+ continue;
+ }
+ } else {
+ if (e->solid || e->closed_pass == pass) {
+ continue;
+ }
+ }
+
+ real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id);
+ bool new_point = false;
+
+ if (e->open_pass != pass) { // The point wasn't inside the open list.
+ e->open_pass = pass;
+ open_list.push_back(e);
+ new_point = true;
+ } else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous.
+ continue;
+ }
+
+ e->prev_point = p;
+ e->g_score = tentative_g_score;
+ e->f_score = e->g_score + _estimate_cost(e->id, p_end_point->id);
+
+ if (new_point) { // The position of the new points is already known.
+ sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
+ } else {
+ sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
+ }
+ }
+ }
+
+ return found_route;
+}
+
+real_t AStarGrid2D::_estimate_cost(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ real_t scost;
+ if (GDVIRTUAL_CALL(_estimate_cost, p_from_id, p_to_id, scost)) {
+ return scost;
+ }
+ return heuristics[default_heuristic](p_from_id, p_to_id);
+}
+
+real_t AStarGrid2D::_compute_cost(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ real_t scost;
+ if (GDVIRTUAL_CALL(_compute_cost, p_from_id, p_to_id, scost)) {
+ return scost;
+ }
+ return heuristics[default_heuristic](p_from_id, p_to_id);
+}
+
+void AStarGrid2D::clear() {
+ points.clear();
+ size = Vector2i();
+}
+
+Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ 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 out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
+
+ Point *a = _get_point(p_from_id.x, p_from_id.y);
+ Point *b = _get_point(p_to_id.x, p_to_id.y);
+
+ if (a == b) {
+ Vector<Vector2> ret;
+ ret.push_back(a->pos);
+ return ret;
+ }
+
+ Point *begin_point = a;
+ Point *end_point = b;
+
+ bool found_route = _solve(begin_point, end_point);
+ if (!found_route) {
+ return Vector<Vector2>();
+ }
+
+ Point *p = end_point;
+ int64_t pc = 1;
+ while (p != begin_point) {
+ pc++;
+ p = p->prev_point;
+ }
+
+ Vector<Vector2> path;
+ path.resize(pc);
+
+ {
+ Vector2 *w = path.ptrw();
+
+ p = end_point;
+ int64_t idx = pc - 1;
+ while (p != begin_point) {
+ w[idx--] = p->pos;
+ p = p->prev_point;
+ }
+
+ w[0] = p->pos;
+ }
+
+ return path;
+}
+
+Vector<Vector2> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ 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 out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
+
+ Point *a = _get_point(p_from_id.x, p_from_id.y);
+ Point *b = _get_point(p_to_id.x, p_to_id.y);
+
+ if (a == b) {
+ Vector<Vector2> ret;
+ ret.push_back(Vector2((float)a->id.x, (float)a->id.y));
+ return ret;
+ }
+
+ Point *begin_point = a;
+ Point *end_point = b;
+
+ bool found_route = _solve(begin_point, end_point);
+ if (!found_route) {
+ return Vector<Vector2>();
+ }
+
+ Point *p = end_point;
+ int64_t pc = 1;
+ while (p != begin_point) {
+ pc++;
+ p = p->prev_point;
+ }
+
+ Vector<Vector2> path;
+ path.resize(pc);
+
+ {
+ Vector2 *w = path.ptrw();
+
+ p = end_point;
+ int64_t idx = pc - 1;
+ while (p != begin_point) {
+ w[idx--] = Vector2((float)p->id.x, (float)p->id.y);
+ p = p->prev_point;
+ }
+
+ w[0] = p->id;
+ }
+
+ return path;
+}
+
+void AStarGrid2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &AStarGrid2D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &AStarGrid2D::get_size);
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &AStarGrid2D::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &AStarGrid2D::get_offset);
+ ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &AStarGrid2D::set_cell_size);
+ ClassDB::bind_method(D_METHOD("get_cell_size"), &AStarGrid2D::get_cell_size);
+ ClassDB::bind_method(D_METHOD("is_in_bounds", "x", "y"), &AStarGrid2D::is_in_bounds);
+ ClassDB::bind_method(D_METHOD("is_in_boundsv", "id"), &AStarGrid2D::is_in_boundsv);
+ ClassDB::bind_method(D_METHOD("is_dirty"), &AStarGrid2D::is_dirty);
+ ClassDB::bind_method(D_METHOD("update"), &AStarGrid2D::update);
+ ClassDB::bind_method(D_METHOD("set_jumping_enabled", "enabled"), &AStarGrid2D::set_jumping_enabled);
+ ClassDB::bind_method(D_METHOD("is_jumping_enabled"), &AStarGrid2D::is_jumping_enabled);
+ ClassDB::bind_method(D_METHOD("set_diagonal_mode", "mode"), &AStarGrid2D::set_diagonal_mode);
+ ClassDB::bind_method(D_METHOD("get_diagonal_mode"), &AStarGrid2D::get_diagonal_mode);
+ ClassDB::bind_method(D_METHOD("set_default_heuristic", "heuristic"), &AStarGrid2D::set_default_heuristic);
+ ClassDB::bind_method(D_METHOD("get_default_heuristic"), &AStarGrid2D::get_default_heuristic);
+ ClassDB::bind_method(D_METHOD("set_point_solid", "id", "solid"), &AStarGrid2D::set_point_solid, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("is_point_solid", "id"), &AStarGrid2D::is_point_solid);
+ ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear);
+
+ 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);
+
+ GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
+ GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size"), "set_cell_size", "get_cell_size");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "jumping_enabled"), "set_jumping_enabled", "is_jumping_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_heuristic", PROPERTY_HINT_ENUM, "Manhattan,Euclidean,Octile,Chebyshev,Max"), "set_default_heuristic", "get_default_heuristic");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "diagonal_mode", PROPERTY_HINT_ENUM, "Never,Always,At Least One Walkable,Only If No Obstacles,Max"), "set_diagonal_mode", "get_diagonal_mode");
+
+ BIND_ENUM_CONSTANT(HEURISTIC_EUCLIDEAN);
+ BIND_ENUM_CONSTANT(HEURISTIC_MANHATTAN);
+ BIND_ENUM_CONSTANT(HEURISTIC_OCTILE);
+ BIND_ENUM_CONSTANT(HEURISTIC_CHEBYSHEV);
+ BIND_ENUM_CONSTANT(HEURISTIC_MAX);
+
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_NEVER);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_MAX);
+}
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
new file mode 100644
index 0000000000..66312d10ac
--- /dev/null
+++ b/core/math/a_star_grid_2d.h
@@ -0,0 +1,178 @@
+/*************************************************************************/
+/* a_star_grid_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef A_STAR_GRID_2D_H
+#define A_STAR_GRID_2D_H
+
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/ref_counted.h"
+#include "core/object/script_language.h"
+#include "core/templates/list.h"
+#include "core/templates/local_vector.h"
+
+class AStarGrid2D : public RefCounted {
+ GDCLASS(AStarGrid2D, RefCounted);
+
+public:
+ enum DiagonalMode {
+ DIAGONAL_MODE_ALWAYS,
+ DIAGONAL_MODE_NEVER,
+ DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE,
+ DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES,
+ DIAGONAL_MODE_MAX,
+ };
+
+ enum Heuristic {
+ HEURISTIC_EUCLIDEAN,
+ HEURISTIC_MANHATTAN,
+ HEURISTIC_OCTILE,
+ HEURISTIC_CHEBYSHEV,
+ HEURISTIC_MAX,
+ };
+
+private:
+ Vector2i size;
+ Vector2 offset;
+ Vector2 cell_size = Vector2(1, 1);
+ bool dirty = false;
+
+ bool jumping_enabled = false;
+ DiagonalMode diagonal_mode = DIAGONAL_MODE_ALWAYS;
+ Heuristic default_heuristic = HEURISTIC_EUCLIDEAN;
+
+ struct Point {
+ Vector2i id;
+
+ bool solid = false;
+ Vector2 pos;
+
+ // Used for pathfinding.
+ Point *prev_point = nullptr;
+ real_t g_score = 0;
+ real_t f_score = 0;
+ uint64_t open_pass = 0;
+ uint64_t closed_pass = 0;
+
+ Point() {}
+
+ Point(const Vector2i &p_id, const Vector2 &p_pos) :
+ id(p_id), pos(p_pos) {}
+ };
+
+ struct SortPoints {
+ _FORCE_INLINE_ bool operator()(const Point *A, const Point *B) const { // Returns true when the Point A is worse than Point B.
+ if (A->f_score > B->f_score) {
+ return true;
+ } else if (A->f_score < B->f_score) {
+ return false;
+ } else {
+ return A->g_score < B->g_score; // If the f_costs are the same then prioritize the points that are further away from the start.
+ }
+ }
+ };
+
+ LocalVector<LocalVector<Point>> points;
+ Point *end = nullptr;
+
+ uint64_t pass = 1;
+
+private: // Internal routines.
+ _FORCE_INLINE_ bool _is_walkable(int64_t p_x, int64_t p_y) const {
+ if (p_x >= 0 && p_y >= 0 && p_x < size.width && p_y < size.height) {
+ return !points[p_y][p_x].solid;
+ }
+ return false;
+ }
+
+ _FORCE_INLINE_ Point *_get_point(int64_t p_x, int64_t p_y) {
+ if (p_x >= 0 && p_y >= 0 && p_x < size.width && p_y < size.height) {
+ return &points[p_y][p_x];
+ }
+ return nullptr;
+ }
+
+ _FORCE_INLINE_ Point *_get_point_unchecked(int64_t p_x, int64_t p_y) {
+ return &points[p_y][p_x];
+ }
+
+ void _get_nbors(Point *p_point, List<Point *> &r_nbors);
+ Point *_jump(Point *p_from, Point *p_to);
+ bool _solve(Point *p_begin_point, Point *p_end_point);
+
+protected:
+ static void _bind_methods();
+
+ virtual real_t _estimate_cost(const Vector2i &p_from_id, const Vector2i &p_to_id);
+ virtual real_t _compute_cost(const Vector2i &p_from_id, const Vector2i &p_to_id);
+
+ GDVIRTUAL2RC(real_t, _estimate_cost, Vector2i, Vector2i)
+ GDVIRTUAL2RC(real_t, _compute_cost, Vector2i, Vector2i)
+
+public:
+ void set_size(const Vector2i &p_size);
+ Vector2i get_size() const;
+
+ void set_offset(const Vector2 &p_offset);
+ Vector2 get_offset() const;
+
+ void set_cell_size(const Vector2 &p_cell_size);
+ Vector2 get_cell_size() const;
+
+ void update();
+
+ int get_width() const;
+ int get_height() const;
+
+ bool is_in_bounds(int p_x, int p_y) const;
+ bool is_in_boundsv(const Vector2i &p_id) const;
+ bool is_dirty() const;
+
+ void set_jumping_enabled(bool p_enabled);
+ bool is_jumping_enabled() const;
+
+ void set_diagonal_mode(DiagonalMode p_diagonal_mode);
+ DiagonalMode get_diagonal_mode() const;
+
+ void set_default_heuristic(Heuristic p_heuristic);
+ Heuristic get_default_heuristic() const;
+
+ void set_point_solid(const Vector2i &p_id, bool p_solid = true);
+ bool is_point_solid(const Vector2i &p_id) const;
+
+ void clear();
+
+ Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to);
+ Vector<Vector2> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
+};
+
+VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode);
+VARIANT_ENUM_CAST(AStarGrid2D::Heuristic);
+
+#endif // A_STAR_GRID_2D_H
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index b3d63c0094..1a80faaa12 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -48,7 +48,7 @@ static inline float undenormalise(volatile float f) {
}
static const float AUDIO_PEAK_OFFSET = 0.0000000001f;
-static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear2db(AUDIO_PEAK_OFFSET)
+static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear_to_db(AUDIO_PEAK_OFFSET)
struct AudioFrame {
//left and right samples
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index f8e7c47107..bc50d0e64c 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -749,67 +749,6 @@ Quaternion Basis::get_quaternion() const {
return Quaternion(temp[0], temp[1], temp[2], temp[3]);
}
-static const Basis _ortho_bases[24] = {
- Basis(1, 0, 0, 0, 1, 0, 0, 0, 1),
- Basis(0, -1, 0, 1, 0, 0, 0, 0, 1),
- Basis(-1, 0, 0, 0, -1, 0, 0, 0, 1),
- Basis(0, 1, 0, -1, 0, 0, 0, 0, 1),
- Basis(1, 0, 0, 0, 0, -1, 0, 1, 0),
- Basis(0, 0, 1, 1, 0, 0, 0, 1, 0),
- Basis(-1, 0, 0, 0, 0, 1, 0, 1, 0),
- Basis(0, 0, -1, -1, 0, 0, 0, 1, 0),
- Basis(1, 0, 0, 0, -1, 0, 0, 0, -1),
- Basis(0, 1, 0, 1, 0, 0, 0, 0, -1),
- Basis(-1, 0, 0, 0, 1, 0, 0, 0, -1),
- Basis(0, -1, 0, -1, 0, 0, 0, 0, -1),
- Basis(1, 0, 0, 0, 0, 1, 0, -1, 0),
- Basis(0, 0, -1, 1, 0, 0, 0, -1, 0),
- Basis(-1, 0, 0, 0, 0, -1, 0, -1, 0),
- Basis(0, 0, 1, -1, 0, 0, 0, -1, 0),
- Basis(0, 0, 1, 0, 1, 0, -1, 0, 0),
- Basis(0, -1, 0, 0, 0, 1, -1, 0, 0),
- Basis(0, 0, -1, 0, -1, 0, -1, 0, 0),
- Basis(0, 1, 0, 0, 0, -1, -1, 0, 0),
- Basis(0, 0, 1, 0, -1, 0, 1, 0, 0),
- Basis(0, 1, 0, 0, 0, 1, 1, 0, 0),
- Basis(0, 0, -1, 0, 1, 0, 1, 0, 0),
- Basis(0, -1, 0, 0, 0, -1, 1, 0, 0)
-};
-
-int Basis::get_orthogonal_index() const {
- //could be sped up if i come up with a way
- Basis orth = *this;
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- real_t v = orth[i][j];
- if (v > 0.5f) {
- v = 1.0f;
- } else if (v < -0.5f) {
- v = -1.0f;
- } else {
- v = 0;
- }
-
- orth[i][j] = v;
- }
- }
-
- for (int i = 0; i < 24; i++) {
- if (_ortho_bases[i] == orth) {
- return i;
- }
- }
-
- return 0;
-}
-
-void Basis::set_orthogonal_index(int p_index) {
- //there only exist 24 orthogonal bases in r3
- ERR_FAIL_INDEX(p_index, 24);
-
- *this = _ortho_bases[p_index];
-}
-
void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
/* checking this is a bad idea, because obtaining from scaled transform is a valid use case
#ifdef MATH_CHECKS
diff --git a/core/math/basis.h b/core/math/basis.h
index 4be325cdd2..2853947ba7 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -149,9 +149,6 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ void operator*=(const real_t p_val);
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;
- int get_orthogonal_index() const;
- void set_orthogonal_index(int p_index);
-
bool is_orthogonal() const;
bool is_diagonal() const;
bool is_rotation() const;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 53deb9bd42..cae76b182a 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -229,11 +229,11 @@ public:
return value;
}
- static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * (Math_PI / 180.0); }
- static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (float)(Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ double deg_to_rad(double p_y) { return p_y * (Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ float deg_to_rad(float p_y) { return p_y * (float)(Math_PI / 180.0); }
- static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y * (180.0 / Math_PI); }
- static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (float)(180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ double rad_to_deg(double p_y) { return p_y * (180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ float rad_to_deg(float p_y) { return p_y * (float)(180.0 / Math_PI); }
static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; }
static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; }
@@ -253,6 +253,89 @@ public:
(-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
}
+ static _ALWAYS_INLINE_ double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
+ double from_rot = fmod(p_from, Math_TAU);
+
+ double pre_diff = fmod(p_pre - from_rot, Math_TAU);
+ double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
+
+ double to_diff = fmod(p_to - from_rot, Math_TAU);
+ double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
+
+ double post_diff = fmod(p_post - to_rot, Math_TAU);
+ double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
+
+ return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
+ }
+ static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
+ float from_rot = fmod(p_from, (float)Math_TAU);
+
+ float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
+ float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
+
+ float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
+ float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
+
+ float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
+ float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
+
+ return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
+ }
+
+ static _ALWAYS_INLINE_ double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
+ double p_to_t, double p_pre_t, double p_post_t) {
+ /* Barry-Goldman method */
+ double t = Math::lerp(0.0, p_to_t, p_weight);
+ double a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t);
+ double a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t);
+ double a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t));
+ double b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t));
+ double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
+ return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
+ }
+ static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
+ float p_to_t, float p_pre_t, float p_post_t) {
+ /* Barry-Goldman method */
+ float t = Math::lerp(0.0f, p_to_t, p_weight);
+ float a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t);
+ float a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t);
+ float a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t));
+ float b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t));
+ float b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t);
+ return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t);
+ }
+
+ static _ALWAYS_INLINE_ double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
+ double p_to_t, double p_pre_t, double p_post_t) {
+ double from_rot = fmod(p_from, Math_TAU);
+
+ double pre_diff = fmod(p_pre - from_rot, Math_TAU);
+ double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
+
+ double to_diff = fmod(p_to - from_rot, Math_TAU);
+ double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
+
+ double post_diff = fmod(p_post - to_rot, Math_TAU);
+ double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
+
+ return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
+ }
+ static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
+ float p_to_t, float p_pre_t, float p_post_t) {
+ float from_rot = fmod(p_from, (float)Math_TAU);
+
+ float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
+ float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
+
+ float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
+ float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
+
+ float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
+ float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
+
+ return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
+ }
+
static _ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
/* Formula from Wikipedia article on Bezier curves. */
double omt = (1.0 - p_t);
@@ -308,11 +391,11 @@ public:
static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
- static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ double db_to_linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ float db_to_linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index edf8bf36cd..863fe6ee79 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -255,7 +255,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
}
real_t sine, cotangent, deltaZ;
- real_t radians = Math::deg2rad(p_fovy_degrees / 2.0);
+ real_t radians = Math::deg_to_rad(p_fovy_degrees / 2.0);
deltaZ = p_z_far - p_z_near;
sine = Math::sin(radians);
@@ -282,7 +282,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
real_t left, right, modeltranslation, ymax, xmax, frustumshift;
- ymax = p_z_near * tan(Math::deg2rad(p_fovy_degrees / 2.0));
+ ymax = p_z_near * tan(Math::deg_to_rad(p_fovy_degrees / 2.0));
xmax = ymax * p_aspect;
frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist;
@@ -816,7 +816,7 @@ real_t Projection::get_fov() const {
right_plane.normalize();
if ((matrix[8] == 0) && (matrix[9] == 0)) {
- return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
+ return Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
} else {
// our frustum is asymmetrical need to calculate the left planes angle separately..
Plane left_plane = Plane(matrix[3] + matrix[0],
@@ -825,7 +825,7 @@ real_t Projection::get_fov() const {
matrix[15] + matrix[12]);
left_plane.normalize();
- return Math::rad2deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x)));
+ return Math::rad_to_deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x)));
}
}
diff --git a/core/math/projection.h b/core/math/projection.h
index a3d2d7720b..f149d307b3 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -96,7 +96,7 @@ struct Projection {
Projection jitter_offseted(const Vector2 &p_offset) const;
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
- return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0);
+ return Math::rad_to_deg(Math::atan(p_aspect * Math::tan(Math::deg_to_rad(p_fovx) * 0.5)) * 2.0);
}
real_t get_z_far() const;
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index c681c60694..c836a82e37 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -112,10 +112,11 @@ Quaternion Quaternion::exp() const {
Quaternion src = *this;
Vector3 src_v = Vector3(src.x, src.y, src.z);
real_t theta = src_v.length();
- if (theta < CMP_EPSILON) {
+ src_v = src_v.normalized();
+ if (theta < CMP_EPSILON || !src_v.is_normalized()) {
return Quaternion(0, 0, 0, 1);
}
- return Quaternion(src_v.normalized(), theta);
+ return Quaternion(src_v, theta);
}
Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
@@ -233,6 +234,57 @@ Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const
return q1.slerp(q2, p_weight);
}
+Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight,
+ const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
+#endif
+ Quaternion from_q = *this;
+ Quaternion pre_q = p_pre_a;
+ Quaternion to_q = p_b;
+ Quaternion post_q = p_post_b;
+
+ // Align flip phases.
+ from_q = Basis(from_q).get_rotation_quaternion();
+ pre_q = Basis(pre_q).get_rotation_quaternion();
+ to_q = Basis(to_q).get_rotation_quaternion();
+ post_q = Basis(post_q).get_rotation_quaternion();
+
+ // Flip quaternions to shortest path if necessary.
+ bool flip1 = signbit(from_q.dot(pre_q));
+ pre_q = flip1 ? -pre_q : pre_q;
+ bool flip2 = signbit(from_q.dot(to_q));
+ to_q = flip2 ? -to_q : to_q;
+ bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q));
+ post_q = flip3 ? -post_q : post_q;
+
+ // Calc by Expmap in from_q space.
+ Quaternion ln_from = Quaternion(0, 0, 0, 0);
+ Quaternion ln_to = (from_q.inverse() * to_q).log();
+ Quaternion ln_pre = (from_q.inverse() * pre_q).log();
+ Quaternion ln_post = (from_q.inverse() * post_q).log();
+ Quaternion ln = Quaternion(0, 0, 0, 0);
+ ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ Quaternion q1 = from_q * ln.exp();
+
+ // Calc by Expmap in to_q space.
+ ln_from = (to_q.inverse() * from_q).log();
+ ln_to = Quaternion(0, 0, 0, 0);
+ ln_pre = (to_q.inverse() * pre_q).log();
+ ln_post = (to_q.inverse() * post_q).log();
+ ln = Quaternion(0, 0, 0, 0);
+ ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ Quaternion q2 = to_q * ln.exp();
+
+ // To cancel error made by Expmap ambiguity, do blends.
+ return q1.slerp(q2, p_weight);
+}
+
Quaternion::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index cb54a6f540..43d7bffcfc 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -72,6 +72,7 @@ struct _NO_DISCARD_ Quaternion {
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
+ Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
Vector3 get_axis() const;
real_t get_angle() const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index a634faca9a..2de9e81b38 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -94,9 +94,7 @@ void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, con
origin = p_eye;
}
-Transform3D Transform3D::spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const {
- /* not sure if very "efficient" but good enough? */
-
+Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
Transform3D interp;
Vector3 src_scale = basis.get_scale();
@@ -113,15 +111,6 @@ Transform3D Transform3D::spherical_interpolate_with(const Transform3D &p_transfo
return interp;
}
-Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
- Transform3D interp;
-
- interp.basis = basis.lerp(p_transform.basis, p_c);
- interp.origin = origin.lerp(p_transform.origin, p_c);
-
- return interp;
-}
-
void Transform3D::scale(const Vector3 &p_scale) {
basis.scale(p_scale);
origin *= p_scale;
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index b572e90859..c62e4a7b0e 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -103,7 +103,6 @@ struct _NO_DISCARD_ Transform3D {
void operator*=(const real_t p_val);
Transform3D operator*(const real_t p_val) const;
- Transform3D spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const;
Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const;
_FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const {
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 91d3d3a56b..caa6b226e7 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -114,6 +114,7 @@ struct _NO_DISCARD_ Vector2 {
_FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const;
+ _FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const;
@@ -270,6 +271,13 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c
return res;
}
+Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+ Vector2 res = *this;
+ res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ return res;
+}
+
Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
Vector2 res = *this;
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index d71d365053..fdbbb8cb5c 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -117,6 +117,22 @@ Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
return n.normalized();
}
+Vector2 Vector3::octahedron_tangent_encode(const float sign) const {
+ Vector2 res = this->octahedron_encode();
+ res.y = res.y * 0.5f + 0.5f;
+ res.y = sign >= 0.0f ? res.y : 1 - res.y;
+ return res;
+}
+
+Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *sign) {
+ Vector2 oct_compressed = p_oct;
+ oct_compressed.y = oct_compressed.y * 2 - 1;
+ *sign = oct_compressed.y >= 0.0f ? 1.0f : -1.0f;
+ oct_compressed.y = Math::abs(oct_compressed.y);
+ Vector3 res = Vector3::octahedron_decode(oct_compressed);
+ return res;
+}
+
Basis Vector3::outer(const Vector3 &p_with) const {
Vector3 row0(x * p_with.x, x * p_with.y, x * p_with.z);
Vector3 row1(y * p_with.x, y * p_with.y, y * p_with.z);
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 4ce01da60e..7cae6e2481 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -105,12 +105,15 @@ struct _NO_DISCARD_ Vector3 {
_FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const;
+ _FORCE_INLINE_ Vector3 cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const;
Vector2 octahedron_encode() const;
static Vector3 octahedron_decode(const Vector2 &p_oct);
+ Vector2 octahedron_tangent_encode(const float sign) const;
+ static Vector3 octahedron_tangent_decode(const Vector2 &p_oct, float *sign);
_FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const;
_FORCE_INLINE_ real_t dot(const Vector3 &p_with) const;
@@ -246,6 +249,14 @@ Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, c
return res;
}
+Vector3 Vector3::cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+ Vector3 res = *this;
+ res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.z = Math::cubic_interpolate_in_time(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ return res;
+}
+
Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const {
Vector3 res = *this;
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index 1dd5adad2b..273a111891 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -138,6 +138,15 @@ Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, c
return res;
}
+Vector4 Vector4::cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+ Vector4 res = *this;
+ res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.z = Math::cubic_interpolate_in_time(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.w = Math::cubic_interpolate_in_time(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ return res;
+}
+
Vector4 Vector4::posmod(const real_t p_mod) const {
return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod));
}
diff --git a/core/math/vector4.h b/core/math/vector4.h
index d26fe15941..17d0de18e1 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -89,6 +89,7 @@ struct _NO_DISCARD_ Vector4 {
Vector4 round() const;
Vector4 lerp(const Vector4 &p_to, const real_t p_weight) const;
Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const;
+ Vector4 cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
Vector4 posmod(const real_t p_mod) const;
Vector4 posmodv(const Vector4 &p_modv) const;
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 9790cc44e3..99b20560da 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -981,7 +981,7 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p
if (p_validator) {
// Making a copy as we may modify it.
PropertyInfo pi_mut = pi;
- p_validator->_validate_property(pi_mut);
+ p_validator->validate_property(pi_mut);
p_list->push_back(pi_mut);
} else {
p_list->push_back(pi);
@@ -1022,7 +1022,7 @@ bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_p
if (check->property_map.has(p_property)) {
PropertyInfo pinfo = check->property_map[p_property];
if (p_validator) {
- p_validator->_validate_property(pinfo);
+ p_validator->validate_property(pinfo);
}
if (r_info) {
*r_info = pinfo;
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 0fcd1c0e40..33208be539 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -38,6 +38,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "core/variant/typed_array.h"
#ifdef DEBUG_ENABLED
@@ -102,8 +103,8 @@ PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) {
return pi;
}
-Array convert_property_list(const List<PropertyInfo> *p_list) {
- Array va;
+TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) {
+ TypedArray<Dictionary> va;
for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) {
va.push_back(Dictionary(E->get()));
}
@@ -515,7 +516,61 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
}
-void Object::_validate_property(PropertyInfo &property) const {
+void Object::validate_property(PropertyInfo &p_property) const {
+ _validate_propertyv(p_property);
+}
+
+bool Object::property_can_revert(const StringName &p_name) const {
+ if (script_instance) {
+ if (script_instance->property_can_revert(p_name)) {
+ return true;
+ }
+ }
+
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+ if (_extension && _extension->property_can_revert) {
+ if (_extension->property_can_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name)) {
+ return true;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ return _property_can_revertv(p_name);
+}
+
+Variant Object::property_get_revert(const StringName &p_name) const {
+ Variant ret;
+
+ if (script_instance) {
+ if (script_instance->property_get_revert(p_name, ret)) {
+ return ret;
+ }
+ }
+
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+ if (_extension && _extension->property_get_revert) {
+ if (_extension->property_get_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
+ return ret;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ if (_property_get_revertv(p_name, ret)) {
+ return ret;
+ }
+ return Variant();
}
void Object::get_method_list(List<MethodInfo> *p_list) const {
@@ -756,7 +811,7 @@ String Object::to_string() {
_extension->to_string(_extension_instance, &ret);
return ret;
}
- return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
+ return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
}
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
@@ -858,16 +913,16 @@ void Object::remove_meta(const StringName &p_name) {
set_meta(p_name, Variant());
}
-Array Object::_get_property_list_bind() const {
+TypedArray<Dictionary> Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
get_property_list(&lpi);
return convert_property_list(&lpi);
}
-Array Object::_get_method_list_bind() const {
+TypedArray<Dictionary> Object::_get_method_list_bind() const {
List<MethodInfo> ml;
get_method_list(&ml);
- Array ret;
+ TypedArray<Dictionary> ret;
for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) {
Dictionary d = E->get();
@@ -1055,11 +1110,11 @@ void Object::_add_user_signal(const String &p_name, const Array &p_args) {
add_user_signal(mi);
}
-Array Object::_get_signal_list() const {
+TypedArray<Dictionary> Object::_get_signal_list() const {
List<MethodInfo> signal_list;
get_signal_list(&signal_list);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : signal_list) {
ret.push_back(Dictionary(E));
}
@@ -1067,11 +1122,11 @@ Array Object::_get_signal_list() const {
return ret;
}
-Array Object::_get_signal_connection_list(const StringName &p_signal) const {
+TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_signal) const {
List<Connection> conns;
get_all_signal_connections(&conns);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const Connection &c : conns) {
if (c.signal.get_name() == p_signal) {
@@ -1082,8 +1137,8 @@ Array Object::_get_signal_connection_list(const StringName &p_signal) const {
return ret;
}
-Array Object::_get_incoming_connections() const {
- Array ret;
+TypedArray<Dictionary> Object::_get_incoming_connections() const {
+ TypedArray<Dictionary> ret;
int connections_amount = connections.size();
for (int idx_conn = 0; idx_conn < connections_amount; idx_conn++) {
ret.push_back(connections[idx_conn]);
@@ -1500,10 +1555,17 @@ void Object::_bind_methods() {
BIND_OBJ_CORE_METHOD(miget);
MethodInfo plget("_get_property_list");
-
plget.return_val.type = Variant::ARRAY;
+ plget.return_val.hint = PROPERTY_HINT_ARRAY_TYPE;
+ plget.return_val.hint_string = "Dictionary";
BIND_OBJ_CORE_METHOD(plget);
+ BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_property_can_revert", PropertyInfo(Variant::STRING_NAME, "property")));
+ MethodInfo mipgr("_property_get_revert", PropertyInfo(Variant::STRING_NAME, "property"));
+ mipgr.return_val.name = "Variant";
+ mipgr.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ BIND_OBJ_CORE_METHOD(mipgr);
+
#endif
BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string"));
diff --git a/core/object/object.h b/core/object/object.h
index 35d0aaaa7d..1784c1fe70 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -45,6 +45,9 @@
#include "core/variant/callable_bind.h"
#include "core/variant/variant.h"
+template <typename T>
+class TypedArray;
+
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
@@ -91,6 +94,8 @@ enum PropertyHint {
PROPERTY_HINT_LOCALE_ID,
PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_NODE_TYPE, ///< a node object type
+ PROPERTY_HINT_HIDE_QUATERNION_EDIT, /// Only Node3D::transform should hide the quaternion editor.
+ PROPERTY_HINT_PASSWORD,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -207,7 +212,7 @@ struct PropertyInfo {
}
};
-Array convert_property_list(const List<PropertyInfo> *p_list);
+TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list);
enum MethodFlags {
METHOD_FLAG_NORMAL = 1,
@@ -294,6 +299,8 @@ struct ObjectNativeExtension {
GDNativeExtensionClassGet get;
GDNativeExtensionClassGetPropertyList get_property_list;
GDNativeExtensionClassFreePropertyList free_property_list;
+ GDNativeExtensionClassPropertyCanRevert property_can_revert;
+ GDNativeExtensionClassPropertyGetRevert property_get_revert;
GDNativeExtensionClassNotification notification;
GDNativeExtensionClassToString to_string;
GDNativeExtensionClassReference reference;
@@ -469,6 +476,37 @@ protected:
m_inherits::_get_property_listv(p_list, p_reversed); \
} \
} \
+ _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \
+ return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \
+ } \
+ virtual void _validate_propertyv(PropertyInfo &p_property) const override { \
+ m_inherits::_validate_propertyv(p_property); \
+ if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
+ _validate_property(p_property); \
+ } \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const { \
+ return (bool(Object::*)(const StringName &) const) & m_class::_property_can_revert; \
+ } \
+ virtual bool _property_can_revertv(const StringName &p_name) const override { \
+ if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \
+ if (_property_can_revert(p_name)) { \
+ return true; \
+ } \
+ } \
+ return m_inherits::_property_can_revertv(p_name); \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const { \
+ return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_property_get_revert; \
+ } \
+ virtual bool _property_get_revertv(const StringName &p_name, Variant &r_ret) const override { \
+ if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \
+ if (_property_get_revert(p_name, r_ret)) { \
+ return true; \
+ } \
+ } \
+ return m_inherits::_property_get_revertv(p_name, r_ret); \
+ } \
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \
return (void(Object::*)(int)) & m_class::_notification; \
} \
@@ -564,9 +602,9 @@ private:
void _add_user_signal(const String &p_name, const Array &p_args = Array());
bool _has_user_signal(const StringName &p_name) const;
Error _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Array _get_signal_list() const;
- Array _get_signal_connection_list(const StringName &p_signal) const;
- Array _get_incoming_connections() const;
+ TypedArray<Dictionary> _get_signal_list() const;
+ TypedArray<Dictionary> _get_signal_connection_list(const StringName &p_signal) const;
+ TypedArray<Dictionary> _get_incoming_connections() const;
void _set_bind(const StringName &p_set, const Variant &p_value);
Variant _get_bind(const StringName &p_name) const;
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
@@ -613,12 +651,18 @@ protected:
virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; };
virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; };
virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const {};
+ virtual void _validate_propertyv(PropertyInfo &p_property) const {};
+ virtual bool _property_can_revertv(const StringName &p_name) const { return false; };
+ virtual bool _property_get_revertv(const StringName &p_name, Variant &r_property) const { return false; };
virtual void _notificationv(int p_notification, bool p_reversed) {}
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_property) { return false; };
bool _get(const StringName &p_name, Variant &r_property) const { return false; };
void _get_property_list(List<PropertyInfo> *p_list) const {};
+ void _validate_property(PropertyInfo &p_property) const {};
+ bool _property_can_revert(const StringName &p_name) const { return false; };
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; };
void _notification(int p_notification) {}
_FORCE_INLINE_ static void (*_get_bind_methods())() {
@@ -633,6 +677,15 @@ protected:
_FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> *p_list) const {
return &Object::_get_property_list;
}
+ _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo &p_property) const {
+ return &Object::_validate_property;
+ }
+ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const {
+ return &Object::_property_can_revert;
+ }
+ _FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const {
+ return &Object::_property_get_revert;
+ }
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) {
return &Object::_notification;
}
@@ -650,13 +703,12 @@ protected:
}
Vector<StringName> _get_meta_list_bind() const;
- Array _get_property_list_bind() const;
- Array _get_method_list_bind() const;
+ TypedArray<Dictionary> _get_property_list_bind() const;
+ TypedArray<Dictionary> _get_method_list_bind() const;
void _clear_internal_resource_paths(const Variant &p_var);
friend class ClassDB;
- virtual void _validate_property(PropertyInfo &property) const;
void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false);
@@ -757,6 +809,9 @@ public:
Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = nullptr) const;
void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const;
+ void validate_property(PropertyInfo &p_property) const;
+ bool property_can_revert(const StringName &p_name) const;
+ Variant property_get_revert(const StringName &p_name) const;
bool has_method(const StringName &p_method) const;
void get_method_list(List<MethodInfo> *p_list) const;
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index 726e2c012c..cac2400744 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -85,7 +85,8 @@ bool RefCounted::unreference() {
_get_extension()->unreference(_get_extension_instance());
}
- die = die && _instance_binding_reference(false);
+ bool binding_ret = _instance_binding_reference(false);
+ die = die && binding_ret;
}
return die;
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index b06c2e8896..e56d2e80b9 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/variant/typed_array.h"
#include <stdint.h>
@@ -61,8 +62,8 @@ Variant Script::_get_property_default_value(const StringName &p_property) {
return ret;
}
-Array Script::_get_script_property_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_property_list() {
+ TypedArray<Dictionary> ret;
List<PropertyInfo> list;
get_script_property_list(&list);
for (const PropertyInfo &E : list) {
@@ -71,8 +72,8 @@ Array Script::_get_script_property_list() {
return ret;
}
-Array Script::_get_script_method_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_method_list() {
+ TypedArray<Dictionary> ret;
List<MethodInfo> list;
get_script_method_list(&list);
for (const MethodInfo &E : list) {
@@ -81,8 +82,8 @@ Array Script::_get_script_method_list() {
return ret;
}
-Array Script::_get_script_signal_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_signal_list() {
+ TypedArray<Dictionary> ret;
List<MethodInfo> list;
get_script_signal_list(&list);
for (const MethodInfo &E : list) {
diff --git a/core/object/script_language.h b/core/object/script_language.h
index f5f052b600..12a21150bc 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -37,6 +37,8 @@
#include "core/templates/rb_map.h"
class ScriptLanguage;
+template <typename T>
+class TypedArray;
typedef void (*ScriptEditRequestFunction)(const String &p_path);
@@ -108,9 +110,9 @@ protected:
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {}
Variant _get_property_default_value(const StringName &p_property);
- Array _get_script_property_list();
- Array _get_script_method_list();
- Array _get_script_signal_list();
+ TypedArray<Dictionary> _get_script_property_list();
+ TypedArray<Dictionary> _get_script_method_list();
+ TypedArray<Dictionary> _get_script_signal_list();
Dictionary _get_script_constant_map();
public:
@@ -171,6 +173,9 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const = 0;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const = 0;
+ virtual bool property_can_revert(const StringName &p_name) const = 0;
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const = 0;
+
virtual Object *get_owner() { return nullptr; }
virtual void get_property_state(List<Pair<StringName, Variant>> &state);
@@ -447,6 +452,9 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const override;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override;
+ virtual bool property_can_revert(const StringName &p_name) const override { return false; };
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override { return false; };
+
virtual void get_method_list(List<MethodInfo> *p_list) const override;
virtual bool has_method(const StringName &p_method) const override;
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
index 9de784ea7f..78e9038b66 100644
--- a/core/object/script_language_extension.cpp
+++ b/core/object/script_language_extension.cpp
@@ -62,6 +62,7 @@ void ScriptExtension::_bind_methods() {
GDVIRTUAL_BIND(_has_script_signal, "signal");
GDVIRTUAL_BIND(_get_script_signal_list);
+ GDVIRTUAL_BIND(_has_property_default_value, "property");
GDVIRTUAL_BIND(_get_property_default_value, "property");
GDVIRTUAL_BIND(_update_exports);
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 2869f4ad98..7e74f6a2be 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -692,6 +692,19 @@ public:
return Variant::NIL;
}
+ virtual bool property_can_revert(const StringName &p_name) const override {
+ if (native_info->property_can_revert_func) {
+ return native_info->property_can_revert_func(instance, (const GDNativeStringNamePtr)&p_name);
+ }
+ return false;
+ }
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override {
+ if (native_info->property_get_revert_func) {
+ return native_info->property_get_revert_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&r_ret);
+ }
+ return false;
+ }
+
virtual Object *get_owner() override {
if (native_info->get_owner_func) {
return (Object *)native_info->get_owner_func(instance);
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 517a53e505..29418049cb 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -329,67 +329,71 @@ enum class KeyModifierMask {
// To avoid having unnecessary operators, only define the ones that are needed.
-inline Key operator-(uint32_t a, Key b) {
+constexpr Key operator-(uint32_t a, Key b) {
return (Key)(a - (uint32_t)b);
}
-inline Key &operator-=(Key &a, int b) {
- return (Key &)((int &)a -= b);
+constexpr Key &operator-=(Key &a, int b) {
+ a = static_cast<Key>(static_cast<int>(a) - static_cast<int>(b));
+ return a;
}
-inline Key operator+(Key a, int b) {
+constexpr Key operator+(Key a, int b) {
return (Key)((int)a + (int)b);
}
-inline Key operator+(Key a, Key b) {
+constexpr Key operator+(Key a, Key b) {
return (Key)((int)a + (int)b);
}
-inline Key operator-(Key a, Key b) {
+constexpr Key operator-(Key a, Key b) {
return (Key)((int)a - (int)b);
}
-inline Key operator&(Key a, Key b) {
+constexpr Key operator&(Key a, Key b) {
return (Key)((int)a & (int)b);
}
-inline Key operator|(Key a, Key b) {
+constexpr Key operator|(Key a, Key b) {
return (Key)((int)a | (int)b);
}
-inline Key &operator|=(Key &a, Key b) {
- return (Key &)((int &)a |= (int)b);
+constexpr Key &operator|=(Key &a, Key b) {
+ a = static_cast<Key>(static_cast<int>(a) | static_cast<int>(b));
+ return a;
}
-inline Key &operator|=(Key &a, KeyModifierMask b) {
- return (Key &)((int &)a |= (int)b);
+constexpr Key &operator|=(Key &a, KeyModifierMask b) {
+ a = static_cast<Key>(static_cast<int>(a) | static_cast<int>(b));
+ return a;
}
-inline Key &operator&=(Key &a, KeyModifierMask b) {
- return (Key &)((int &)a &= (int)b);
+constexpr Key &operator&=(Key &a, KeyModifierMask b) {
+ a = static_cast<Key>(static_cast<int>(a) & static_cast<int>(b));
+ return a;
}
-inline Key operator|(Key a, KeyModifierMask b) {
+constexpr Key operator|(Key a, KeyModifierMask b) {
return (Key)((int)a | (int)b);
}
-inline Key operator&(Key a, KeyModifierMask b) {
+constexpr Key operator&(Key a, KeyModifierMask b) {
return (Key)((int)a & (int)b);
}
-inline Key operator+(KeyModifierMask a, Key b) {
+constexpr Key operator+(KeyModifierMask a, Key b) {
return (Key)((int)a + (int)b);
}
-inline Key operator|(KeyModifierMask a, Key b) {
+constexpr Key operator|(KeyModifierMask a, Key b) {
return (Key)((int)a | (int)b);
}
-inline KeyModifierMask operator+(KeyModifierMask a, KeyModifierMask b) {
+constexpr KeyModifierMask operator+(KeyModifierMask a, KeyModifierMask b) {
return (KeyModifierMask)((int)a + (int)b);
}
-inline KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) {
+constexpr KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) {
return (KeyModifierMask)((int)a | (int)b);
}
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 1358c926d1..526b31ae7e 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -159,17 +159,13 @@ int OS::get_process_id() const {
}
void OS::vibrate_handheld(int p_duration_ms) {
- WARN_PRINT("vibrate_handheld() only works with Android, iOS and HTML5");
+ WARN_PRINT("vibrate_handheld() only works with Android, iOS and Web");
}
bool OS::is_stdout_verbose() const {
return _verbose_stdout;
}
-bool OS::is_single_window() const {
- return _single_window;
-}
-
bool OS::is_stdout_debug_enabled() const {
return _debug_stdout;
}
@@ -190,50 +186,6 @@ void OS::set_stderr_enabled(bool p_enabled) {
_stderr_enabled = p_enabled;
}
-void OS::dump_memory_to_file(const char *p_file) {
- //Memory::dump_static_mem_to_file(p_file);
-}
-
-static Ref<FileAccess> _OSPRF;
-
-static void _OS_printres(Object *p_obj) {
- Resource *res = Object::cast_to<Resource>(p_obj);
- if (!res) {
- return;
- }
-
- String str = vformat("%s - %s - %s", res->to_string(), res->get_name(), res->get_path());
- if (_OSPRF.is_valid()) {
- _OSPRF->store_line(str);
- } else {
- print_line(str);
- }
-}
-
-void OS::print_all_resources(String p_to_file) {
- ERR_FAIL_COND(!p_to_file.is_empty() && _OSPRF.is_valid());
- if (!p_to_file.is_empty()) {
- Error err;
- _OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err);
- if (err != OK) {
- _OSPRF.unref();
- ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + ".");
- }
- }
-
- ObjectDB::debug_objects(_OS_printres);
-
- _OSPRF.unref();
-}
-
-void OS::print_resources_in_use(bool p_short) {
- ResourceCache::dump(nullptr, p_short);
-}
-
-void OS::dump_resources_to_file(const char *p_file) {
- ResourceCache::dump(p_file);
-}
-
int OS::get_exit_code() const {
return _exit_code;
}
diff --git a/core/os/os.h b/core/os/os.h
index 9152b797ef..0e8a2d0398 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -52,7 +52,6 @@ class OS {
int low_processor_usage_mode_sleep_usec = 10000;
bool _verbose_stdout = false;
bool _debug_stdout = false;
- bool _single_window = false;
String _local_clipboard;
int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure
bool _allow_hidpi = false;
@@ -243,17 +242,10 @@ public:
void set_stdout_enabled(bool p_enabled);
void set_stderr_enabled(bool p_enabled);
- virtual bool is_single_window() const;
-
virtual void disable_crash_handler() {}
virtual bool is_disable_crash_handler() const { return false; }
virtual void initialize_debugging() {}
- virtual void dump_memory_to_file(const char *p_file);
- virtual void dump_resources_to_file(const char *p_file);
- virtual void print_resources_in_use(bool p_short = false);
- virtual void print_all_resources(String p_to_file = "");
-
virtual uint64_t get_static_memory_usage() const;
virtual uint64_t get_static_memory_peak_usage() const;
virtual uint64_t get_free_static_memory() const;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 9ad6b0ca68..7f734201e7 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -64,6 +64,7 @@
#include "core/io/udp_server.h"
#include "core/io/xml_parser.h"
#include "core/math/a_star.h"
+#include "core/math/a_star_grid_2d.h"
#include "core/math/expression.h"
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
@@ -236,6 +237,7 @@ void register_core_types() {
GDREGISTER_ABSTRACT_CLASS(PackedDataContainerRef);
GDREGISTER_CLASS(AStar3D);
GDREGISTER_CLASS(AStar2D);
+ GDREGISTER_CLASS(AStarGrid2D);
GDREGISTER_CLASS(EncodedObjectAsID);
GDREGISTER_CLASS(RandomNumberGenerator);
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index b83b7c786f..4748f1a0cb 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -70,7 +70,7 @@ void Translation::_set_messages(const Dictionary &p_messages) {
void Translation::set_locale(const String &p_locale) {
locale = TranslationServer::get_singleton()->standardize_locale(p_locale);
- if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(this)) {
+ if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(get_locale())) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
}
}
@@ -505,11 +505,11 @@ String TranslationServer::get_locale() const {
return locale;
}
-Array TranslationServer::get_loaded_locales() const {
- Array locales;
+PackedStringArray TranslationServer::get_loaded_locales() const {
+ PackedStringArray locales;
for (const Ref<Translation> &E : translations) {
const Ref<Translation> &t = E;
- ERR_FAIL_COND_V(t.is_null(), Array());
+ ERR_FAIL_COND_V(t.is_null(), PackedStringArray());
String l = t->get_locale();
locales.push_back(l);
diff --git a/core/string/translation.h b/core/string/translation.h
index 20c6ebd5a5..3f97a8d4fc 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -145,7 +145,7 @@ public:
String get_locale_name(const String &p_locale) const;
- Array get_loaded_locales() const;
+ PackedStringArray get_loaded_locales() const;
void add_translation(const Ref<Translation> &p_translation);
void remove_translation(const Ref<Translation> &p_translation);
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index e93375bff7..d8b93998af 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -531,10 +531,12 @@ String &String::operator+=(const String &p_str) {
resize(lhs_len + rhs_len + 1);
- const char32_t *src = p_str.get_data();
+ const char32_t *src = p_str.ptr();
char32_t *dst = ptrw() + lhs_len;
- memcpy(dst, src, (rhs_len + 1) * sizeof(char32_t));
+ // Don't copy the terminating null with `memcpy` to avoid undefined behavior when string is being added to itself (it would overlap the destination).
+ memcpy(dst, src, rhs_len * sizeof(char32_t));
+ *(dst + rhs_len) = _null;
return *this;
}
@@ -968,62 +970,71 @@ const char32_t *String::get_data() const {
return size() ? &operator[](0) : &zero;
}
-String String::capitalize() const {
- String aux = this->camelcase_to_underscore(true).replace("_", " ").strip_edges();
- String cap;
- for (int i = 0; i < aux.get_slice_count(" "); i++) {
- String slice = aux.get_slicec(' ', i);
- if (slice.length() > 0) {
- slice[0] = _find_upper(slice[0]);
- if (i > 0) {
- cap += " ";
- }
- cap += slice;
- }
- }
-
- return cap;
-}
-
-String String::camelcase_to_underscore(bool lowercase) const {
+String String::_camelcase_to_underscore() const {
const char32_t *cstr = get_data();
String new_string;
int start_index = 0;
for (int i = 1; i < this->size(); i++) {
- bool is_upper = is_ascii_upper_case(cstr[i]);
- bool is_number = is_digit(cstr[i]);
+ bool is_prev_upper = is_ascii_upper_case(cstr[i - 1]);
+ bool is_prev_lower = is_ascii_lower_case(cstr[i - 1]);
+ bool is_prev_digit = is_digit(cstr[i - 1]);
- bool are_next_2_lower = false;
- bool is_next_lower = false;
- bool is_next_number = false;
- bool was_precedent_upper = is_ascii_upper_case(cstr[i - 1]);
- bool was_precedent_number = is_digit(cstr[i - 1]);
-
- if (i + 2 < this->size()) {
- are_next_2_lower = is_ascii_lower_case(cstr[i + 1]) && is_ascii_lower_case(cstr[i + 2]);
- }
+ bool is_curr_upper = is_ascii_upper_case(cstr[i]);
+ bool is_curr_lower = is_ascii_lower_case(cstr[i]);
+ bool is_curr_digit = is_digit(cstr[i]);
+ bool is_next_lower = false;
if (i + 1 < this->size()) {
is_next_lower = is_ascii_lower_case(cstr[i + 1]);
- is_next_number = is_digit(cstr[i + 1]);
}
- const bool cond_a = is_upper && !was_precedent_upper && !was_precedent_number;
- const bool cond_b = was_precedent_upper && is_upper && are_next_2_lower;
- const bool cond_c = is_number && !was_precedent_number;
- const bool can_break_number_letter = is_number && !was_precedent_number && is_next_lower;
- const bool can_break_letter_number = !is_number && was_precedent_number && (is_next_lower || is_next_number);
+ const bool cond_a = is_prev_lower && is_curr_upper; // aA
+ const bool cond_b = (is_prev_upper || is_prev_digit) && is_curr_upper && is_next_lower; // AAa, 2Aa
+ const bool cond_c = is_prev_digit && is_curr_lower && is_next_lower; // 2aa
+ const bool cond_d = (is_prev_upper || is_prev_lower) && is_curr_digit; // A2, a2
- bool should_split = cond_a || cond_b || cond_c || can_break_number_letter || can_break_letter_number;
- if (should_split) {
+ if (cond_a || cond_b || cond_c || cond_d) {
new_string += this->substr(start_index, i - start_index) + "_";
start_index = i;
}
}
new_string += this->substr(start_index, this->size() - start_index);
- return lowercase ? new_string.to_lower() : new_string;
+ return new_string.to_lower();
+}
+
+String String::capitalize() const {
+ String aux = this->_camelcase_to_underscore().replace("_", " ").strip_edges();
+ String cap;
+ for (int i = 0; i < aux.get_slice_count(" "); i++) {
+ String slice = aux.get_slicec(' ', i);
+ if (slice.length() > 0) {
+ slice[0] = _find_upper(slice[0]);
+ if (i > 0) {
+ cap += " ";
+ }
+ cap += slice;
+ }
+ }
+
+ return cap;
+}
+
+String String::to_camel_case() const {
+ String s = this->to_pascal_case();
+ if (!s.is_empty()) {
+ s[0] = _find_lower(s[0]);
+ }
+ return s;
+}
+
+String String::to_pascal_case() const {
+ return this->capitalize().replace(" ", "");
+}
+
+String String::to_snake_case() const {
+ return this->_camelcase_to_underscore().replace(" ", "_").strip_edges();
}
String String::get_with_code_lines() const {
@@ -3449,18 +3460,19 @@ String String::replacen(const String &p_key, const String &p_with) const {
String String::repeat(int p_count) const {
ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number.");
- String new_string;
- const char32_t *src = this->get_data();
-
- new_string.resize(length() * p_count + 1);
- new_string[length() * p_count] = 0;
-
- for (int i = 0; i < p_count; i++) {
- for (int j = 0; j < length(); j++) {
- new_string[i * length() + j] = src[j];
- }
- }
-
+ int len = length();
+ String new_string = *this;
+ new_string.resize(p_count * len + 1);
+
+ char32_t *dst = new_string.ptrw();
+ int offset = 1;
+ int stride = 1;
+ while (offset < p_count) {
+ memcpy(dst + offset * len, dst, stride * len * sizeof(char32_t));
+ offset += stride;
+ stride = MIN(stride * 2, p_count - offset);
+ }
+ dst[p_count * len] = _null;
return new_string;
}
@@ -4448,7 +4460,7 @@ String String::get_extension() const {
return substr(pos + 1, length());
}
-String String::plus_file(const String &p_file) const {
+String String::path_join(const String &p_file) const {
if (is_empty()) {
return p_file;
}
@@ -4664,6 +4676,71 @@ String String::sprintf(const Array &values, bool *error) const {
in_format = false;
break;
}
+ case 'v': { // Vector2/3/4/2i/3i/4i
+ if (value_index >= values.size()) {
+ return "not enough arguments for format string";
+ }
+
+ int count;
+ switch (values[value_index].get_type()) {
+ case Variant::VECTOR2:
+ case Variant::VECTOR2I: {
+ count = 2;
+ } break;
+ case Variant::VECTOR3:
+ case Variant::VECTOR3I: {
+ count = 3;
+ } break;
+ case Variant::VECTOR4:
+ case Variant::VECTOR4I: {
+ count = 4;
+ } break;
+ default: {
+ return "%v requires a vector type (Vector2/3/4/2i/3i/4i)";
+ }
+ }
+
+ Vector4 vec = values[value_index];
+ String str = "(";
+ for (int i = 0; i < count; i++) {
+ double val = vec[i];
+ // Pad decimals out.
+ String number_str = String::num(ABS(val), min_decimals).pad_decimals(min_decimals);
+
+ int initial_len = number_str.length();
+
+ // Padding. Leave room for sign later if required.
+ int pad_chars_count = val < 0 ? min_chars - 1 : min_chars;
+ String pad_char = pad_with_zeros ? String("0") : String(" ");
+ if (left_justified) {
+ number_str = number_str.rpad(pad_chars_count, pad_char);
+ } else {
+ number_str = number_str.lpad(pad_chars_count, pad_char);
+ }
+
+ // Add sign if needed.
+ if (val < 0) {
+ if (left_justified) {
+ number_str = number_str.insert(0, "-");
+ } else {
+ number_str = number_str.insert(pad_with_zeros ? 0 : number_str.length() - initial_len, "-");
+ }
+ }
+
+ // Add number to combined string
+ str += number_str;
+
+ if (i < count - 1) {
+ str += ", ";
+ }
+ }
+ str += ")";
+
+ formatted += str;
+ ++value_index;
+ in_format = false;
+ break;
+ }
case 's': { // String
if (value_index >= values.size()) {
return "not enough arguments for format string";
@@ -4756,7 +4833,7 @@ String String::sprintf(const Array &values, bool *error) const {
}
break;
}
- case '.': { // Float separator.
+ case '.': { // Float/Vector separator.
if (in_decimals) {
return "too many decimal points in format";
}
@@ -4770,8 +4847,12 @@ String String::sprintf(const Array &values, bool *error) const {
return "not enough arguments for format string";
}
- if (!values[value_index].is_num()) {
- return "* wants number";
+ Variant::Type value_type = values[value_index].get_type();
+ if (!values[value_index].is_num() &&
+ value_type != Variant::VECTOR2 && value_type != Variant::VECTOR2I &&
+ value_type != Variant::VECTOR3 && value_type != Variant::VECTOR3I &&
+ value_type != Variant::VECTOR4 && value_type != Variant::VECTOR4I) {
+ return "* wants number or vector";
}
int size = values[value_index];
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 6c3169f136..31de7cc464 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -196,6 +196,7 @@ class String {
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
+ String _camelcase_to_underscore() const;
public:
enum {
@@ -335,7 +336,9 @@ public:
static double to_float(const char32_t *p_str, const char32_t **r_end = nullptr);
String capitalize() const;
- String camelcase_to_underscore(bool lowercase = true) const;
+ String to_camel_case() const;
+ String to_pascal_case() const;
+ String to_snake_case() const;
String get_with_code_lines() const;
int get_slice_count(String p_splitter) const;
@@ -370,7 +373,7 @@ public:
String rstrip(const String &p_chars) const;
String get_extension() const;
String get_basename() const;
- String plus_file(const String &p_file) const;
+ String path_join(const String &p_file) const;
char32_t unicode_at(int p_idx) const;
void erase(int p_pos, int p_chars);
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index a5bc6c229d..b280fc9fe3 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1787,7 +1787,7 @@ String stringify_vector(const T &vec, int recursion_count) {
String Variant::stringify(int recursion_count) const {
switch (type) {
case NIL:
- return "null";
+ return "<null>";
case BOOL:
return _data._bool ? "true" : "false";
case INT:
@@ -1904,12 +1904,12 @@ String Variant::stringify(int recursion_count) const {
case OBJECT: {
if (_get_obj().obj) {
if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- return "[Freed Object]";
+ return "<Freed Object>";
}
return _get_obj().obj->to_string();
} else {
- return "[Object:null]";
+ return "<Object#null>";
}
} break;
@@ -1926,7 +1926,7 @@ String Variant::stringify(int recursion_count) const {
return "RID(" + itos(s.get_id()) + ")";
} break;
default: {
- return "[" + get_type_name(type) + "]";
+ return "<" + get_type_name(type) + ">";
}
}
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index eba12b68bb..a4bce979fe 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1506,6 +1506,9 @@ static void _register_variant_builtin_methods() {
bind_method(String, repeat, sarray("count"), varray());
bind_method(String, insert, sarray("position", "what"), varray());
bind_method(String, capitalize, sarray(), varray());
+ bind_method(String, to_camel_case, sarray(), varray());
+ bind_method(String, to_pascal_case, sarray(), varray());
+ bind_method(String, to_snake_case, sarray(), varray());
bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true));
@@ -1523,7 +1526,7 @@ static void _register_variant_builtin_methods() {
bind_method(String, rstrip, sarray("chars"), varray());
bind_method(String, get_extension, sarray(), varray());
bind_method(String, get_basename, sarray(), varray());
- bind_method(String, plus_file, sarray("file"), varray());
+ bind_method(String, path_join, sarray("file"), varray());
bind_method(String, unicode_at, sarray("at"), varray());
bind_method(String, indent, sarray("prefix"), varray());
bind_method(String, dedent, sarray(), varray());
@@ -1608,6 +1611,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, lerp, sarray("to", "weight"), varray());
bind_method(Vector2, slerp, sarray("to", "weight"), varray());
bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Vector2, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Vector2, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector2, max_axis_index, sarray(), varray());
bind_method(Vector2, min_axis_index, sarray(), varray());
@@ -1696,6 +1700,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, lerp, sarray("to", "weight"), varray());
bind_method(Vector3, slerp, sarray("to", "weight"), varray());
bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Vector3, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Vector3, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector3, move_toward, sarray("to", "delta"), varray());
bind_method(Vector3, dot, sarray("with"), varray());
@@ -1738,6 +1743,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, round, sarray(), varray());
bind_method(Vector4, lerp, sarray("to", "weight"), varray());
bind_method(Vector4, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Vector4, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Vector4, posmod, sarray("mod"), varray());
bind_method(Vector4, posmodv, sarray("modv"), varray());
bind_method(Vector4, snapped, sarray("step"), varray());
@@ -1789,6 +1795,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, slerp, sarray("to", "weight"), varray());
bind_method(Quaternion, slerpni, sarray("to", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Quaternion, spherical_cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Quaternion, get_euler, sarray(), varray());
bind_method(Quaternion, get_axis, sarray(), varray());
bind_method(Quaternion, get_angle, sarray(), varray());
@@ -1916,7 +1923,6 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, tdotx, sarray("with"), varray());
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
- bind_method(Basis, get_orthogonal_index, sarray(), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
@@ -1963,7 +1969,6 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, translated, sarray("offset"), varray());
bind_method(Transform3D, translated_local, sarray("offset"), varray());
bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
- bind_method(Transform3D, spherical_interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform3D, is_equal_approx, sarray("xform"), varray());
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 3a0b6c1bb9..d048f45737 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -162,6 +162,7 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Projection>>(sarray());
add_constructor<VariantConstructor<Projection, Projection>>(sarray("from"));
add_constructor<VariantConstructor<Projection, Transform3D>>(sarray("from"));
+ add_constructor<VariantConstructor<Projection, Vector4, Vector4, Vector4, Vector4>>(sarray("x_axis", "y_axis", "z_axis", "w_axis"));
add_constructor<VariantConstructNoArgs<Color>>(sarray());
add_constructor<VariantConstructor<Color, Color>>(sarray("from"));
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 1f1439ab24..1be17405c7 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -367,6 +367,20 @@ struct VariantUtilityFunctions {
return Math::cubic_interpolate(from, to, pre, post, weight);
}
+ static inline double cubic_interpolate_angle(double from, double to, double pre, double post, double weight) {
+ return Math::cubic_interpolate_angle(from, to, pre, post, weight);
+ }
+
+ static inline double cubic_interpolate_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t) {
+ return Math::cubic_interpolate_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
+ }
+
+ static inline double cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t) {
+ return Math::cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
+ }
+
static inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t);
}
@@ -391,20 +405,20 @@ struct VariantUtilityFunctions {
return Math::move_toward(from, to, delta);
}
- static inline double deg2rad(double angle_deg) {
- return Math::deg2rad(angle_deg);
+ static inline double deg_to_rad(double angle_deg) {
+ return Math::deg_to_rad(angle_deg);
}
- static inline double rad2deg(double angle_rad) {
- return Math::rad2deg(angle_rad);
+ static inline double rad_to_deg(double angle_rad) {
+ return Math::rad_to_deg(angle_rad);
}
- static inline double linear2db(double linear) {
- return Math::linear2db(linear);
+ static inline double linear_to_db(double linear) {
+ return Math::linear_to_db(linear);
}
- static inline double db2linear(double db) {
- return Math::db2linear(db);
+ static inline double db_to_linear(double db) {
+ return Math::db_to_linear(db);
}
static inline Variant wrap(const Variant &p_x, const Variant &p_min, const Variant &p_max, Callable::CallError &r_error) {
@@ -832,13 +846,13 @@ struct VariantUtilityFunctions {
r_error.error = Callable::CallError::CALL_OK;
}
- static inline String var2str(const Variant &p_var) {
+ static inline String var_to_str(const Variant &p_var) {
String vars;
VariantWriter::write_to_string(p_var, vars);
return vars;
}
- static inline Variant str2var(const String &p_var) {
+ static inline Variant str_to_var(const String &p_var) {
VariantParser::StreamString ss;
ss.s = p_var;
@@ -850,7 +864,7 @@ struct VariantUtilityFunctions {
return ret;
}
- static inline PackedByteArray var2bytes(const Variant &p_var) {
+ static inline PackedByteArray var_to_bytes(const Variant &p_var) {
int len;
Error err = encode_variant(p_var, nullptr, len, false);
if (err != OK) {
@@ -870,7 +884,7 @@ struct VariantUtilityFunctions {
return barr;
}
- static inline PackedByteArray var2bytes_with_objects(const Variant &p_var) {
+ static inline PackedByteArray var_to_bytes_with_objects(const Variant &p_var) {
int len;
Error err = encode_variant(p_var, nullptr, len, true);
if (err != OK) {
@@ -890,7 +904,7 @@ struct VariantUtilityFunctions {
return barr;
}
- static inline Variant bytes2var(const PackedByteArray &p_arr) {
+ static inline Variant bytes_to_var(const PackedByteArray &p_arr) {
Variant ret;
{
const uint8_t *r = p_arr.ptr();
@@ -902,7 +916,7 @@ struct VariantUtilityFunctions {
return ret;
}
- static inline Variant bytes2var_with_objects(const PackedByteArray &p_arr) {
+ static inline Variant bytes_to_var_with_objects(const PackedByteArray &p_arr) {
Variant ret;
{
const uint8_t *r = p_arr.ptr();
@@ -1414,6 +1428,9 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDVR3(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerpf, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cubic_interpolate_angle, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cubic_interpolate_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1422,10 +1439,10 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(smoothstep, sarray("from", "to", "x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(deg2rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(rad2deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(linear2db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(db2linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(deg_to_rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(rad_to_deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(linear_to_db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(db_to_linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVR3(wrap, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1473,14 +1490,14 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDVARARGV(push_error, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(push_warning, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(var2str, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(str2var, sarray("string"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(var_to_str, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(str_to_var, sarray("string"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(var2bytes, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(bytes2var, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(var_to_bytes, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(bytes_to_var, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(var2bytes_with_objects, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(bytes2var_with_objects, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(var_to_bytes_with_objects, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(bytes_to_var_with_objects, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDR(hash, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);