summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/engine.cpp80
-rw-r--r--core/config/engine.h17
-rw-r--r--core/config/project_settings.cpp73
-rw-r--r--core/config/project_settings.h9
-rw-r--r--core/core_bind.cpp175
-rw-r--r--core/core_bind.h42
-rw-r--r--core/core_constants.cpp4
-rw-r--r--core/extension/extension_api_dump.cpp16
-rw-r--r--core/extension/gdnative_interface.h10
-rw-r--r--core/extension/native_extension.cpp13
-rw-r--r--core/input/gamecontrollerdb.txt134
-rw-r--r--core/input/godotcontrollerdb.txt50
-rw-r--r--core/input/input.cpp22
-rw-r--r--core/input/input.h20
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/input/input_event.cpp104
-rw-r--r--core/input/input_event.h27
-rw-r--r--core/input/input_map.cpp71
-rw-r--r--core/input/input_map.h7
-rw-r--r--core/io/config_file.cpp26
-rw-r--r--core/io/config_file.h2
-rw-r--r--core/io/dir_access.cpp14
-rw-r--r--core/io/dir_access.h4
-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.cpp4
-rw-r--r--core/io/http_client.h4
-rw-r--r--core/io/http_client_tcp.cpp76
-rw-r--r--core/io/http_client_tcp.h6
-rw-r--r--core/io/image.cpp14
-rw-r--r--core/io/image.h2
-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/marshalls.cpp2
-rw-r--r--core/io/packed_data_container.cpp2
-rw-r--r--core/io/packet_peer.cpp26
-rw-r--r--core/io/packet_peer.h13
-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_loader.cpp14
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/io/resource_uid.cpp2
-rw-r--r--core/io/stream_peer.cpp25
-rw-r--r--core/io/stream_peer.h15
-rw-r--r--core/io/stream_peer_tls.cpp (renamed from core/io/stream_peer_ssl.cpp)34
-rw-r--r--core/io/stream_peer_tls.h (renamed from core/io/stream_peer_ssl.h)20
-rw-r--r--core/io/xml_parser.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/aabb.h8
-rw-r--r--core/math/audio_frame.h2
-rw-r--r--core/math/basis.cpp67
-rw-r--r--core/math/basis.h9
-rw-r--r--core/math/geometry_3d.cpp105
-rw-r--r--core/math/geometry_3d.h92
-rw-r--r--core/math/math_funcs.h103
-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/rect2.h4
-rw-r--r--core/math/rect2i.h4
-rw-r--r--core/math/transform_2d.cpp34
-rw-r--r--core/math/transform_2d.h5
-rw-r--r--core/math/transform_3d.cpp43
-rw-r--r--core/math/transform_3d.h4
-rw-r--r--core/math/vector2.cpp4
-rw-r--r--core/math/vector2.h9
-rw-r--r--core/math/vector2i.h2
-rw-r--r--core/math/vector3.cpp30
-rw-r--r--core/math/vector3.h23
-rw-r--r--core/math/vector3i.h2
-rw-r--r--core/math/vector4.cpp130
-rw-r--r--core/math/vector4.h28
-rw-r--r--core/math/vector4i.cpp10
-rw-r--r--core/math/vector4i.h2
-rw-r--r--core/object/class_db.cpp30
-rw-r--r--core/object/class_db.h2
-rw-r--r--core/object/method_bind.cpp2
-rw-r--r--core/object/object.cpp96
-rw-r--r--core/object/object.h77
-rw-r--r--core/object/ref_counted.cpp3
-rw-r--r--core/object/script_language.cpp38
-rw-r--r--core/object/script_language.h15
-rw-r--r--core/object/script_language_extension.cpp1
-rw-r--r--core/object/script_language_extension.h21
-rw-r--r--core/os/keyboard.cpp16
-rw-r--r--core/os/keyboard.h61
-rw-r--r--core/os/memory.h9
-rw-r--r--core/os/os.cpp50
-rw-r--r--core/os/os.h8
-rw-r--r--core/register_core_types.cpp11
-rw-r--r--core/string/translation.cpp10
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/ustring.cpp193
-rw-r--r--core/string/ustring.h9
-rw-r--r--core/templates/cowdata.h13
-rw-r--r--core/templates/local_vector.h11
-rw-r--r--core/templates/paged_array.h12
-rw-r--r--core/templates/rid_owner.h20
-rw-r--r--core/templates/vector.h1
-rw-r--r--core/variant/dictionary.cpp9
-rw-r--r--core/variant/dictionary.h1
-rw-r--r--core/variant/variant.cpp8
-rw-r--r--core/variant/variant_call.cpp55
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_op.cpp2
-rw-r--r--core/variant/variant_parser.cpp2
-rw-r--r--core/variant/variant_utility.cpp225
118 files changed, 2729 insertions, 1157 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 1a6093869f..cf9697be07 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;
@@ -181,6 +184,42 @@ String Engine::get_license_text() const {
return String(GODOT_LICENSE_TEXT);
}
+String Engine::get_architecture_name() const {
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
+ return "x86_64";
+
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+ return "x86_32";
+
+#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
+ return "arm64";
+
+#elif defined(__arm__) || defined(_M_ARM)
+ return "arm32";
+
+#elif defined(__riscv)
+#if __riscv_xlen == 8
+ return "rv64";
+#else
+ return "riscv";
+#endif
+
+#elif defined(__powerpc__)
+#if defined(__powerpc64__)
+ return "ppc64";
+#else
+ return "ppc";
+#endif
+
+#elif defined(__wasm__)
+#if defined(__wasm64__)
+ return "wasm64";
+#elif defined(__wasm32__)
+ return "wasm32";
+#endif
+#endif
+}
+
bool Engine::is_abort_on_gpu_errors_enabled() const {
return abort_on_gpu_errors;
}
@@ -271,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 68562643e7..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;
@@ -142,6 +150,8 @@ public:
void set_write_movie_path(const String &p_path);
String get_write_movie_path() const;
+ String get_architecture_name() const;
+
void set_shader_cache_path(const String &p_path);
String get_shader_cache_path() const;
@@ -149,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 38db7f9190..6275502378 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -41,7 +41,10 @@
#include "core/os/keyboard.h"
#include "core/variant/variant_parser.h"
#include "core/version.h"
+
+#ifdef TOOLS_ENABLED
#include "modules/modules_enabled.gen.h" // For mono.
+#endif // TOOLS_ENABLED
const String ProjectSettings::PROJECT_DATA_DIR_NAME_SUFFIX = "godot";
@@ -72,9 +75,10 @@ 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");
}
+#ifdef TOOLS_ENABLED
// Returns the features that a project must have when opened with this build of Godot.
// This is used by the project manager to provide the initial_settings for config/features.
const PackedStringArray ProjectSettings::get_required_features() {
@@ -137,6 +141,7 @@ const PackedStringArray ProjectSettings::_trim_to_supported_features(const Packe
features.sort();
return features;
}
+#endif // TOOLS_ENABLED
String ProjectSettings::localize_path(const String &p_path) const {
if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") ||
@@ -157,12 +162,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 +447,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 +477,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 +505,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 +528,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 +538,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 +561,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 +690,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 +769,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;
}
@@ -895,6 +902,7 @@ Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other par
Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) {
ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Project settings save path cannot be empty.");
+#ifdef TOOLS_ENABLED
PackedStringArray project_features = get_setting("application/config/features");
// If there is no feature list currently present, force one to generate.
if (project_features.is_empty()) {
@@ -909,7 +917,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#");
@@ -922,6 +930,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
project_features = _trim_to_supported_features(project_features);
set_setting("application/config/features", project_features);
+#endif // TOOLS_ENABLED
RBSet<_VCSort> vclist;
@@ -1070,7 +1079,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 +1087,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 +1144,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 +1191,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);
@@ -1198,6 +1210,9 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("display/window/size/window_height_override", 0);
custom_prop_info["display/window/size/window_height_override"] = PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
+ GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false);
+
GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
GLOBAL_DEF_RST("audio/general/2d_panning_strength", 1.0f);
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index c3992a4db2..a9af63ee39 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -48,8 +48,10 @@ public:
//properties that are not for built in values begin from this value, so builtin ones are displayed first
NO_BUILTIN_ORDER_BASE = 1 << 16
};
+#ifdef TOOLS_ENABLED
const static PackedStringArray get_required_features();
const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features);
+#endif // TOOLS_ENABLED
struct AutoloadInfo {
StringName name;
@@ -102,6 +104,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;
@@ -114,8 +118,10 @@ protected:
Error _save_custom_bnd(const String &p_file);
+#ifdef TOOLS_ENABLED
const static PackedStringArray _get_supported_features();
const static PackedStringArray _trim_to_supported_features(const PackedStringArray &p_project_features);
+#endif // TOOLS_ENABLED
void _convert_to_last_version(int p_from_version);
@@ -147,9 +153,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 2cf6e8a025..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;
@@ -933,6 +814,7 @@ Dictionary Geometry2D::make_atlas(const Vector<Size2> &p_rects) {
void Geometry2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &Geometry2D::is_point_in_circle);
+ ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &Geometry2D::segment_intersects_circle);
ClassDB::bind_method(D_METHOD("segment_intersects_segment", "from_a", "to_a", "from_b", "to_b"), &Geometry2D::segment_intersects_segment);
ClassDB::bind_method(D_METHOD("line_intersects_line", "from_a", "dir_a", "from_b", "dir_b"), &Geometry2D::line_intersects_line);
@@ -987,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) {
@@ -2021,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());
@@ -2033,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());
}
@@ -2065,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
@@ -2253,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();
}
@@ -2269,6 +2154,10 @@ String Engine::get_license_text() const {
return ::Engine::get_singleton()->get_license_text();
}
+String Engine::get_architecture_name() const {
+ return ::Engine::get_singleton()->get_architecture_name();
+}
+
bool Engine::is_in_physics_frame() const {
return ::Engine::get_singleton()->is_in_physics_frame();
}
@@ -2366,6 +2255,8 @@ void Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_license_info"), &Engine::get_license_info);
ClassDB::bind_method(D_METHOD("get_license_text"), &Engine::get_license_text);
+ ClassDB::bind_method(D_METHOD("get_architecture_name"), &Engine::get_architecture_name);
+
ClassDB::bind_method(D_METHOD("is_in_physics_frame"), &Engine::is_in_physics_frame);
ClassDB::bind_method(D_METHOD("has_singleton", "name"), &Engine::has_singleton);
diff --git a/core/core_bind.h b/core/core_bind.h
index 98bf34e07d..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,11 +655,13 @@ 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;
+ String get_architecture_name() const;
+
bool is_in_physics_frame() const;
bool has_singleton(const StringName &p_name) const;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index dc0ab72a86..2f8b28363b 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -433,11 +433,11 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(KeyModifierMask, KEY_CODE_MASK, CODE_MASK);
BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(KeyModifierMask, KEY_MODIFIER_MASK, MODIFIER_MASK);
+ BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, CMD_OR_CTRL);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, SHIFT);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, ALT);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, META);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, CTRL);
- BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(KeyModifierMask, KEY_MASK, CMD);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, KPAD);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, GROUP_SWITCH);
@@ -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 b69859b441..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;
@@ -372,7 +374,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
}
if (err != OK) {
- ERR_PRINT("Error loading GDExtension config file: " + p_path);
+ ERR_PRINT("Error loading GDExtension configuration file: " + p_path);
return Ref<Resource>();
}
@@ -380,7 +382,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
if (r_error) {
*r_error = ERR_INVALID_DATA;
}
- ERR_PRINT("GDExtension config file must contain 'configuration.entry_symbol' key: " + p_path);
+ ERR_PRINT("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: " + p_path);
return Ref<Resource>();
}
@@ -413,12 +415,13 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
- ERR_PRINT("No GDExtension library found for current architecture; in config file " + p_path);
+ const String os_arch = OS::get_singleton()->get_name().to_lower() + "." + Engine::get_singleton()->get_architecture_name();
+ ERR_PRINT(vformat("No GDExtension library found for current OS and architecture (%s) in configuration file: %s", os_arch, p_path));
return Ref<Resource>();
}
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/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index d751f6c9b8..5ae3b2c799 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -11,7 +11,7 @@
03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
-03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,
+03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,
03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -19,14 +19,16 @@
03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
-03000000c82d00000151000000000000,8BitDo M30 Modkit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,
03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows,
-03000000c82d00000451000000000000,8BitDo N30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,start:b11,platform:Windows,
03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
@@ -37,7 +39,8 @@
03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
@@ -45,7 +48,7 @@
03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows,
03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
@@ -54,11 +57,11 @@
03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00000351000000000000,8BitDo SN30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
@@ -96,6 +99,8 @@
03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,
@@ -120,6 +125,7 @@
030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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:b2,platform:Windows,
03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
@@ -208,6 +214,7 @@
03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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:Windows,
03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
+03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -234,14 +241,14 @@
030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
+030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows,
030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f00008700000000000000,Hori Fightstick Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f00008800000000000000,Hori Fightstick Mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,
@@ -273,7 +280,7 @@
030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b07,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b08,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows,
+03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c100000000000000,Horipad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -439,7 +446,7 @@
03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-0300000062060000d570000000000000,PowerA PS3 Contoller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000013a7000000000000,PowerA Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -482,7 +489,6 @@
03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000f10e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -538,7 +544,6 @@
03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000632500008005000000010000,Redgear,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,guide:b12,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,
03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
@@ -648,6 +653,7 @@
030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows,
@@ -666,7 +672,6 @@
03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
-03000000666600000288000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
@@ -741,11 +746,18 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Mac OS X,
03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X,
+03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
@@ -754,13 +766,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X,
03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
@@ -776,6 +792,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
+03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -786,6 +804,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Mac OS X,
030000006f0e00008401000003010000,Faceoff Premiere Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle3:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Mac OS X,
@@ -804,6 +823,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -883,6 +904,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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:Mac OS X,
030000000d0f0000c100000072050000,Retro Bit Sega Genesis 6B Controller,a:b2,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b8,rightshoulder:b6,righttrigger:b7,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -954,11 +976,18 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
# Linux
030000005e0400008e02000020010000,8BitDo Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -968,12 +997,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux,
05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
@@ -981,6 +1013,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
@@ -1008,8 +1041,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
-05000000050b00000045000031000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
-05000000050b00000045000040000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
03000000503200000110000011010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
@@ -1075,9 +1110,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
-030000000d0f00004d00000011010000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux,
030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -1092,7 +1129,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f0000c100000011010000,Horipad S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-050000000d0f0000f600000001000000,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1197,18 +1234,18 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,
-060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,
03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
+050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux,
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
@@ -1216,8 +1253,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-19000000010000000100000001010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
-19000000010000000200000011000000,odroidgo2 joypad v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
+19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
+19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux,
05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
@@ -1243,14 +1280,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
+03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
+03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1357,6 +1394,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000512000010010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux,
03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,
03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1391,6 +1429,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Linux,
+03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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:Linux,
03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
@@ -1422,8 +1464,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b000007050000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1433,8 +1477,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000007050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,
@@ -1449,18 +1495,34 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android,
+38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android,
+32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android,
+38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android,
64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android,
66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android,
66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android,
+33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android,
38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
@@ -1468,12 +1530,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android,
61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android,
05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
@@ -1497,6 +1564,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android,
05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1535,6 +1604,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android,
436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+484a5a204d6179666c61736820576969,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Android,
@@ -1589,10 +1661,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
-32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,x:b2,y:b3,leftshoulder:b9,rightshoulder:b10,lefttrigger:a4,righttrigger:a5,guide:b5,start:b6,leftstick:b7,rightstick:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,back:b15,platform:Android,
64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1669,6 +1741,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,
4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,
4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,
+050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS,
+050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,
+050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS,
+050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
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 da0c6cb62a..1390a0a7fa 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -169,11 +169,10 @@ void Input::_bind_methods() {
void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
String pf = p_function;
- if (p_idx == 0 &&
- (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" ||
- pf == "is_action_just_pressed" || pf == "is_action_just_released" ||
- pf == "get_action_strength" || pf == "get_action_raw_strength" ||
- pf == "get_axis" || pf == "get_vector")) {
+
+ if ((p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength" || pf == "get_action_raw_strength")) ||
+ (p_idx < 2 && pf == "get_axis") ||
+ (p_idx < 4 && pf == "get_vector")) {
List<PropertyInfo> pinfo;
ProjectSettings::get_singleton()->get_property_list(&pinfo);
@@ -767,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;
@@ -974,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) {
@@ -1129,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;
@@ -1187,7 +1181,7 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, J
return event;
}
-void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[]) {
+void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]) {
for (int i = 0; i < mapping.bindings.size(); i++) {
const JoyBinding binding = mapping.bindings[i];
if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) {
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 3c104c2c86..596b704732 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -142,13 +142,33 @@ int64_t InputEventFromWindow::get_window_id() const {
///////////////////////////////////
-void InputEventWithModifiers::set_store_command(bool p_enabled) {
- store_command = p_enabled;
+void InputEventWithModifiers::set_command_or_control_autoremap(bool p_enabled) {
+ command_or_control_autoremap = p_enabled;
+ if (command_or_control_autoremap) {
+#ifdef MACOS_ENABLED
+ ctrl_pressed = false;
+ meta_pressed = true;
+#else
+ ctrl_pressed = true;
+ meta_pressed = false;
+#endif
+ } else {
+ ctrl_pressed = false;
+ meta_pressed = false;
+ }
emit_changed();
}
-bool InputEventWithModifiers::is_storing_command() const {
- return store_command;
+bool InputEventWithModifiers::is_command_or_control_autoremap() const {
+ return command_or_control_autoremap;
+}
+
+bool InputEventWithModifiers::is_command_or_control_pressed() const {
+#ifdef MACOS_ENABLED
+ return meta_pressed;
+#else
+ return ctrl_pressed;
+#endif
}
void InputEventWithModifiers::set_shift_pressed(bool p_enabled) {
@@ -170,6 +190,7 @@ bool InputEventWithModifiers::is_alt_pressed() const {
}
void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) {
+ ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Control directly!");
ctrl_pressed = p_enabled;
emit_changed();
}
@@ -179,6 +200,7 @@ bool InputEventWithModifiers::is_ctrl_pressed() const {
}
void InputEventWithModifiers::set_meta_pressed(bool p_enabled) {
+ ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Meta directly!");
meta_pressed = p_enabled;
emit_changed();
}
@@ -187,15 +209,6 @@ bool InputEventWithModifiers::is_meta_pressed() const {
return meta_pressed;
}
-void InputEventWithModifiers::set_command_pressed(bool p_enabled) {
- command_pressed = p_enabled;
- emit_changed();
-}
-
-bool InputEventWithModifiers::is_command_pressed() const {
- return command_pressed;
-}
-
void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModifiers *event) {
set_alt_pressed(event->is_alt_pressed());
set_shift_pressed(event->is_shift_pressed());
@@ -217,6 +230,13 @@ Key InputEventWithModifiers::get_modifiers_mask() const {
if (is_meta_pressed()) {
mask |= KeyModifierMask::META;
}
+ if (is_command_or_control_autoremap()) {
+#ifdef MACOS_ENABLED
+ mask |= KeyModifierMask::META;
+#else
+ mask |= KeyModifierMask::CTRL;
+#endif
+ }
return mask;
}
@@ -248,8 +268,10 @@ String InputEventWithModifiers::to_string() {
}
void InputEventWithModifiers::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_store_command", "enable"), &InputEventWithModifiers::set_store_command);
- ClassDB::bind_method(D_METHOD("is_storing_command"), &InputEventWithModifiers::is_storing_command);
+ ClassDB::bind_method(D_METHOD("set_command_or_control_autoremap", "enable"), &InputEventWithModifiers::set_command_or_control_autoremap);
+ ClassDB::bind_method(D_METHOD("is_command_or_control_autoremap"), &InputEventWithModifiers::is_command_or_control_autoremap);
+
+ ClassDB::bind_method(D_METHOD("is_command_or_control_pressed"), &InputEventWithModifiers::is_command_or_control_pressed);
ClassDB::bind_method(D_METHOD("set_alt_pressed", "pressed"), &InputEventWithModifiers::set_alt_pressed);
ClassDB::bind_method(D_METHOD("is_alt_pressed"), &InputEventWithModifiers::is_alt_pressed);
@@ -263,35 +285,25 @@ void InputEventWithModifiers::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_meta_pressed", "pressed"), &InputEventWithModifiers::set_meta_pressed);
ClassDB::bind_method(D_METHOD("is_meta_pressed"), &InputEventWithModifiers::is_meta_pressed);
- ClassDB::bind_method(D_METHOD("set_command_pressed", "pressed"), &InputEventWithModifiers::set_command_pressed);
- ClassDB::bind_method(D_METHOD("is_command_pressed"), &InputEventWithModifiers::is_command_pressed);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "store_command"), "set_store_command", "is_storing_command");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_or_control_autoremap"), "set_command_or_control_autoremap", "is_command_or_control_autoremap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt_pressed"), "set_alt_pressed", "is_alt_pressed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift_pressed"), "set_shift_pressed", "is_shift_pressed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ctrl_pressed"), "set_ctrl_pressed", "is_ctrl_pressed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_pressed"), "set_meta_pressed", "is_meta_pressed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_pressed"), "set_command_pressed", "is_command_pressed");
}
-void InputEventWithModifiers::_validate_property(PropertyInfo &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;
+void InputEventWithModifiers::_validate_property(PropertyInfo &p_property) const {
+ if (command_or_control_autoremap) {
+ // Cannot be used with Meta/Command or Control!
+ 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_or_control_autoremap") {
+ p_property.usage ^= PROPERTY_USAGE_STORAGE;
}
}
}
@@ -399,14 +411,18 @@ Ref<InputEventKey> InputEventKey::create_reference(Key p_keycode) {
if ((p_keycode & KeyModifierMask::ALT) != Key::NONE) {
ie->set_alt_pressed(true);
}
- if ((p_keycode & KeyModifierMask::CTRL) != Key::NONE) {
- ie->set_ctrl_pressed(true);
- }
- if ((p_keycode & KeyModifierMask::CMD) != Key::NONE) {
- ie->set_command_pressed(true);
- }
- if ((p_keycode & KeyModifierMask::META) != Key::NONE) {
- ie->set_meta_pressed(true);
+ if ((p_keycode & KeyModifierMask::CMD_OR_CTRL) != Key::NONE) {
+ ie->set_command_or_control_autoremap(true);
+ if ((p_keycode & KeyModifierMask::CTRL) != Key::NONE || (p_keycode & KeyModifierMask::META) != Key::NONE) {
+ WARN_PRINT("Invalid Key Modifiers: Command or Control autoremapping is enabled, Meta and Control values are ignored!");
+ }
+ } else {
+ if ((p_keycode & KeyModifierMask::CTRL) != Key::NONE) {
+ ie->set_ctrl_pressed(true);
+ }
+ if ((p_keycode & KeyModifierMask::META) != Key::NONE) {
+ ie->set_meta_pressed(true);
+ }
}
return ie;
@@ -816,7 +832,7 @@ String InputEventMouseMotion::to_string() {
// Work around the fact vformat can only take 5 substitutions but 7 need to be passed.
String mask_and_position_and_relative = vformat("button_mask=%s, position=(%s), relative=(%s)", button_mask_string, String(get_position()), String(get_relative()));
- return vformat("InputEventMouseMotion: %s, velocity=(%s), pressure=%.2f, tilt=(%s), pen_inverted=(%d)", mask_and_position_and_relative, String(get_velocity()), get_pressure(), String(get_tilt()), get_pen_inverted());
+ return vformat("InputEventMouseMotion: %s, velocity=(%s), pressure=%.2f, tilt=(%s), pen_inverted=(%s)", mask_and_position_and_relative, String(get_velocity()), get_pressure(), String(get_tilt()), get_pen_inverted());
}
bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 59a2df497c..bc3ec3e7ac 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -107,32 +107,22 @@ public:
class InputEventWithModifiers : public InputEventFromWindow {
GDCLASS(InputEventWithModifiers, InputEventFromWindow);
- bool store_command = true;
+ bool command_or_control_autoremap = false;
bool shift_pressed = false;
bool alt_pressed = false;
-#ifdef APPLE_STYLE_KEYS
- union {
- bool command_pressed;
- bool meta_pressed = false; //< windows/mac key
- };
-
+ bool meta_pressed = false; // "Command" on macOS, "Meta/Win" key on other platforms.
bool ctrl_pressed = false;
-#else
- union {
- bool command_pressed; //< windows/mac key
- bool ctrl_pressed = false;
- };
- bool meta_pressed = false; //< windows/mac key
-#endif
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);
- bool is_storing_command() const;
+ void set_command_or_control_autoremap(bool p_enabled);
+ bool is_command_or_control_autoremap() const;
+
+ bool is_command_or_control_pressed() const;
void set_shift_pressed(bool p_pressed);
bool is_shift_pressed() const;
@@ -146,9 +136,6 @@ public:
void set_meta_pressed(bool p_pressed);
bool is_meta_pressed() const;
- void set_command_pressed(bool p_pressed);
- bool is_command_pressed() const;
-
void set_modifiers_from_event(const InputEventWithModifiers *event);
Key get_modifiers_mask() const;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 942c5248df..ce76d11b6e 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()) {
@@ -428,27 +429,27 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
// ///// UI basic Shortcuts /////
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::X | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::X | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_cut", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::C | KeyModifierMask::CMD));
- inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::C | KeyModifierMask::CMD_OR_CTRL));
+ inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_copy", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL));
inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT));
default_builtin_cache.insert("ui_paste", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_undo", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD | KeyModifierMask::SHIFT));
- inputs.push_back(InputEventKey::create_reference(Key::Y | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::Z | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT));
+ inputs.push_back(InputEventKey::create_reference(Key::Y | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_redo", inputs);
// ///// UI Text Input Shortcuts /////
@@ -473,13 +474,13 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::CMD));
- inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::CMD_OR_CTRL));
+ inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_newline_blank", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD));
- inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_newline_above", inputs);
// Indentation
@@ -498,7 +499,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_backspace", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_backspace_word", inputs);
inputs = List<Ref<InputEvent>>();
@@ -509,7 +510,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_backspace_all_to_left", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_backspace_all_to_left.macos", inputs);
inputs = List<Ref<InputEvent>>();
@@ -517,7 +518,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_delete", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_delete_word", inputs);
inputs = List<Ref<InputEvent>>();
@@ -528,7 +529,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_delete_all_to_right", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_delete_all_to_right.macos", inputs);
// Text Caret Movement Left/Right
@@ -538,7 +539,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_caret_left", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_word_left", inputs);
inputs = List<Ref<InputEvent>>();
@@ -550,7 +551,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_caret_right", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_word_right", inputs);
inputs = List<Ref<InputEvent>>();
@@ -575,7 +576,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CTRL));
- inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_line_start.macos", inputs);
inputs = List<Ref<InputEvent>>();
@@ -584,7 +585,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::E | KeyModifierMask::CTRL));
- inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_line_end.macos", inputs);
// Text Caret Movement Page Up/Down
@@ -600,47 +601,47 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
// Text Caret Movement Document Start/End
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::HOME | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_start", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_start.macos", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::END | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_end", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_end.macos", inputs);
// Text Scrolling
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_scroll_up", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD | KeyModifierMask::ALT));
+ inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_scroll_up.macos", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_scroll_down", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD | KeyModifierMask::ALT));
+ inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_scroll_down.macos", inputs);
// Text Misc
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::A | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_select_all", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
inputs = List<Ref<InputEvent>>();
@@ -659,7 +660,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
// ///// UI Graph Shortcuts /////
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_graph_duplicate", inputs);
inputs = List<Ref<InputEvent>>();
@@ -680,7 +681,7 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_filedialog_show_hidden", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD));
+ inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_swap_input_direction", inputs);
return default_builtin_cache;
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/config_file.cpp b/core/io/config_file.cpp
index ae421654ca..f84a95347a 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -32,6 +32,7 @@
#include "core/io/file_access_encrypted.h"
#include "core/os/keyboard.h"
+#include "core/string/string_builder.h"
#include "core/variant/variant_parser.h"
PackedStringArray ConfigFile::_get_sections() const {
@@ -130,6 +131,28 @@ void ConfigFile::erase_section_key(const String &p_section, const String &p_key)
}
}
+String ConfigFile::encode_to_text() const {
+ StringBuilder sb;
+ bool first = true;
+ for (const KeyValue<String, HashMap<String, Variant>> &E : values) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append("\n");
+ }
+ if (!E.key.is_empty()) {
+ sb.append("[" + E.key + "]\n\n");
+ }
+
+ for (const KeyValue<String, Variant> &F : E.value) {
+ String vstr;
+ VariantWriter::write_to_string(F.value, vstr);
+ sb.append(F.key.property_name_encode() + "=" + vstr + "\n");
+ }
+ }
+ return sb.as_string();
+}
+
Error ConfigFile::save(const String &p_path) {
Error err;
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
@@ -295,6 +318,7 @@ Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream)
void ConfigFile::clear() {
values.clear();
}
+
void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value", "section", "key", "value"), &ConfigFile::set_value);
ClassDB::bind_method(D_METHOD("get_value", "section", "key", "default"), &ConfigFile::get_value, DEFVAL(Variant()));
@@ -312,6 +336,8 @@ void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
+ ClassDB::bind_method(D_METHOD("encode_to_text"), &ConfigFile::encode_to_text);
+
BIND_METHOD_ERR_RETURN_DOC("load", ERR_FILE_CANT_OPEN);
ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted);
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 3b07ec52f5..f6209492b7 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -68,6 +68,8 @@ public:
Error load(const String &p_path);
Error parse(const String &p_data);
+ String encode_to_text() const; // used by exporter
+
void clear();
Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
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 22017efaa3..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;
@@ -108,6 +108,8 @@ public:
if (da->remove(p_path) != OK) {
ERR_FAIL_MSG("Cannot remove file or directory: " + p_path);
}
+ } else {
+ ERR_FAIL_MSG("Cannot remove non-existent file or directory: " + p_path);
}
}
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.cpp b/core/io/http_client.cpp
index 52b1120b2a..93a310e83b 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -138,7 +138,7 @@ PackedStringArray HTTPClient::_get_response_headers() {
}
void HTTPClient::_bind_methods() {
- ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(-1), DEFVAL(false), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_tls", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(-1), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_connection", "connection"), &HTTPClient::set_connection);
ClassDB::bind_method(D_METHOD("get_connection"), &HTTPClient::get_connection);
ClassDB::bind_method(D_METHOD("request_raw", "method", "url", "headers", "body"), &HTTPClient::_request_raw);
@@ -190,7 +190,7 @@ void HTTPClient::_bind_methods() {
BIND_ENUM_CONSTANT(STATUS_REQUESTING); // Request in progress
BIND_ENUM_CONSTANT(STATUS_BODY); // Request resulted in body which must be read
BIND_ENUM_CONSTANT(STATUS_CONNECTION_ERROR);
- BIND_ENUM_CONSTANT(STATUS_SSL_HANDSHAKE_ERROR);
+ BIND_ENUM_CONSTANT(STATUS_TLS_HANDSHAKE_ERROR);
BIND_ENUM_CONSTANT(RESPONSE_CONTINUE);
BIND_ENUM_CONSTANT(RESPONSE_SWITCHING_PROTOCOLS);
diff --git a/core/io/http_client.h b/core/io/http_client.h
index de6045f647..0524b010f4 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -138,7 +138,7 @@ public:
STATUS_REQUESTING, // Request in progress
STATUS_BODY, // Request resulted in body, which must be read
STATUS_CONNECTION_ERROR,
- STATUS_SSL_HANDSHAKE_ERROR,
+ STATUS_TLS_HANDSHAKE_ERROR,
};
@@ -168,7 +168,7 @@ public:
Error verify_headers(const Vector<String> &p_headers);
virtual Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) = 0;
- virtual Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) = 0;
+ virtual Error connect_to_host(const String &p_host, int p_port = -1, bool p_tls = false, bool p_verify_host = true) = 0;
virtual void set_connection(const Ref<StreamPeer> &p_connection) = 0;
virtual Ref<StreamPeer> get_connection() const = 0;
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index d983d86b99..5c1d00a330 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -28,18 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "http_client_tcp.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/version.h"
HTTPClient *HTTPClientTCP::_create_func() {
return memnew(HTTPClientTCP);
}
-Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
+Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_tls, bool p_verify_host) {
close();
conn_port = p_port;
@@ -47,21 +47,21 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ss
ip_candidates.clear();
- ssl = p_ssl;
- ssl_verify_host = p_verify_host;
+ tls = p_tls;
+ tls_verify_host = p_verify_host;
String host_lower = conn_host.to_lower();
if (host_lower.begins_with("http://")) {
conn_host = conn_host.substr(7, conn_host.length() - 7);
} else if (host_lower.begins_with("https://")) {
- ssl = true;
+ tls = true;
conn_host = conn_host.substr(8, conn_host.length() - 8);
}
ERR_FAIL_COND_V(conn_host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER);
if (conn_port < 0) {
- if (ssl) {
+ if (tls) {
conn_port = PORT_HTTPS;
} else {
conn_port = PORT_HTTP;
@@ -70,11 +70,11 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ss
connection = tcp_connection;
- if (ssl && https_proxy_port != -1) {
+ if (tls && https_proxy_port != -1) {
proxy_client.instantiate(); // Needs proxy negotiation.
server_host = https_proxy_host;
server_port = https_proxy_port;
- } else if (!ssl && http_proxy_port != -1) {
+ } else if (!tls && http_proxy_port != -1) {
server_host = http_proxy_host;
server_port = http_proxy_port;
} else {
@@ -94,6 +94,10 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ss
} else {
// Host contains hostname and needs to be resolved to IP.
resolving = IP::get_singleton()->resolve_hostname_queue_item(server_host);
+ if (resolving == IP::RESOLVER_INVALID_ID) {
+ status = STATUS_CANT_RESOLVE;
+ return ERR_CANT_RESOLVE;
+ }
status = STATUS_RESOLVING;
}
@@ -103,9 +107,9 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ss
void HTTPClientTCP::set_connection(const Ref<StreamPeer> &p_connection) {
ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object.");
- if (ssl) {
- ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()),
- "Connection is not a reference to a valid StreamPeerSSL object.");
+ if (tls) {
+ ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerTLS>(p_connection.ptr()),
+ "Connection is not a reference to a valid StreamPeerTLS object.");
}
if (connection == p_connection) {
@@ -152,7 +156,7 @@ Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector<
}
String uri = p_url;
- if (!ssl && http_proxy_port != -1) {
+ if (!tls && http_proxy_port != -1) {
uri = vformat("http://%s:%d%s", conn_host, conn_port, p_url);
}
@@ -177,7 +181,7 @@ Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector<
}
}
if (add_host) {
- if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
+ if ((tls && conn_port == PORT_HTTPS) || (!tls && conn_port == PORT_HTTP)) {
// Don't append the standard ports.
request += "Host: " + conn_host + "\r\n";
} else {
@@ -312,7 +316,7 @@ Error HTTPClientTCP::poll() {
return OK;
} break;
case StreamPeerTCP::STATUS_CONNECTED: {
- if (ssl && proxy_client.is_valid()) {
+ if (tls && proxy_client.is_valid()) {
Error err = proxy_client->poll();
if (err == ERR_UNCONFIGURED) {
proxy_client->set_connection(tcp_connection);
@@ -353,42 +357,42 @@ Error HTTPClientTCP::poll() {
return ERR_CANT_CONNECT;
} break;
}
- } else if (ssl) {
- Ref<StreamPeerSSL> ssl;
+ } else if (tls) {
+ Ref<StreamPeerTLS> tls;
if (!handshaking) {
- // Connect the StreamPeerSSL and start handshaking.
- ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
- ssl->set_blocking_handshake_enabled(false);
- Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host);
+ // Connect the StreamPeerTLS and start handshaking.
+ tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
+ tls->set_blocking_handshake_enabled(false);
+ Error err = tls->connect_to_stream(tcp_connection, tls_verify_host, conn_host);
if (err != OK) {
close();
- status = STATUS_SSL_HANDSHAKE_ERROR;
+ status = STATUS_TLS_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- connection = ssl;
+ connection = tls;
handshaking = true;
} else {
- // We are already handshaking, which means we can use your already active SSL connection.
- ssl = static_cast<Ref<StreamPeerSSL>>(connection);
- if (ssl.is_null()) {
+ // We are already handshaking, which means we can use your already active TLS connection.
+ tls = static_cast<Ref<StreamPeerTLS>>(connection);
+ if (tls.is_null()) {
close();
- status = STATUS_SSL_HANDSHAKE_ERROR;
+ status = STATUS_TLS_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- ssl->poll(); // Try to finish the handshake.
+ tls->poll(); // Try to finish the handshake.
}
- if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) {
+ if (tls->get_status() == StreamPeerTLS::STATUS_CONNECTED) {
// Handshake has been successful.
handshaking = false;
ip_candidates.clear();
status = STATUS_CONNECTED;
return OK;
- } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) {
+ } else if (tls->get_status() != StreamPeerTLS::STATUS_HANDSHAKING) {
// Handshake has failed.
close();
- status = STATUS_SSL_HANDSHAKE_ERROR;
+ status = STATUS_TLS_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
// ... we will need to poll more for handshake to finish.
@@ -417,10 +421,10 @@ Error HTTPClientTCP::poll() {
case STATUS_BODY:
case STATUS_CONNECTED: {
// Check if we are still connected.
- if (ssl) {
- Ref<StreamPeerSSL> tmp = connection;
+ if (tls) {
+ Ref<StreamPeerTLS> tmp = connection;
tmp->poll();
- if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ if (tmp->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
status = STATUS_CONNECTION_ERROR;
return ERR_CONNECTION_ERROR;
}
@@ -544,7 +548,7 @@ Error HTTPClientTCP::poll() {
return ERR_UNCONFIGURED;
} break;
case STATUS_CONNECTION_ERROR:
- case STATUS_SSL_HANDSHAKE_ERROR: {
+ case STATUS_TLS_HANDSHAKE_ERROR: {
return ERR_CONNECTION_ERROR;
} break;
case STATUS_CANT_CONNECT: {
@@ -788,4 +792,4 @@ HTTPClientTCP::HTTPClientTCP() {
HTTPClient *(*HTTPClient::_create)() = HTTPClientTCP::_create_func;
-#endif // #ifndef JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/core/io/http_client_tcp.h b/core/io/http_client_tcp.h
index c10e0b1eca..744c15f7ab 100644
--- a/core/io/http_client_tcp.h
+++ b/core/io/http_client_tcp.h
@@ -46,8 +46,8 @@ private:
String http_proxy_host;
int https_proxy_port = -1; // Proxy server for https requests.
String https_proxy_host;
- bool ssl = false;
- bool ssl_verify_host = false;
+ bool tls = false;
+ bool tls_verify_host = false;
bool blocking = false;
bool handshaking = false;
bool head_request = false;
@@ -79,7 +79,7 @@ public:
Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) override;
- Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) override;
+ Error connect_to_host(const String &p_host, int p_port = -1, bool p_tls = false, bool p_verify_host = true) override;
void set_connection(const Ref<StreamPeer> &p_connection) override;
Ref<StreamPeer> get_connection() const override;
void close() override;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 0f20aabd7e..812bfa8263 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -416,8 +416,8 @@ int Image::get_height() const {
return height;
}
-Vector2 Image::get_size() const {
- return Vector2(width, height);
+Size2i Image::get_size() const {
+ return Size2i(width, height);
}
bool Image::has_mipmaps() const {
@@ -2671,7 +2671,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const P
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2717,7 +2717,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2762,7 +2762,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2802,7 +2802,7 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2862,7 +2862,7 @@ void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
- if (r.has_no_area()) {
+ if (!r.has_area()) {
return;
}
diff --git a/core/io/image.h b/core/io/image.h
index 46820a4c08..fd264a7a38 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -209,7 +209,7 @@ private:
public:
int get_width() const; ///< Get image width
int get_height() const; ///< Get image height
- Vector2 get_size() const;
+ Size2i get_size() const;
bool has_mipmaps() const;
int get_mipmap_count() const;
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/marshalls.cpp b/core/io/marshalls.cpp
index 2f69c10218..b24c49f58d 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -510,7 +510,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
(*r_len) += sizeof(double) * 16;
}
} else {
- ERR_FAIL_COND_V((size_t)len < sizeof(float) * 62, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V((size_t)len < sizeof(float) * 16, ERR_INVALID_DATA);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
val.matrix[i][j] = decode_float(&buf[(i * 4 + j) * sizeof(float)]);
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index a456318148..2dcb86cbc6 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -353,7 +353,7 @@ Variant PackedDataContainer::_iter_get(const Variant &p_iter) {
}
void PackedDataContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_data"), &PackedDataContainer::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &PackedDataContainer::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &PackedDataContainer::_get_data);
ClassDB::bind_method(D_METHOD("_iter_init"), &PackedDataContainer::_iter_init);
ClassDB::bind_method(D_METHOD("_iter_get"), &PackedDataContainer::_iter_get);
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 0af236f766..1df779d034 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -152,42 +152,24 @@ void PacketPeer::_bind_methods() {
/***************/
-int PacketPeerExtension::get_available_packet_count() const {
- int count;
- if (GDVIRTUAL_CALL(_get_available_packet_count, count)) {
- return count;
- }
- WARN_PRINT_ONCE("PacketPeerExtension::_get_available_packet_count is unimplemented!");
- return -1;
-}
-
Error PacketPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("PacketPeerExtension::_get_packet_native is unimplemented!");
return FAILED;
}
Error PacketPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("PacketPeerExtension::_put_packet_native is unimplemented!");
return FAILED;
}
-int PacketPeerExtension::get_max_packet_size() const {
- int size;
- if (GDVIRTUAL_CALL(_get_max_packet_size, size)) {
- return size;
- }
- WARN_PRINT_ONCE("PacketPeerExtension::_get_max_packet_size is unimplemented!");
- return 0;
-}
-
void PacketPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index ec9d33aa5a..07045e62a6 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -35,6 +35,7 @@
#include "core/object/class_db.h"
#include "core/templates/ring_buffer.h"
+#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/script_language.h"
#include "core/variant/native_ptr.h"
@@ -84,16 +85,14 @@ protected:
static void _bind_methods();
public:
- virtual int get_available_packet_count() const override;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
+ GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
+
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override;
+ GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int);
- /* GDExtension */
- GDVIRTUAL0RC(int, _get_available_packet_count);
- GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
- GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int);
- GDVIRTUAL0RC(int, _get_max_packet_size);
+ EXBIND0RC(int, get_available_packet_count);
+ EXBIND0RC(int, get_max_packet_size);
};
class PacketPeerStream : public PacketPeer {
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_loader.cpp b/core/io/resource_loader.cpp
index fc4177004b..eccb397e2e 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -794,6 +794,8 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
// To find the path of the remapped resource, we extract the locale name after
// the last ':' to match the project locale.
+ // An extra remap may still be necessary afterwards due to the text -> binary converter on export.
+
String locale = TranslationServer::get_singleton()->get_locale();
ERR_FAIL_COND_V_MSG(locale.length() < 2, p_path, "Could not remap path '" + p_path + "' for translation as configured locale '" + locale + "' is invalid.");
@@ -819,16 +821,20 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
if (r_translation_remapped) {
*r_translation_remapped = true;
}
+
+ // Fallback to p_path if new_path does not exist.
+ if (!FileAccess::exists(new_path)) {
+ WARN_PRINT(vformat("Translation remap '%s' does not exist. Falling back to '%s'.", new_path, p_path));
+ new_path = p_path;
+ }
}
if (path_remaps.has(new_path)) {
new_path = path_remaps[new_path];
- }
-
- if (new_path == p_path) { // Did not remap.
+ } else {
// Try file remap.
Error err;
- Ref<FileAccess> f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(new_path + ".remap", FileAccess::READ, &err);
if (f.is_valid()) {
VariantParser::StreamFile stream;
stream.f = f;
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/io/stream_peer.cpp b/core/io/stream_peer.cpp
index c65968ef03..053ff64069 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -410,48 +410,39 @@ void StreamPeer::_bind_methods() {
////////////////////////////////
-int StreamPeerExtension::get_available_bytes() const {
- int count;
- if (GDVIRTUAL_CALL(_get_available_bytes, count)) {
- return count;
- }
- WARN_PRINT_ONCE("StreamPeerExtension::_get_available_bytes is unimplemented!");
- return -1;
-}
-
Error StreamPeerExtension::get_data(uint8_t *r_buffer, int p_bytes) {
- int err;
+ Error err;
int received = 0;
if (GDVIRTUAL_CALL(_get_data, r_buffer, p_bytes, &received, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_get_data is unimplemented!");
return FAILED;
}
Error StreamPeerExtension::get_partial_data(uint8_t *r_buffer, int p_bytes, int &r_received) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_get_partial_data, r_buffer, p_bytes, &r_received, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_get_partial_data is unimplemented!");
return FAILED;
}
Error StreamPeerExtension::put_data(const uint8_t *p_data, int p_bytes) {
- int err;
+ Error err;
int sent = 0;
if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &sent, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_put_data is unimplemented!");
return FAILED;
}
Error StreamPeerExtension::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &r_sent, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_put_partial_data is unimplemented!");
return FAILED;
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 4609e52aa2..108a8ce9d9 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -33,6 +33,7 @@
#include "core/object/ref_counted.h"
+#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/script_language.h"
#include "core/variant/native_ptr.h"
@@ -104,16 +105,18 @@ protected:
public:
virtual Error put_data(const uint8_t *p_data, int p_bytes) override;
+ GDVIRTUAL3R(Error, _put_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
+
virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
+ GDVIRTUAL3R(Error, _put_partial_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
+
virtual Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ GDVIRTUAL3R(Error, _get_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
+
virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
- virtual int get_available_bytes() const override;
+ GDVIRTUAL3R(Error, _get_partial_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _put_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _put_partial_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _get_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _get_partial_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL0RC(int, _get_available_bytes);
+ EXBIND0RC(int, get_available_bytes);
};
class StreamPeerBuffer : public StreamPeer {
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_tls.cpp
index 5b90fb52a6..b1adde018a 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_tls.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* stream_peer_ssl.cpp */
+/* stream_peer_tls.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,42 +28,42 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "stream_peer_ssl.h"
+#include "stream_peer_tls.h"
#include "core/config/engine.h"
-StreamPeerSSL *(*StreamPeerSSL::_create)() = nullptr;
+StreamPeerTLS *(*StreamPeerTLS::_create)() = nullptr;
-StreamPeerSSL *StreamPeerSSL::create() {
+StreamPeerTLS *StreamPeerTLS::create() {
if (_create) {
return _create();
}
return nullptr;
}
-bool StreamPeerSSL::available = false;
+bool StreamPeerTLS::available = false;
-bool StreamPeerSSL::is_available() {
+bool StreamPeerTLS::is_available() {
return available;
}
-void StreamPeerSSL::set_blocking_handshake_enabled(bool p_enabled) {
+void StreamPeerTLS::set_blocking_handshake_enabled(bool p_enabled) {
blocking_handshake = p_enabled;
}
-bool StreamPeerSSL::is_blocking_handshake_enabled() const {
+bool StreamPeerTLS::is_blocking_handshake_enabled() const {
return blocking_handshake;
}
-void StreamPeerSSL::_bind_methods() {
- ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll);
- ClassDB::bind_method(D_METHOD("accept_stream", "stream", "private_key", "certificate", "chain"), &StreamPeerSSL::accept_stream, DEFVAL(Ref<X509Certificate>()));
- ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname", "valid_certificate"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()), DEFVAL(Ref<X509Certificate>()));
- ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status);
- ClassDB::bind_method(D_METHOD("get_stream"), &StreamPeerSSL::get_stream);
- ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream);
- ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled);
- ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerSSL::is_blocking_handshake_enabled);
+void StreamPeerTLS::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("poll"), &StreamPeerTLS::poll);
+ ClassDB::bind_method(D_METHOD("accept_stream", "stream", "private_key", "certificate", "chain"), &StreamPeerTLS::accept_stream, DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname", "valid_certificate"), &StreamPeerTLS::connect_to_stream, DEFVAL(false), DEFVAL(String()), DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerTLS::get_status);
+ ClassDB::bind_method(D_METHOD("get_stream"), &StreamPeerTLS::get_stream);
+ ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerTLS::disconnect_from_stream);
+ ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerTLS::set_blocking_handshake_enabled);
+ ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerTLS::is_blocking_handshake_enabled);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_handshake"), "set_blocking_handshake_enabled", "is_blocking_handshake_enabled");
diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_tls.h
index fe68667adc..ed7334fab3 100644
--- a/core/io/stream_peer_ssl.h
+++ b/core/io/stream_peer_tls.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* stream_peer_ssl.h */
+/* stream_peer_tls.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,17 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef STREAM_PEER_SSL_H
-#define STREAM_PEER_SSL_H
+#ifndef STREAM_PEER_TLS_H
+#define STREAM_PEER_TLS_H
#include "core/crypto/crypto.h"
#include "core/io/stream_peer.h"
-class StreamPeerSSL : public StreamPeer {
- GDCLASS(StreamPeerSSL, StreamPeer);
+class StreamPeerTLS : public StreamPeer {
+ GDCLASS(StreamPeerTLS, StreamPeer);
protected:
- static StreamPeerSSL *(*_create)();
+ static StreamPeerTLS *(*_create)();
static void _bind_methods();
static bool available;
@@ -65,13 +65,13 @@ public:
virtual void disconnect_from_stream() = 0;
- static StreamPeerSSL *create();
+ static StreamPeerTLS *create();
static bool is_available();
- StreamPeerSSL() {}
+ StreamPeerTLS() {}
};
-VARIANT_ENUM_CAST(StreamPeerSSL::Status);
+VARIANT_ENUM_CAST(StreamPeerTLS::Status);
-#endif // STREAM_PEER_SSL_H
+#endif // STREAM_PEER_TLS_H
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 154b55f5e7..abae48fdd8 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -137,7 +137,7 @@ bool XMLParser::_parse_cdata() {
next_char();
}
- if (cDataEnd) {
+ if (!cDataEnd) {
cDataEnd = P;
}
node_name = String::utf8(cDataBegin, (int)(cDataEnd - cDataBegin));
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..23d7e379ee
--- /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 Size2i &p_size) {
+ ERR_FAIL_COND(p_size.x < 0 || p_size.y < 0);
+ if (p_size != size) {
+ size = p_size;
+ dirty = true;
+ }
+}
+
+Size2i 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 Size2 &p_cell_size) {
+ if (!cell_size.is_equal_approx(p_cell_size)) {
+ cell_size = p_cell_size;
+ dirty = true;
+ }
+}
+
+Size2 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..bf6363aa01
--- /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:
+ Size2i size;
+ Vector2 offset;
+ Size2 cell_size = Size2(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 Size2i &p_size);
+ Size2i get_size() const;
+
+ void set_offset(const Vector2 &p_offset);
+ Vector2 get_offset() const;
+
+ void set_cell_size(const Size2 &p_cell_size);
+ Size2 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/aabb.h b/core/math/aabb.h
index e88ba33531..acf903eeba 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -47,12 +47,12 @@ struct _NO_DISCARD_ AABB {
Vector3 size;
real_t get_volume() const;
- _FORCE_INLINE_ bool has_no_volume() const {
- return (size.x <= 0 || size.y <= 0 || size.z <= 0);
+ _FORCE_INLINE_ bool has_volume() const {
+ return size.x > 0.0f && size.y > 0.0f && size.z > 0.0f;
}
- _FORCE_INLINE_ bool has_no_surface() const {
- return (size.x <= 0 && size.y <= 0 && size.z <= 0);
+ _FORCE_INLINE_ bool has_surface() const {
+ return size.x > 0.0f || size.y > 0.0f || size.z > 0.0f;
}
const Vector3 &get_position() const { return position; }
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..0eb6320ac6 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
@@ -1094,13 +1033,13 @@ void Basis::rotate_sh(real_t *p_values) {
Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(p_target.is_equal_approx(Vector3()), Basis(), "The target vector can't be zero.");
- ERR_FAIL_COND_V_MSG(p_up.is_equal_approx(Vector3()), Basis(), "The up vector can't be zero.");
+ ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero.");
+ ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero.");
#endif
Vector3 v_z = -p_target.normalized();
Vector3 v_x = p_up.cross(v_z);
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(v_x.is_equal_approx(Vector3()), Basis(), "The target vector and up vector can't be parallel to each other.");
+ ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other.");
#endif
v_x.normalize();
Vector3 v_y = v_z.cross(v_x);
diff --git a/core/math/basis.h b/core/math/basis.h
index 4be325cdd2..cc2924f5ff 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;
@@ -241,10 +238,8 @@ struct _NO_DISCARD_ Basis {
Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); }
static Basis from_scale(const Vector3 &p_scale);
- _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) {
- rows[0] = row0;
- rows[1] = row1;
- rows[2] = row2;
+ _FORCE_INLINE_ Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) {
+ set_columns(p_x_axis, p_y_axis, p_z_axis);
}
_FORCE_INLINE_ Basis() {}
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index ec96753c79..9238293b48 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -35,6 +35,111 @@
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
+void Geometry3D::get_closest_points_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1, Vector3 &r_ps, Vector3 &r_qt) {
+ // Based on David Eberly's Computation of Distance Between Line Segments algorithm.
+
+ Vector3 p = p_p1 - p_p0;
+ Vector3 q = p_q1 - p_q0;
+ Vector3 r = p_p0 - p_q0;
+
+ real_t a = p.dot(p);
+ real_t b = p.dot(q);
+ real_t c = q.dot(q);
+ real_t d = p.dot(r);
+ real_t e = q.dot(r);
+
+ real_t s = 0.0f;
+ real_t t = 0.0f;
+
+ real_t det = a * c - b * b;
+ if (det > CMP_EPSILON) {
+ // Non-parallel segments
+ real_t bte = b * e;
+ real_t ctd = c * d;
+
+ if (bte <= ctd) {
+ // s <= 0.0f
+ if (e <= 0.0f) {
+ // t <= 0.0f
+ s = (-d >= a ? 1 : (-d > 0.0f ? -d / a : 0.0f));
+ t = 0.0f;
+ } else if (e < c) {
+ // 0.0f < t < 1
+ s = 0.0f;
+ t = e / c;
+ } else {
+ // t >= 1
+ s = (b - d >= a ? 1 : (b - d > 0.0f ? (b - d) / a : 0.0f));
+ t = 1;
+ }
+ } else {
+ // s > 0.0f
+ s = bte - ctd;
+ if (s >= det) {
+ // s >= 1
+ if (b + e <= 0.0f) {
+ // t <= 0.0f
+ s = (-d <= 0.0f ? 0.0f : (-d < a ? -d / a : 1));
+ t = 0.0f;
+ } else if (b + e < c) {
+ // 0.0f < t < 1
+ s = 1;
+ t = (b + e) / c;
+ } else {
+ // t >= 1
+ s = (b - d <= 0.0f ? 0.0f : (b - d < a ? (b - d) / a : 1));
+ t = 1;
+ }
+ } else {
+ // 0.0f < s < 1
+ real_t ate = a * e;
+ real_t btd = b * d;
+
+ if (ate <= btd) {
+ // t <= 0.0f
+ s = (-d <= 0.0f ? 0.0f : (-d >= a ? 1 : -d / a));
+ t = 0.0f;
+ } else {
+ // t > 0.0f
+ t = ate - btd;
+ if (t >= det) {
+ // t >= 1
+ s = (b - d <= 0.0f ? 0.0f : (b - d >= a ? 1 : (b - d) / a));
+ t = 1;
+ } else {
+ // 0.0f < t < 1
+ s /= det;
+ t /= det;
+ }
+ }
+ }
+ }
+ } else {
+ // Parallel segments
+ if (e <= 0.0f) {
+ s = (-d <= 0.0f ? 0.0f : (-d >= a ? 1 : -d / a));
+ t = 0.0f;
+ } else if (e >= c) {
+ s = (b - d <= 0.0f ? 0.0f : (b - d >= a ? 1 : (b - d) / a));
+ t = 1;
+ } else {
+ s = 0.0f;
+ t = e / c;
+ }
+ }
+
+ r_ps = (1 - s) * p_p0 + s * p_p1;
+ r_qt = (1 - t) * p_q0 + t * p_q1;
+}
+
+real_t Geometry3D::get_closest_distance_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1) {
+ Vector3 ps;
+ Vector3 qt;
+ get_closest_points_between_segments(p_p0, p_p1, p_q0, p_q1, ps, qt);
+ Vector3 st = qt - ps;
+ return st.length();
+}
+
void Geometry3D::MeshData::optimize_vertices() {
HashMap<int, int> vtx_remap;
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 59c56906f4..e5ace9db72 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -37,96 +37,8 @@
class Geometry3D {
public:
- static void get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2, Vector3 &c1, Vector3 &c2) {
-// Do the function 'd' as defined by pb. I think it's a dot product of some sort.
-#define d_of(m, n, o, p) ((m.x - n.x) * (o.x - p.x) + (m.y - n.y) * (o.y - p.y) + (m.z - n.z) * (o.z - p.z))
-
- // Calculate the parametric position on the 2 curves, mua and mub.
- real_t mua = (d_of(p1, q1, q2, q1) * d_of(q2, q1, p2, p1) - d_of(p1, q1, p2, p1) * d_of(q2, q1, q2, q1)) / (d_of(p2, p1, p2, p1) * d_of(q2, q1, q2, q1) - d_of(q2, q1, p2, p1) * d_of(q2, q1, p2, p1));
- real_t mub = (d_of(p1, q1, q2, q1) + mua * d_of(q2, q1, p2, p1)) / d_of(q2, q1, q2, q1);
-
- // Clip the value between [0..1] constraining the solution to lie on the original curves.
- if (mua < 0) {
- mua = 0;
- }
- if (mub < 0) {
- mub = 0;
- }
- if (mua > 1) {
- mua = 1;
- }
- if (mub > 1) {
- mub = 1;
- }
- c1 = p1.lerp(p2, mua);
- c2 = q1.lerp(q2, mub);
- }
-
- static real_t get_closest_distance_between_segments(const Vector3 &p_from_a, const Vector3 &p_to_a, const Vector3 &p_from_b, const Vector3 &p_to_b) {
- Vector3 u = p_to_a - p_from_a;
- Vector3 v = p_to_b - p_from_b;
- Vector3 w = p_from_a - p_to_a;
- real_t a = u.dot(u); // Always >= 0
- real_t b = u.dot(v);
- real_t c = v.dot(v); // Always >= 0
- real_t d = u.dot(w);
- real_t e = v.dot(w);
- real_t D = a * c - b * b; // Always >= 0
- real_t sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
- real_t tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
-
- // Compute the line parameters of the two closest points.
- if (D < (real_t)CMP_EPSILON) { // The lines are almost parallel.
- sN = 0.0f; // Force using point P0 on segment S1
- sD = 1.0f; // to prevent possible division by 0.0 later.
- tN = e;
- tD = c;
- } else { // Get the closest points on the infinite lines
- sN = (b * e - c * d);
- tN = (a * e - b * d);
- if (sN < 0.0f) { // sc < 0 => the s=0 edge is visible.
- sN = 0.0f;
- tN = e;
- tD = c;
- } else if (sN > sD) { // sc > 1 => the s=1 edge is visible.
- sN = sD;
- tN = e + b;
- tD = c;
- }
- }
-
- if (tN < 0.0f) { // tc < 0 => the t=0 edge is visible.
- tN = 0.0f;
- // Recompute sc for this edge.
- if (-d < 0.0f) {
- sN = 0.0f;
- } else if (-d > a) {
- sN = sD;
- } else {
- sN = -d;
- sD = a;
- }
- } else if (tN > tD) { // tc > 1 => the t=1 edge is visible.
- tN = tD;
- // Recompute sc for this edge.
- if ((-d + b) < 0.0f) {
- sN = 0;
- } else if ((-d + b) > a) {
- sN = sD;
- } else {
- sN = (-d + b);
- sD = a;
- }
- }
- // Finally do the division to get sc and tc.
- sc = (Math::is_zero_approx(sN) ? 0.0f : sN / sD);
- tc = (Math::is_zero_approx(tN) ? 0.0f : tN / tD);
-
- // Get the difference of the two closest points.
- Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
-
- return dP.length(); // Return the closest distance.
- }
+ static void get_closest_points_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1, Vector3 &r_ps, Vector3 &r_qt);
+ static real_t get_closest_distance_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1);
static inline bool ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2, Vector3 *r_res = nullptr) {
Vector3 e1 = p_v1 - p_v0;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 53deb9bd42..656fc9f798 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);
@@ -288,8 +371,8 @@ public:
static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); }
static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); }
- static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
- static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) {
if (is_equal_approx(p_from, p_to)) {
@@ -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/rect2.h b/core/math/rect2.h
index 679af933c2..2d1be3d4f3 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -140,8 +140,8 @@ struct _NO_DISCARD_ Rect2 {
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
}
- _FORCE_INLINE_ bool has_no_area() const {
- return (size.x <= 0 || size.y <= 0);
+ _FORCE_INLINE_ bool has_area() const {
+ return size.x > 0.0f && size.y > 0.0f;
}
// Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
diff --git a/core/math/rect2i.h b/core/math/rect2i.h
index db1459a3e6..2b58dcdd98 100644
--- a/core/math/rect2i.h
+++ b/core/math/rect2i.h
@@ -83,8 +83,8 @@ struct _NO_DISCARD_ Rect2i {
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
}
- _FORCE_INLINE_ bool has_no_area() const {
- return (size.x <= 0 || size.y <= 0);
+ _FORCE_INLINE_ bool has_area() const {
+ return size.x > 0 && size.y > 0;
}
// Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index bb8bf9f569..226076029b 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -217,34 +217,48 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
return t;
}
-Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
Transform2D copy = *this;
- copy.scale(p_scale);
+ copy.scale_basis(p_scale);
return copy;
}
-Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+ // Equivalent to left multiplication
Transform2D copy = *this;
- copy.scale_basis(p_scale);
+ copy.scale(p_scale);
return copy;
}
+Transform2D Transform2D::scaled_local(const Size2 &p_scale) const {
+ // Equivalent to right multiplication
+ return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]);
+}
+
Transform2D Transform2D::untranslated() const {
Transform2D copy = *this;
copy.columns[2] = Vector2();
return copy;
}
+Transform2D Transform2D::translated(const Vector2 &p_offset) const {
+ // Equivalent to left multiplication
+ return Transform2D(columns[0], columns[1], columns[2] + p_offset);
+}
+
Transform2D Transform2D::translated_local(const Vector2 &p_offset) const {
- Transform2D copy = *this;
- copy.translate_local(p_offset);
- return copy;
+ // Equivalent to right multiplication
+ return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset));
}
Transform2D Transform2D::rotated(const real_t p_angle) const {
- Transform2D copy = *this;
- copy.rotate(p_angle);
- return copy;
+ // Equivalent to left multiplication
+ return Transform2D(p_angle, Vector2()) * (*this);
+}
+
+Transform2D Transform2D::rotated_local(const real_t p_angle) const {
+ // Equivalent to right multiplication
+ return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped.
}
real_t Transform2D::basis_determinant() const {
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index e64d050f0c..f23f32867a 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -85,10 +85,13 @@ struct _NO_DISCARD_ Transform2D {
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
- Transform2D scaled(const Size2 &p_scale) const;
Transform2D basis_scaled(const Size2 &p_scale) const;
+ Transform2D scaled(const Size2 &p_scale) const;
+ Transform2D scaled_local(const Size2 &p_scale) const;
+ Transform2D translated(const Vector2 &p_offset) const;
Transform2D translated_local(const Vector2 &p_offset) const;
Transform2D rotated(const real_t p_angle) const;
+ Transform2D rotated_local(const real_t p_angle) const;
Transform2D untranslated() const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index c497a276f3..2de9e81b38 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -62,7 +62,15 @@ void Transform3D::rotate(const Vector3 &p_axis, real_t p_angle) {
}
Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_angle) const {
- return Transform3D(Basis(p_axis, p_angle), Vector3()) * (*this);
+ // Equivalent to left multiplication
+ Basis p_basis(p_axis, p_angle);
+ return Transform3D(p_basis * basis, p_basis.xform(origin));
+}
+
+Transform3D Transform3D::rotated_local(const Vector3 &p_axis, real_t p_angle) const {
+ // Equivalent to right multiplication
+ Basis p_basis(p_axis, p_angle);
+ return Transform3D(basis * p_basis, origin);
}
void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) {
@@ -86,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();
@@ -105,24 +111,19 @@ 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;
}
Transform3D Transform3D::scaled(const Vector3 &p_scale) const {
- Transform3D t = *this;
- t.scale(p_scale);
- return t;
+ // Equivalent to left multiplication
+ return Transform3D(basis.scaled(p_scale), origin * p_scale);
+}
+
+Transform3D Transform3D::scaled_local(const Vector3 &p_scale) const {
+ // Equivalent to right multiplication
+ return Transform3D(basis.scaled_local(p_scale), origin);
}
void Transform3D::scale_basis(const Vector3 &p_scale) {
@@ -139,10 +140,14 @@ void Transform3D::translate_local(const Vector3 &p_translation) {
}
}
+Transform3D Transform3D::translated(const Vector3 &p_translation) const {
+ // Equivalent to left multiplication
+ return Transform3D(basis, origin + p_translation);
+}
+
Transform3D Transform3D::translated_local(const Vector3 &p_translation) const {
- Transform3D t = *this;
- t.translate_local(p_translation);
- return t;
+ // Equivalent to right multiplication
+ return Transform3D(basis, origin + basis.xform(p_translation));
}
void Transform3D::orthonormalize() {
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index 1f8026043f..c62e4a7b0e 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -46,6 +46,7 @@ struct _NO_DISCARD_ Transform3D {
Transform3D affine_inverse() const;
Transform3D rotated(const Vector3 &p_axis, real_t p_angle) const;
+ Transform3D rotated_local(const Vector3 &p_axis, real_t p_angle) const;
void rotate(const Vector3 &p_axis, real_t p_angle);
void rotate_basis(const Vector3 &p_axis, real_t p_angle);
@@ -55,9 +56,11 @@ struct _NO_DISCARD_ Transform3D {
void scale(const Vector3 &p_scale);
Transform3D scaled(const Vector3 &p_scale) const;
+ Transform3D scaled_local(const Vector3 &p_scale) const;
void scale_basis(const Vector3 &p_scale);
void translate_local(real_t p_tx, real_t p_ty, real_t p_tz);
void translate_local(const Vector3 &p_translation);
+ Transform3D translated(const Vector3 &p_translation) const;
Transform3D translated_local(const Vector3 &p_translation) const;
const Basis &get_basis() const { return basis; }
@@ -100,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.cpp b/core/math/vector2.cpp
index d9b5d55454..56dbba393a 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -182,6 +182,10 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const {
return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y);
}
+bool Vector2::is_zero_approx() const {
+ return Math::is_zero_approx(x) && Math::is_zero_approx(y);
+}
+
Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 91d3d3a56b..9441f84087 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;
@@ -123,6 +124,7 @@ struct _NO_DISCARD_ Vector2 {
Vector2 reflect(const Vector2 &p_normal) const;
bool is_equal_approx(const Vector2 &p_v) const;
+ bool is_zero_approx() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
@@ -270,6 +272,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/vector2i.h b/core/math/vector2i.h
index 13b70031bd..0245900a3b 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -115,7 +115,7 @@ struct _NO_DISCARD_ Vector2i {
real_t aspect() const { return width / (real_t)height; }
Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); }
- Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); }
+ Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); }
Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const;
operator String() const;
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index d71d365053..4db45fe798 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -117,18 +117,38 @@ Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
return n.normalized();
}
-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);
- Vector3 row2(z * p_with.x, z * p_with.y, z * p_with.z);
+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;
+}
- return Basis(row0, row1, row2);
+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 {
+ Basis basis;
+ basis.rows[0] = Vector3(x * p_with.x, x * p_with.y, x * p_with.z);
+ basis.rows[1] = Vector3(y * p_with.x, y * p_with.y, y * p_with.z);
+ basis.rows[2] = Vector3(z * p_with.x, z * p_with.y, z * p_with.z);
+ return basis;
}
bool Vector3::is_equal_approx(const Vector3 &p_v) const {
return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z);
}
+bool Vector3::is_zero_approx() const {
+ return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
+}
+
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 970416234d..3944afa92e 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;
@@ -139,6 +142,7 @@ struct _NO_DISCARD_ Vector3 {
_FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const;
bool is_equal_approx(const Vector3 &p_v) const;
+ bool is_zero_approx() const;
/* Operators */
@@ -217,16 +221,25 @@ Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const {
}
Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const {
+ // This method seems more complicated than it really is, since we write out
+ // the internals of some methods for efficiency (mainly, checking length).
real_t start_length_sq = length_squared();
real_t end_length_sq = p_to.length_squared();
if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) {
// Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
return lerp(p_to, p_weight);
}
+ Vector3 axis = cross(p_to);
+ real_t axis_length_sq = axis.length_squared();
+ if (unlikely(axis_length_sq == 0.0f)) {
+ // Colinear vectors have no rotation axis or angle between them, so the best we can do is lerp.
+ return lerp(p_to, p_weight);
+ }
+ axis /= Math::sqrt(axis_length_sq);
real_t start_length = Math::sqrt(start_length_sq);
real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight);
real_t angle = angle_to(p_to);
- return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length);
+ return rotated(axis, angle * p_weight) * (result_length / start_length);
}
Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const {
@@ -237,6 +250,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/vector3i.h b/core/math/vector3i.h
index b49c1142ed..825ce40318 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -128,7 +128,7 @@ double Vector3i::length() const {
}
Vector3i Vector3i::abs() const {
- return Vector3i(ABS(x), ABS(y), ABS(z));
+ return Vector3i(Math::abs(x), Math::abs(y), Math::abs(z));
}
Vector3i Vector3i::sign() const {
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index cc0d0dcf72..3c25f454a3 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -33,24 +33,87 @@
#include "core/math/basis.h"
#include "core/string/print_string.h"
+void Vector4::set_axis(const int p_axis, const real_t p_value) {
+ ERR_FAIL_INDEX(p_axis, 4);
+ components[p_axis] = p_value;
+}
+
+real_t Vector4::get_axis(const int p_axis) const {
+ ERR_FAIL_INDEX_V(p_axis, 4, 0);
+ return operator[](p_axis);
+}
+
+Vector4::Axis Vector4::min_axis_index() const {
+ uint32_t min_index = 0;
+ real_t min_value = x;
+ for (uint32_t i = 1; i < 4; i++) {
+ if (operator[](i) <= min_value) {
+ min_index = i;
+ min_value = operator[](i);
+ }
+ }
+ return Vector4::Axis(min_index);
+}
+
+Vector4::Axis Vector4::max_axis_index() const {
+ uint32_t max_index = 0;
+ real_t max_value = x;
+ for (uint32_t i = 1; i < 4; i++) {
+ if (operator[](i) > max_value) {
+ max_index = i;
+ max_value = operator[](i);
+ }
+ }
+ return Vector4::Axis(max_index);
+}
+
bool Vector4::is_equal_approx(const Vector4 &p_vec4) const {
return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w);
}
+bool Vector4::is_zero_approx() const {
+ return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
+}
+
real_t Vector4::length() const {
return Math::sqrt(length_squared());
}
void Vector4::normalize() {
- *this /= length();
+ real_t lengthsq = length_squared();
+ if (lengthsq == 0) {
+ x = y = z = w = 0;
+ } else {
+ real_t length = Math::sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
+ w /= length;
+ }
}
Vector4 Vector4::normalized() const {
- return *this / length();
+ Vector4 v = *this;
+ v.normalize();
+ return v;
}
bool Vector4::is_normalized() const {
- return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // Use less epsilon.
+ return Math::is_equal_approx(length_squared(), (real_t)1, (real_t)UNIT_EPSILON);
+}
+
+real_t Vector4::distance_to(const Vector4 &p_to) const {
+ return (p_to - *this).length();
+}
+
+real_t Vector4::distance_squared_to(const Vector4 &p_to) const {
+ return (p_to - *this).length_squared();
+}
+
+Vector4 Vector4::direction_to(const Vector4 &p_to) const {
+ Vector4 ret(p_to.x - x, p_to.y - y, p_to.z - z, p_to.w - w);
+ ret.normalize();
+ return ret;
}
Vector4 Vector4::abs() const {
@@ -81,32 +144,47 @@ Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const {
w + (p_weight * (p_to.w - w)));
}
-Vector4 Vector4::inverse() const {
- return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
+Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const {
+ Vector4 res = *this;
+ res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
+ res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
+ res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight);
+ res.w = Math::cubic_interpolate(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight);
+ return res;
}
-Vector4::Axis Vector4::min_axis_index() const {
- uint32_t min_index = 0;
- real_t min_value = x;
- for (uint32_t i = 1; i < 4; i++) {
- if (operator[](i) <= min_value) {
- min_index = i;
- min_value = operator[](i);
- }
- }
- return Vector4::Axis(min_index);
+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::Axis Vector4::max_axis_index() const {
- uint32_t max_index = 0;
- real_t max_value = x;
- for (uint32_t i = 1; i < 4; i++) {
- if (operator[](i) > max_value) {
- max_index = i;
- max_value = operator[](i);
- }
- }
- return Vector4::Axis(max_index);
+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));
+}
+
+Vector4 Vector4::posmodv(const Vector4 &p_modv) const {
+ return Vector4(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z), Math::fposmod(w, p_modv.w));
+}
+
+void Vector4::snap(const Vector4 &p_step) {
+ x = Math::snapped(x, p_step.x);
+ y = Math::snapped(y, p_step.y);
+ z = Math::snapped(z, p_step.z);
+ w = Math::snapped(w, p_step.w);
+}
+
+Vector4 Vector4::snapped(const Vector4 &p_step) const {
+ Vector4 v = *this;
+ v.snap(p_step);
+ return v;
+}
+
+Vector4 Vector4::inverse() const {
+ return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
}
Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
@@ -120,3 +198,5 @@ Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
Vector4::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
+
+static_assert(sizeof(Vector4) == 4 * sizeof(real_t));
diff --git a/core/math/vector4.h b/core/math/vector4.h
index 37ddb509d6..f964264108 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -62,22 +62,40 @@ struct _NO_DISCARD_ Vector4 {
DEV_ASSERT((unsigned int)p_axis < 4);
return components[p_axis];
}
+
+ _FORCE_INLINE_ void set_all(const real_t p_value);
+
+ void set_axis(const int p_axis, const real_t p_value);
+ real_t get_axis(const int p_axis) const;
+
+ Vector4::Axis min_axis_index() const;
+ Vector4::Axis max_axis_index() const;
+
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
+ bool is_zero_approx() const;
real_t length() const;
void normalize();
Vector4 normalized() const;
bool is_normalized() const;
+ real_t distance_to(const Vector4 &p_to) const;
+ real_t distance_squared_to(const Vector4 &p_to) const;
+ Vector4 direction_to(const Vector4 &p_to) const;
+
Vector4 abs() const;
Vector4 sign() const;
Vector4 floor() const;
Vector4 ceil() const;
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::Axis min_axis_index() const;
- Vector4::Axis max_axis_index() const;
+ Vector4 posmod(const real_t p_mod) const;
+ Vector4 posmodv(const Vector4 &p_modv) const;
+ void snap(const Vector4 &p_step);
+ Vector4 snapped(const Vector4 &p_step) const;
Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const;
Vector4 inverse() const;
@@ -130,6 +148,10 @@ struct _NO_DISCARD_ Vector4 {
}
};
+void Vector4::set_all(const real_t p_value) {
+ x = y = z = p_value;
+}
+
real_t Vector4::dot(const Vector4 &p_vec4) const {
return x * p_vec4.x + y * p_vec4.y + z * p_vec4.z + w * p_vec4.w;
}
@@ -193,7 +215,7 @@ Vector4 Vector4::operator/(const Vector4 &p_vec4) const {
}
Vector4 Vector4::operator-() const {
- return Vector4(x, y, z, w);
+ return Vector4(-x, -y, -z, -w);
}
Vector4 Vector4::operator*(const real_t &s) const {
diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp
index 2dc5b74202..a89b802675 100644
--- a/core/math/vector4i.cpp
+++ b/core/math/vector4i.cpp
@@ -84,8 +84,10 @@ Vector4i::operator Vector4() const {
}
Vector4i::Vector4i(const Vector4 &p_vec4) {
- x = p_vec4.x;
- y = p_vec4.y;
- z = p_vec4.z;
- w = p_vec4.w;
+ x = (int32_t)p_vec4.x;
+ y = (int32_t)p_vec4.y;
+ z = (int32_t)p_vec4.z;
+ w = (int32_t)p_vec4.w;
}
+
+static_assert(sizeof(Vector4i) == 4 * sizeof(int32_t));
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index 37d905878f..d08e40d754 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -132,7 +132,7 @@ double Vector4i::length() const {
}
Vector4i Vector4i::abs() const {
- return Vector4i(ABS(x), ABS(y), ABS(z), ABS(w));
+ return Vector4i(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w));
}
Vector4i Vector4i::sign() const {
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index d67315f20d..99b20560da 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -963,8 +963,11 @@ void ClassDB::add_linked_property(const StringName &p_class, const String &p_pro
ERR_FAIL_COND(!type->property_map.has(p_property));
ERR_FAIL_COND(!type->property_map.has(p_linked_property));
- PropertyInfo &pinfo = type->property_map[p_property];
- pinfo.linked_properties.push_back(p_linked_property);
+ if (!type->linked_properties.has(p_property)) {
+ type->linked_properties.insert(p_property, List<StringName>());
+ }
+ type->linked_properties[p_property].push_back(p_linked_property);
+
#endif
}
@@ -978,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);
@@ -992,6 +995,25 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p
}
}
+void ClassDB::get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance) {
+#ifdef TOOLS_ENABLED
+ ClassInfo *check = classes.getptr(p_class);
+ while (check) {
+ if (!check->linked_properties.has(p_property)) {
+ return;
+ }
+ for (const StringName &E : check->linked_properties[p_property]) {
+ r_properties->push_back(E);
+ }
+
+ if (p_no_inheritance) {
+ break;
+ }
+ check = check->inherits_ptr;
+ }
+#endif
+}
+
bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
OBJTYPE_RLOCK;
@@ -1000,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/class_db.h b/core/object/class_db.h
index 8b6a260d86..5fba52e23e 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -120,6 +120,7 @@ public:
List<MethodInfo> virtual_methods;
HashMap<StringName, MethodInfo> virtual_methods_map;
HashMap<StringName, Vector<Error>> method_error_values;
+ HashMap<StringName, List<StringName>> linked_properties;
#endif
HashMap<StringName, PropertySetGet> property_setget;
@@ -312,6 +313,7 @@ public:
static void add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property);
static void get_property_list(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
static bool get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr);
+ static void get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance = false);
static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr);
static bool get_property(Object *p_object, const StringName &p_property, Variant &r_value);
static bool has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance = false);
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index a4474ea53b..0edc7a90c2 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -63,7 +63,7 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
PropertyInfo info = _gen_argument_type_info(p_argument);
#ifdef DEBUG_METHODS_ENABLED
- info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("arg" + itos(p_argument));
+ info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
#endif
return info;
}
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 75dbe8872f..c275164b14 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()));
}
@@ -472,7 +473,6 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {
if (script_instance && p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
@@ -503,7 +503,6 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
if (script_instance && !p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
@@ -517,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 {
@@ -758,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) {
@@ -860,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();
@@ -1007,7 +1060,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
}
}
- bool disconnect = c.flags & CONNECT_ONESHOT;
+ bool disconnect = c.flags & CONNECT_ONE_SHOT;
#ifdef TOOLS_ENABLED
if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
//this signal was connected from the editor, and is being edited. just don't disconnect for now
@@ -1057,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));
}
@@ -1069,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) {
@@ -1084,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]);
@@ -1502,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"));
@@ -1515,7 +1575,7 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
- BIND_ENUM_CONSTANT(CONNECT_ONESHOT);
+ BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
diff --git a/core/object/object.h b/core/object/object.h
index 649f42c9a0..8ade5a204a 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -45,9 +45,12 @@
#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.
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only")
@@ -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
};
@@ -154,9 +159,7 @@ struct PropertyInfo {
String hint_string;
uint32_t usage = PROPERTY_USAGE_DEFAULT;
-#ifdef TOOLS_ENABLED
- Vector<String> linked_properties;
-#endif
+ // If you are thinking about adding another member to this class, ask the maintainer (Juan) first.
_FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const {
PropertyInfo pi = *this;
@@ -209,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,
@@ -296,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;
@@ -471,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; \
} \
@@ -501,7 +537,7 @@ public:
enum ConnectFlags {
CONNECT_DEFERRED = 1,
CONNECT_PERSIST = 2, // hint for scene to save this connection
- CONNECT_ONESHOT = 4,
+ CONNECT_ONE_SHOT = 4,
CONNECT_REFERENCE_COUNTED = 8,
};
@@ -566,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);
@@ -615,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())() {
@@ -635,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;
}
@@ -652,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);
@@ -759,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 226fd8b791..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) {
@@ -101,6 +102,31 @@ Dictionary Script::_get_script_constant_map() {
return ret;
}
+#ifdef TOOLS_ENABLED
+
+PropertyInfo Script::get_class_category() const {
+ String path = get_path();
+ String name;
+
+ if (is_built_in()) {
+ if (get_name().is_empty()) {
+ name = TTR("Built-in script");
+ } else {
+ name = vformat("%s (%s)", get_name(), TTR("Built-in"));
+ }
+ } else {
+ if (get_name().is_empty()) {
+ name = path.get_file();
+ } else {
+ name = get_name();
+ }
+ }
+
+ return PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY);
+}
+
+#endif // TOOLS_ENABLED
+
void Script::_bind_methods() {
ClassDB::bind_method(D_METHOD("can_instantiate"), &Script::can_instantiate);
//ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create);
diff --git a/core/object/script_language.h b/core/object/script_language.h
index c9f8a4f828..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:
@@ -132,6 +134,7 @@ public:
#ifdef TOOLS_ENABLED
virtual Vector<DocData::ClassDoc> get_documentation() const = 0;
+ virtual PropertyInfo get_class_category() const;
#endif // TOOLS_ENABLED
virtual bool has_method(const StringName &p_method) const = 0;
@@ -170,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);
@@ -446,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 10eacfd9f7..7e74f6a2be 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -663,6 +663,14 @@ public:
if (native_info->get_property_list_func) {
uint32_t pcount;
const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount);
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_script();
+ if (script->is_valid() && pcount > 0) {
+ p_list->push_back(script->get_class_category());
+ }
+#endif // TOOLS_ENABLED
+
for (uint32_t i = 0; i < pcount; i++) {
p_list->push_back(PropertyInfo(pinfo[i]));
}
@@ -684,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.cpp b/core/os/keyboard.cpp
index a592791d06..f3be495c8e 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -61,12 +61,16 @@ static const _KeyCodeText _keycodes[] = {
{Key::PAGEDOWN ,"PageDown"},
{Key::SHIFT ,"Shift"},
{Key::CTRL ,"Ctrl"},
-#ifdef MACOS_ENABLED
+#if defined(MACOS_ENABLED)
{Key::META ,"Command"},
+ {Key::ALT ,"Option"},
+#elif defined(WINDOWS_ENABLED)
+ {Key::META ,"Windows"},
+ {Key::ALT ,"Alt"},
#else
{Key::META ,"Meta"},
-#endif
{Key::ALT ,"Alt"},
+#endif
{Key::CAPSLOCK ,"CapsLock"},
{Key::NUMLOCK ,"NumLock"},
{Key::SCROLLLOCK ,"ScrollLock"},
@@ -437,6 +441,14 @@ String keycode_get_string(Key p_code) {
codestr += find_keycode_name(Key::ALT);
codestr += "+";
}
+ if ((p_code & KeyModifierMask::CMD_OR_CTRL) != Key::NONE) {
+#ifdef MACOS_ENABLED
+ codestr += find_keycode_name(Key::META);
+#else
+ codestr += find_keycode_name(Key::CTRL);
+#endif
+ codestr += "+";
+ }
if ((p_code & KeyModifierMask::CTRL) != Key::NONE) {
codestr += find_keycode_name(Key::CTRL);
codestr += "+";
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 517a53e505..e5d9b24e85 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -36,11 +36,11 @@
enum class Key {
NONE = 0,
// Special key: The strategy here is similar to the one used by toolkits,
- // which consists in leaving the 24 bits unicode range for printable
- // characters, and use the upper 8 bits for special keys and modifiers.
+ // which consists in leaving the 21 bits unicode range for printable
+ // characters, and use the upper 11 bits for special keys and modifiers.
// This way everything (char/keycode) can fit nicely in one 32-bit
// integer (the enum's underlying type is `int` by default).
- SPECIAL = (1 << 24),
+ SPECIAL = (1 << 22),
/* CURSOR/FUNCTION/BROWSER/MULTIMEDIA/MISC KEYS */
ESCAPE = SPECIAL | 0x01,
TAB = SPECIAL | 0x02,
@@ -312,84 +312,85 @@ enum class Key {
};
enum class KeyModifierMask {
- CODE_MASK = ((1 << 25) - 1), ///< Apply this mask to any keycode to remove modifiers.
- MODIFIER_MASK = (0x7F << 24), ///< Apply this mask to isolate modifiers.
+ CODE_MASK = ((1 << 23) - 1), ///< Apply this mask to any keycode to remove modifiers.
+ MODIFIER_MASK = (0x7F << 22), ///< Apply this mask to isolate modifiers.
+ //RESERVED = (1 << 23),
+ CMD_OR_CTRL = (1 << 24),
SHIFT = (1 << 25),
ALT = (1 << 26),
META = (1 << 27),
CTRL = (1 << 28),
-#ifdef APPLE_STYLE_KEYS
- CMD = META,
-#else
- CMD = CTRL,
-#endif
KPAD = (1 << 29),
GROUP_SWITCH = (1 << 30)
};
// 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/memory.h b/core/os/memory.h
index 42ba9634e2..0e1afe027e 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -36,6 +36,7 @@
#include <stddef.h>
#include <new>
+#include <type_traits>
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
@@ -104,7 +105,7 @@ void memdelete(T *p_class) {
if (!predelete_handler(p_class)) {
return; // doesn't want to be deleted
}
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
p_class->~T();
}
@@ -116,7 +117,7 @@ void memdelete_allocator(T *p_class) {
if (!predelete_handler(p_class)) {
return; // doesn't want to be deleted
}
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
p_class->~T();
}
@@ -146,7 +147,7 @@ T *memnew_arr_template(size_t p_elements) {
ERR_FAIL_COND_V(!mem, failptr);
*(mem - 1) = p_elements;
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
T *elems = (T *)mem;
/* call operator new */
@@ -173,7 +174,7 @@ template <typename T>
void memdelete_arr(T *p_class) {
uint64_t *ptr = (uint64_t *)p_class;
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
uint64_t elem_count = *(ptr - 1);
for (uint64_t i = 0; i < elem_count; i++) {
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 1ae5d1c83f..6650d9be23 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -58,12 +58,13 @@
#include "core/io/resource_format_binary.h"
#include "core/io/resource_importer.h"
#include "core/io/resource_uid.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/translation_loader_po.h"
#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"
@@ -201,7 +202,7 @@ void register_core_types() {
ClassDB::register_custom_instance_class<CryptoKey>();
ClassDB::register_custom_instance_class<HMACContext>();
ClassDB::register_custom_instance_class<Crypto>();
- ClassDB::register_custom_instance_class<StreamPeerSSL>();
+ ClassDB::register_custom_instance_class<StreamPeerTLS>();
ClassDB::register_custom_instance_class<PacketPeerDTLS>();
ClassDB::register_custom_instance_class<DTLSServer>();
@@ -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);
@@ -269,6 +271,7 @@ void register_core_types() {
_marshalls = memnew(core_bind::Marshalls);
_engine_debugger = memnew(core_bind::EngineDebugger);
+ GDREGISTER_NATIVE_STRUCT(ObjectID, "uint64_t id = 0");
GDREGISTER_NATIVE_STRUCT(AudioFrame, "float left;float right");
GDREGISTER_NATIVE_STRUCT(ScriptLanguageExtensionProfilingInfo, "StringName signature;uint64_t call_count;uint64_t total_time;uint64_t self_time");
@@ -281,8 +284,8 @@ void register_core_settings() {
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/tcp/connect_timeout_seconds", PropertyInfo(Variant::INT, "network/limits/tcp/connect_timeout_seconds", PROPERTY_HINT_RANGE, "1,1800,1"));
GLOBAL_DEF_RST("network/limits/packet_peer_stream/max_buffer_po2", (16));
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/packet_peer_stream/max_buffer_po2", PropertyInfo(Variant::INT, "network/limits/packet_peer_stream/max_buffer_po2", PROPERTY_HINT_RANGE, "0,64,1,or_greater"));
- GLOBAL_DEF("network/ssl/certificate_bundle_override", "");
- ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificate_bundle_override", PropertyInfo(Variant::STRING, "network/ssl/certificate_bundle_override", PROPERTY_HINT_FILE, "*.crt"));
+ GLOBAL_DEF("network/tls/certificate_bundle_override", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("network/tls/certificate_bundle_override", PropertyInfo(Variant::STRING, "network/tls/certificate_bundle_override", PROPERTY_HINT_FILE, "*.crt"));
int worker_threads = GLOBAL_DEF("threading/worker_pool/max_threads", -1);
bool low_priority_use_system_threads = GLOBAL_DEF("threading/worker_pool/use_system_threads_for_low_priority_tasks", true);
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index cba2f09022..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);
}
}
@@ -141,7 +141,7 @@ void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
- ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages);
+ ClassDB::bind_method(D_METHOD("_set_messages", "messages"), &Translation::_set_messages);
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
GDVIRTUAL_BIND(_get_plural_message, "src_message", "src_plural_message", "n", "context");
@@ -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..b8ae3c2392 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,11 +373,9 @@ 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);
-
CharString ascii(bool p_allow_extended = false) const;
CharString utf8() const;
Error parse_utf8(const char *p_utf8, int p_len = -1, bool p_skip_cr = false);
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index e760fc2176..f98b2308c9 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -36,6 +36,7 @@
#include "core/templates/safe_refcount.h"
#include <string.h>
+#include <type_traits>
template <class T>
class Vector;
@@ -158,6 +159,7 @@ public:
return _ptr[p_index];
}
+ template <bool p_ensure_zero = false>
Error resize(int p_size);
_FORCE_INLINE_ void remove_at(int p_index) {
@@ -204,7 +206,7 @@ void CowData<T>::_unref(void *p_data) {
}
// clean up
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
uint32_t *count = _get_size();
T *data = (T *)(count + 1);
@@ -239,7 +241,7 @@ uint32_t CowData<T>::_copy_on_write() {
T *_data = (T *)(mem_new);
// initialize new elements
- if (__has_trivial_copy(T)) {
+ if (std::is_trivially_copyable<T>::value) {
memcpy(mem_new, _ptr, current_size * sizeof(T));
} else {
@@ -257,6 +259,7 @@ uint32_t CowData<T>::_copy_on_write() {
}
template <class T>
+template <bool p_ensure_zero>
Error CowData<T>::resize(int p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
@@ -302,16 +305,18 @@ Error CowData<T>::resize(int p_size) {
// construct the newly created elements
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&_ptr[i], T);
}
+ } else if (p_ensure_zero) {
+ memset((void *)(_ptr + current_size), 0, (p_size - current_size) * sizeof(T));
}
*_get_size() = p_size;
} else if (p_size < current_size) {
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
// deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) {
T *t = &_ptr[i];
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 8d687effcf..49690f2373 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -37,6 +37,7 @@
#include "core/templates/vector.h"
#include <initializer_list>
+#include <type_traits>
// If tight, it grows strictly as much as needed.
// Otherwise, it grows exponentially (the default and what you want in most cases).
@@ -67,7 +68,7 @@ public:
CRASH_COND_MSG(!data, "Out of memory");
}
- if (!__has_trivial_constructor(T) && !force_trivial) {
+ if (!std::is_trivially_constructible<T>::value && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = p_elem;
@@ -80,7 +81,7 @@ public:
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
}
- if (!__has_trivial_destructor(T) && !force_trivial) {
+ if (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
@@ -93,7 +94,7 @@ public:
if (count > p_index) {
data[p_index] = data[count];
}
- if (!__has_trivial_destructor(T) && !force_trivial) {
+ if (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
@@ -134,7 +135,7 @@ public:
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
- if (!__has_trivial_destructor(T) && !force_trivial) {
+ if (!std::is_trivially_destructible<T>::value && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
@@ -151,7 +152,7 @@ public:
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
- if (!__has_trivial_constructor(T) && !force_trivial) {
+ if (!std::is_trivially_constructible<T>::value && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h
index 33d2757bec..f1ede556e6 100644
--- a/core/templates/paged_array.h
+++ b/core/templates/paged_array.h
@@ -35,6 +35,8 @@
#include "core/os/spin_lock.h"
#include "core/typedefs.h"
+#include <type_traits>
+
// PagedArray is used mainly for filling a very large array from multiple threads efficiently and without causing major fragmentation
// PageArrayPool manages central page allocation in a thread safe matter
@@ -197,7 +199,7 @@ public:
uint32_t page = count >> page_size_shift;
uint32_t offset = count & page_size_mask;
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
memnew_placement(&page_data[page][offset], T(p_value));
} else {
page_data[page][offset] = p_value;
@@ -209,7 +211,7 @@ public:
_FORCE_INLINE_ void pop_back() {
ERR_FAIL_COND(count == 0);
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
uint32_t page = (count - 1) >> page_size_shift;
uint32_t offset = (count - 1) & page_size_mask;
page_data[page][offset].~T();
@@ -226,7 +228,7 @@ public:
void clear() {
//destruct if needed
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
for (uint64_t i = 0; i < count; i++) {
uint32_t page = i >> page_size_shift;
uint32_t offset = i & page_size_mask;
@@ -309,13 +311,13 @@ public:
uint32_t to_copy = MIN(page_size - new_remainder, remainder);
for (uint32_t i = 0; i < to_copy; i++) {
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
memnew_placement(&dst_page[i + new_remainder], T(remainder_page[i + remainder - to_copy]));
} else {
dst_page[i + new_remainder] = remainder_page[i + remainder - to_copy];
}
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
remainder_page[i + remainder - to_copy].~T();
}
}
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index 9c74b41818..320faebe98 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -79,7 +79,7 @@ class RID_Alloc : public RID_AllocBase {
const char *description = nullptr;
- SpinLock spin_lock;
+ mutable SpinLock spin_lock;
_FORCE_INLINE_ RID _allocate_rid() {
if (THREAD_SAFE) {
@@ -220,7 +220,7 @@ public:
memnew_placement(mem, T(p_value));
}
- _FORCE_INLINE_ bool owns(const RID &p_rid) {
+ _FORCE_INLINE_ bool owns(const RID &p_rid) const {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -292,7 +292,7 @@ public:
_FORCE_INLINE_ uint32_t get_rid_count() const {
return alloc_count;
}
- void get_owned_list(List<RID> *p_owned) {
+ void get_owned_list(List<RID> *p_owned) const {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -308,7 +308,7 @@ public:
}
//used for fast iteration in the elements or RIDs
- void fill_owned_buffer(RID *p_rid_buffer) {
+ void fill_owned_buffer(RID *p_rid_buffer) const {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -402,7 +402,7 @@ public:
*ptr = p_new_ptr;
}
- _FORCE_INLINE_ bool owns(const RID &p_rid) {
+ _FORCE_INLINE_ bool owns(const RID &p_rid) const {
return alloc.owns(p_rid);
}
@@ -414,11 +414,11 @@ public:
return alloc.get_rid_count();
}
- _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
+ _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) const {
return alloc.get_owned_list(p_owned);
}
- void fill_owned_buffer(RID *p_rid_buffer) {
+ void fill_owned_buffer(RID *p_rid_buffer) const {
alloc.fill_owned_buffer(p_rid_buffer);
}
@@ -458,7 +458,7 @@ public:
return alloc.get_or_null(p_rid);
}
- _FORCE_INLINE_ bool owns(const RID &p_rid) {
+ _FORCE_INLINE_ bool owns(const RID &p_rid) const {
return alloc.owns(p_rid);
}
@@ -470,10 +470,10 @@ public:
return alloc.get_rid_count();
}
- _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
+ _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) const {
return alloc.get_owned_list(p_owned);
}
- void fill_owned_buffer(RID *p_rid_buffer) {
+ void fill_owned_buffer(RID *p_rid_buffer) const {
alloc.fill_owned_buffer(p_rid_buffer);
}
diff --git a/core/templates/vector.h b/core/templates/vector.h
index f3f5ed76a7..51595a75f5 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -89,6 +89,7 @@ public:
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); }
+ Error resize_zeroed(int p_size) { return _cowdata.template resize<true>(p_size); }
_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); }
Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); }
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index d9f4359ee5..c1cb782a57 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -195,6 +195,15 @@ bool Dictionary::has_all(const Array &p_keys) const {
return true;
}
+Variant Dictionary::find_key(const Variant &p_value) const {
+ for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
+ if (E.value == p_value) {
+ return E.key;
+ }
+ }
+ return Variant();
+}
+
bool Dictionary::erase(const Variant &p_key) {
ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state.");
if (p_key.get_type() == Variant::STRING_NAME) {
diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h
index 2632893e8d..d9c9db56cf 100644
--- a/core/variant/dictionary.h
+++ b/core/variant/dictionary.h
@@ -66,6 +66,7 @@ public:
bool has(const Variant &p_key) const;
bool has_all(const Array &p_keys) const;
+ Variant find_key(const Variant &p_value) const;
bool erase(const Variant &p_key);
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 b933a90a48..f09885b325 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());
@@ -1602,12 +1605,14 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, normalized, sarray(), varray());
bind_method(Vector2, is_normalized, sarray(), varray());
bind_method(Vector2, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector2, is_zero_approx, sarray(), varray());
bind_method(Vector2, posmod, sarray("mod"), varray());
bind_method(Vector2, posmodv, sarray("modv"), varray());
bind_method(Vector2, project, sarray("b"), varray());
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());
@@ -1645,7 +1650,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, get_center, sarray(), varray());
bind_method(Rect2, get_area, sarray(), varray());
- bind_method(Rect2, has_no_area, sarray(), varray());
+ bind_method(Rect2, has_area, sarray(), varray());
bind_method(Rect2, has_point, sarray("point"), varray());
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
@@ -1662,7 +1667,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2i, get_center, sarray(), varray());
bind_method(Rect2i, get_area, sarray(), varray());
- bind_method(Rect2i, has_no_area, sarray(), varray());
+ bind_method(Rect2i, has_area, sarray(), varray());
bind_method(Rect2i, has_point, sarray("point"), varray());
bind_method(Rect2i, intersects, sarray("b"), varray());
bind_method(Rect2i, encloses, sarray("b"), varray());
@@ -1689,6 +1694,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, normalized, sarray(), varray());
bind_method(Vector3, is_normalized, sarray(), varray());
bind_method(Vector3, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector3, is_zero_approx, sarray(), varray());
bind_method(Vector3, inverse, sarray(), varray());
bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
@@ -1696,6 +1702,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());
@@ -1737,12 +1744,21 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, ceil, sarray(), varray());
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());
bind_method(Vector4, clamp, sarray("min", "max"), varray());
bind_method(Vector4, normalized, sarray(), varray());
bind_method(Vector4, is_normalized, sarray(), varray());
+ bind_method(Vector4, direction_to, sarray("to"), varray());
+ bind_method(Vector4, distance_to, sarray("to"), varray());
+ bind_method(Vector4, distance_squared_to, sarray("to"), varray());
bind_method(Vector4, dot, sarray("with"), varray());
bind_method(Vector4, inverse, sarray(), varray());
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
+ bind_method(Vector4, is_zero_approx, sarray(), varray());
/* Vector4i */
@@ -1782,6 +1798,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());
@@ -1882,7 +1899,10 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, get_skew, sarray(), varray());
bind_method(Transform2D, orthonormalized, sarray(), varray());
bind_method(Transform2D, rotated, sarray("angle"), varray());
+ bind_method(Transform2D, rotated_local, sarray("angle"), varray());
bind_method(Transform2D, scaled, sarray("scale"), varray());
+ bind_method(Transform2D, scaled_local, sarray("scale"), varray());
+ bind_method(Transform2D, translated, sarray("offset"), varray());
bind_method(Transform2D, translated_local, sarray("offset"), varray());
bind_method(Transform2D, basis_xform, sarray("v"), varray());
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
@@ -1906,7 +1926,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());
@@ -1919,8 +1938,8 @@ static void _register_variant_builtin_methods() {
bind_method(AABB, abs, sarray(), varray());
bind_method(AABB, get_center, sarray(), varray());
bind_method(AABB, get_volume, sarray(), varray());
- bind_method(AABB, has_no_volume, sarray(), varray());
- bind_method(AABB, has_no_surface, sarray(), varray());
+ bind_method(AABB, has_volume, sarray(), varray());
+ bind_method(AABB, has_surface, sarray(), varray());
bind_method(AABB, has_point, sarray("point"), varray());
bind_method(AABB, is_equal_approx, sarray("aabb"), varray());
bind_method(AABB, intersects, sarray("with"), varray());
@@ -1947,10 +1966,12 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, affine_inverse, sarray(), varray());
bind_method(Transform3D, orthonormalized, sarray(), varray());
bind_method(Transform3D, rotated, sarray("axis", "angle"), varray());
+ bind_method(Transform3D, rotated_local, sarray("axis", "angle"), varray());
bind_method(Transform3D, scaled, sarray("scale"), varray());
+ bind_method(Transform3D, scaled_local, sarray("scale"), varray());
+ 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());
@@ -1996,6 +2017,7 @@ static void _register_variant_builtin_methods() {
bind_method(Dictionary, merge, sarray("dictionary", "overwrite"), varray(false));
bind_method(Dictionary, has, sarray("key"), varray());
bind_method(Dictionary, has_all, sarray("keys"), varray());
+ bind_method(Dictionary, find_key, sarray("value"), varray());
bind_method(Dictionary, erase, sarray("key"), varray());
bind_method(Dictionary, hash, sarray(), varray());
bind_method(Dictionary, keys, sarray(), varray());
@@ -2054,7 +2076,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, remove_at, sarray("index"), varray());
bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedByteArray, fill, sarray("value"), varray());
- bind_method(PackedByteArray, resize, sarray("new_size"), varray());
+ bind_methodv(PackedByteArray, resize, &PackedByteArray::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedByteArray, clear, sarray(), varray());
bind_method(PackedByteArray, has, sarray("value"), varray());
bind_method(PackedByteArray, reverse, sarray(), varray());
bind_method(PackedByteArray, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2118,7 +2141,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, remove_at, sarray("index"), varray());
bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt32Array, fill, sarray("value"), varray());
- bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedInt32Array, resize, &PackedInt32Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedInt32Array, clear, sarray(), varray());
bind_method(PackedInt32Array, has, sarray("value"), varray());
bind_method(PackedInt32Array, reverse, sarray(), varray());
bind_method(PackedInt32Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2141,7 +2165,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, remove_at, sarray("index"), varray());
bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt64Array, fill, sarray("value"), varray());
- bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedInt64Array, resize, &PackedInt64Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedInt64Array, clear, sarray(), varray());
bind_method(PackedInt64Array, has, sarray("value"), varray());
bind_method(PackedInt64Array, reverse, sarray(), varray());
bind_method(PackedInt64Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2164,7 +2189,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, remove_at, sarray("index"), varray());
bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat32Array, fill, sarray("value"), varray());
- bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedFloat32Array, resize, &PackedFloat32Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedFloat32Array, clear, sarray(), varray());
bind_method(PackedFloat32Array, has, sarray("value"), varray());
bind_method(PackedFloat32Array, reverse, sarray(), varray());
bind_method(PackedFloat32Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2187,7 +2213,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, remove_at, sarray("index"), varray());
bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat64Array, fill, sarray("value"), varray());
- bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedFloat64Array, resize, &PackedFloat64Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedFloat64Array, clear, sarray(), varray());
bind_method(PackedFloat64Array, has, sarray("value"), varray());
bind_method(PackedFloat64Array, reverse, sarray(), varray());
bind_method(PackedFloat64Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2211,6 +2238,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedStringArray, fill, sarray("value"), varray());
bind_method(PackedStringArray, resize, sarray("new_size"), varray());
+ bind_method(PackedStringArray, clear, sarray(), varray());
bind_method(PackedStringArray, has, sarray("value"), varray());
bind_method(PackedStringArray, reverse, sarray(), varray());
bind_method(PackedStringArray, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2234,6 +2262,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector2Array, fill, sarray("value"), varray());
bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector2Array, clear, sarray(), varray());
bind_method(PackedVector2Array, has, sarray("value"), varray());
bind_method(PackedVector2Array, reverse, sarray(), varray());
bind_method(PackedVector2Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2257,6 +2286,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector3Array, fill, sarray("value"), varray());
bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector3Array, clear, sarray(), varray());
bind_method(PackedVector3Array, has, sarray("value"), varray());
bind_method(PackedVector3Array, reverse, sarray(), varray());
bind_method(PackedVector3Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2280,6 +2310,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedColorArray, fill, sarray("value"), varray());
bind_method(PackedColorArray, resize, sarray("new_size"), varray());
+ bind_method(PackedColorArray, clear, sarray(), varray());
bind_method(PackedColorArray, has, sarray("value"), varray());
bind_method(PackedColorArray, reverse, sarray(), varray());
bind_method(PackedColorArray, slice, sarray("begin", "end"), varray(INT_MAX));
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_op.cpp b/core/variant/variant_op.cpp
index 669e18b5f7..6cca7955ae 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -341,6 +341,8 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform3D>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorXForm<::AABB, Transform3D, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::AABB);
register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform3D>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorXForm<Plane, Transform3D, Plane>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PLANE);
+ register_op<OperatorEvaluatorXFormInv<Plane, Plane, Transform3D>>(Variant::OP_MULTIPLY, Variant::PLANE, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform3D, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PACKED_VECTOR3_ARRAY);
register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform3D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM3D);
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index 34653310b1..8151ff2102 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1680,7 +1680,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} break;
case Variant::OBJECT: {
- Object *obj = p_variant;
+ Object *obj = p_variant.get_validated_object();
if (!obj) {
p_store_string_func(p_store_string_ud, "null");
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index c1a0ad73b0..7ff64c88f0 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -99,18 +99,105 @@ struct VariantUtilityFunctions {
return Math::posmod(b, r);
}
- static inline double floor(double x) {
+ static inline Variant floor(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::floor(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).floor();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).floor();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).floor();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double floorf(double x) {
return Math::floor(x);
}
- static inline double ceil(double x) {
+ static inline int floori(double x) {
+ return int(x);
+ }
+
+ static inline Variant ceil(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::ceil(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).ceil();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).ceil();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).ceil();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double ceilf(double x) {
return Math::ceil(x);
}
- static inline double round(double x) {
+ static inline int ceili(double x) {
+ return int(Math::ceil(x));
+ }
+
+ static inline Variant round(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::round(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).round();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).round();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).round();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double roundf(double x) {
return Math::round(x);
}
+ static inline int roundi(double x) {
+ return int(Math::round(x));
+ }
+
static inline Variant abs(const Variant &x, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
switch (x.get_type()) {
@@ -235,7 +322,44 @@ struct VariantUtilityFunctions {
return Math::snapped(value, step);
}
- static inline double lerp(double from, double to, double weight) {
+ static inline Variant lerp(const Variant &from, const Variant &to, double weight, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ if (from.get_type() != to.get_type()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ return Variant();
+ }
+
+ switch (from.get_type()) {
+ case Variant::FLOAT: {
+ return lerpf(VariantInternalAccessor<double>::get(&from), to, weight);
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&from).lerp(VariantInternalAccessor<Vector2>::get(&to), weight);
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&from).lerp(VariantInternalAccessor<Vector3>::get(&to), weight);
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&from).lerp(VariantInternalAccessor<Vector4>::get(&to), weight);
+ } break;
+ case Variant::QUATERNION: {
+ return VariantInternalAccessor<Quaternion>::get(&from).slerp(VariantInternalAccessor<Quaternion>::get(&to), weight);
+ } break;
+ case Variant::BASIS: {
+ return VariantInternalAccessor<Basis>::get(&from).slerp(VariantInternalAccessor<Basis>::get(&to), weight);
+ } break;
+ case Variant::COLOR: {
+ return VariantInternalAccessor<Color>::get(&from).lerp(VariantInternalAccessor<Color>::get(&to), weight);
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double lerpf(double from, double to, double weight) {
return Math::lerp(from, to, weight);
}
@@ -243,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);
}
@@ -255,8 +393,8 @@ struct VariantUtilityFunctions {
return Math::inverse_lerp(from, to, weight);
}
- static inline double range_lerp(double value, double istart, double istop, double ostart, double ostop) {
- return Math::range_lerp(value, istart, istop, ostart, ostop);
+ static inline double remap(double value, double istart, double istop, double ostart, double ostop) {
+ return Math::remap(value, istart, istop, ostart, ostop);
}
static inline double smoothstep(double from, double to, double val) {
@@ -267,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) {
@@ -708,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;
@@ -726,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) {
@@ -746,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) {
@@ -766,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();
@@ -778,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();
@@ -1252,17 +1390,24 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(posmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDVR(abs, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDVR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(floorf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(floori, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDVR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(ceilf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(ceili, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(roundf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(roundi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVR(abs, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(absf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(absi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVR(sign, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
-
FUNCBINDR(signf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(signi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1280,32 +1425,34 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ 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);
- FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(remap, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);
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);
FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVARARG(max, sarray(), Variant::UTILITY_FUNC_TYPE_MATH);
-
FUNCBINDR(maxi, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(maxf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVARARG(min, sarray(), Variant::UTILITY_FUNC_TYPE_MATH);
-
FUNCBINDR(mini, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(minf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1343,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);