summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/engine.h2
-rw-r--r--core/config/project_settings.cpp76
-rw-r--r--core/core_bind.cpp218
-rw-r--r--core/core_bind.h25
-rw-r--r--core/core_constants.cpp6
-rw-r--r--core/core_string_names.cpp1
-rw-r--r--core/core_string_names.h1
-rw-r--r--core/crypto/crypto.cpp8
-rw-r--r--core/crypto/crypto.h8
-rw-r--r--core/debugger/engine_profiler.cpp14
-rw-r--r--core/debugger/engine_profiler.h2
-rw-r--r--core/debugger/local_debugger.cpp8
-rw-r--r--core/debugger/remote_debugger.cpp17
-rw-r--r--core/debugger/remote_debugger.h2
-rw-r--r--core/debugger/remote_debugger_peer.cpp10
-rw-r--r--core/debugger/remote_debugger_peer.h14
-rw-r--r--core/doc_data.h2
-rw-r--r--core/error/error_macros.cpp2
-rw-r--r--core/error/error_macros.h24
-rw-r--r--core/extension/SCsub6
-rw-r--r--core/extension/extension_api_dump.cpp30
-rw-r--r--core/extension/gdnative_interface.cpp32
-rw-r--r--core/extension/gdnative_interface.h99
-rw-r--r--core/extension/make_wrappers.py93
-rw-r--r--core/extension/native_extension.cpp70
-rw-r--r--core/extension/native_extension.h13
-rw-r--r--core/extension/native_extension_manager.cpp18
-rw-r--r--core/input/gamecontrollerdb.txt1126
-rw-r--r--core/input/godotcontrollerdb.txt3
-rw-r--r--core/input/input.cpp26
-rw-r--r--core/input/input.h19
-rw-r--r--core/input/input_event.cpp46
-rw-r--r--core/input/input_map.cpp2
-rw-r--r--core/io/config_file.cpp45
-rw-r--r--core/io/config_file.h4
-rw-r--r--core/io/dir_access.cpp100
-rw-r--r--core/io/dir_access.h37
-rw-r--r--core/io/file_access.cpp58
-rw-r--r--core/io/file_access.h33
-rw-r--r--core/io/file_access_compressed.cpp76
-rw-r--r--core/io/file_access_compressed.h7
-rw-r--r--core/io/file_access_encrypted.cpp42
-rw-r--r--core/io/file_access_encrypted.h10
-rw-r--r--core/io/file_access_memory.cpp6
-rw-r--r--core/io/file_access_memory.h3
-rw-r--r--core/io/file_access_network.cpp11
-rw-r--r--core/io/file_access_network.h13
-rw-r--r--core/io/file_access_pack.cpp145
-rw-r--r--core/io/file_access_pack.h37
-rw-r--r--core/io/file_access_zip.cpp52
-rw-r--r--core/io/file_access_zip.h9
-rw-r--r--core/io/http_client_tcp.cpp3
-rw-r--r--core/io/image.cpp148
-rw-r--r--core/io/image.h21
-rw-r--r--core/io/image_loader.cpp37
-rw-r--r--core/io/image_loader.h6
-rw-r--r--core/io/ip.cpp13
-rw-r--r--core/io/ip.h5
-rw-r--r--core/io/logger.cpp32
-rw-r--r--core/io/logger.h17
-rw-r--r--core/io/marshalls.cpp35
-rw-r--r--core/io/missing_resource.cpp90
-rw-r--r--core/io/missing_resource.h63
-rw-r--r--core/io/packed_data_container.cpp2
-rw-r--r--core/io/packet_peer_udp.cpp4
-rw-r--r--core/io/packet_peer_udp.h2
-rw-r--r--core/io/pck_packer.cpp61
-rw-r--r--core/io/pck_packer.h3
-rw-r--r--core/io/resource.cpp46
-rw-r--r--core/io/resource.h3
-rw-r--r--core/io/resource_format_binary.cpp461
-rw-r--r--core/io/resource_format_binary.h46
-rw-r--r--core/io/resource_importer.cpp21
-rw-r--r--core/io/resource_importer.h2
-rw-r--r--core/io/resource_loader.cpp52
-rw-r--r--core/io/resource_loader.h16
-rw-r--r--core/io/resource_saver.cpp12
-rw-r--r--core/io/resource_saver.h17
-rw-r--r--core/io/resource_uid.cpp20
-rw-r--r--core/io/resource_uid.h2
-rw-r--r--core/io/stream_peer.h1
-rw-r--r--core/io/stream_peer_tcp.cpp87
-rw-r--r--core/io/stream_peer_tcp.h12
-rw-r--r--core/io/translation_loader_po.cpp432
-rw-r--r--core/io/translation_loader_po.h4
-rw-r--r--core/io/udp_server.h2
-rw-r--r--core/io/xml_parser.cpp4
-rw-r--r--core/io/zip_io.cpp50
-rw-r--r--core/io/zip_io.h10
-rw-r--r--core/math/a_star.cpp148
-rw-r--r--core/math/a_star.h12
-rw-r--r--core/math/basis.cpp358
-rw-r--r--core/math/basis.h165
-rw-r--r--core/math/bvh.h297
-rw-r--r--core/math/bvh_abb.h64
-rw-r--r--core/math/bvh_cull.inc95
-rw-r--r--core/math/bvh_debug.inc4
-rw-r--r--core/math/bvh_logic.inc16
-rw-r--r--core/math/bvh_misc.inc6
-rw-r--r--core/math/bvh_pair.inc14
-rw-r--r--core/math/bvh_public.inc146
-rw-r--r--core/math/bvh_split.inc18
-rw-r--r--core/math/bvh_structs.inc89
-rw-r--r--core/math/bvh_tree.h56
-rw-r--r--core/math/camera_matrix.cpp48
-rw-r--r--core/math/camera_matrix.h1
-rw-r--r--core/math/color.h6
-rw-r--r--core/math/color_names.inc292
-rw-r--r--core/math/convex_hull.cpp8
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/math/expression.h2
-rw-r--r--core/math/face3.cpp6
-rw-r--r--core/math/face3.h2
-rw-r--r--core/math/geometry_2d.cpp24
-rw-r--r--core/math/geometry_2d.h10
-rw-r--r--core/math/geometry_3d.cpp6
-rw-r--r--core/math/geometry_3d.h30
-rw-r--r--core/math/math_fieldwise.cpp48
-rw-r--r--core/math/math_funcs.h54
-rw-r--r--core/math/octree.h37
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/quaternion.cpp21
-rw-r--r--core/math/quaternion.h4
-rw-r--r--core/math/random_pcg.h6
-rw-r--r--core/math/rect2.cpp32
-rw-r--r--core/math/transform_2d.cpp124
-rw-r--r--core/math/transform_2d.h91
-rw-r--r--core/math/transform_3d.cpp24
-rw-r--r--core/math/transform_3d.h12
-rw-r--r--core/math/triangle_mesh.cpp20
-rw-r--r--core/math/vector2.cpp2
-rw-r--r--core/math/vector2.h3
-rw-r--r--core/math/vector2i.h3
-rw-r--r--core/math/vector3.cpp42
-rw-r--r--core/math/vector3.h50
-rw-r--r--core/math/vector3i.cpp7
-rw-r--r--core/math/vector3i.h9
-rw-r--r--core/object/callable_method_pointer.h2
-rw-r--r--core/object/class_db.cpp258
-rw-r--r--core/object/class_db.h166
-rw-r--r--core/object/make_virtuals.py10
-rw-r--r--core/object/message_queue.cpp41
-rw-r--r--core/object/message_queue.h47
-rw-r--r--core/object/method_bind.cpp6
-rw-r--r--core/object/method_bind.h325
-rw-r--r--core/object/object.cpp204
-rw-r--r--core/object/object.h86
-rw-r--r--core/object/ref_counted.cpp4
-rw-r--r--core/object/ref_counted.h6
-rw-r--r--core/object/script_language.cpp16
-rw-r--r--core/object/script_language.h162
-rw-r--r--core/object/script_language_extension.cpp180
-rw-r--r--core/object/script_language_extension.h835
-rw-r--r--core/object/undo_redo.cpp117
-rw-r--r--core/object/undo_redo.h38
-rw-r--r--core/os/keyboard.cpp4
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/main_loop.h1
-rw-r--r--core/os/memory.h6
-rw-r--r--core/os/os.cpp44
-rw-r--r--core/os/os.h10
-rw-r--r--core/os/pool_allocator.cpp4
-rw-r--r--core/os/pool_allocator.h26
-rw-r--r--core/os/thread.cpp1
-rw-r--r--core/os/thread.h1
-rw-r--r--core/os/time.cpp162
-rw-r--r--core/os/time.h9
-rw-r--r--core/register_core_types.cpp55
-rw-r--r--core/register_core_types.h1
-rw-r--r--core/string/optimized_translation.cpp4
-rw-r--r--core/string/print_string.cpp2
-rw-r--r--core/string/print_string.h12
-rw-r--r--core/string/string_name.cpp17
-rw-r--r--core/string/string_name.h15
-rw-r--r--core/string/translation.cpp12
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/translation_po.cpp3
-rw-r--r--core/string/ustring.cpp130
-rw-r--r--core/string/ustring.h5
-rw-r--r--core/templates/command_queue_mt.h10
-rw-r--r--core/templates/cowdata.h25
-rw-r--r--core/templates/map.h6
-rw-r--r--core/templates/oa_hash_map.h24
-rw-r--r--core/templates/paged_allocator.h2
-rw-r--r--core/templates/pooled_list.h149
-rw-r--r--core/templates/safe_list.h38
-rw-r--r--core/templates/self_list.h2
-rw-r--r--core/templates/set.h4
-rw-r--r--core/templates/thread_work_pool.h4
-rw-r--r--core/templates/vector.h19
-rw-r--r--core/typedefs.h45
-rw-r--r--core/variant/array.cpp27
-rw-r--r--core/variant/array.h4
-rw-r--r--core/variant/binder_common.h10
-rw-r--r--core/variant/callable.cpp16
-rw-r--r--core/variant/callable.h6
-rw-r--r--core/variant/callable_bind.cpp16
-rw-r--r--core/variant/callable_bind.h32
-rw-r--r--core/variant/native_ptr.h1
-rw-r--r--core/variant/type_info.h34
-rw-r--r--core/variant/variant.cpp150
-rw-r--r--core/variant/variant.h28
-rw-r--r--core/variant/variant_call.cpp44
-rw-r--r--core/variant/variant_construct.cpp12
-rw-r--r--core/variant/variant_construct.h6
-rw-r--r--core/variant/variant_op.cpp1
-rw-r--r--core/variant/variant_parser.cpp21
-rw-r--r--core/variant/variant_parser.h16
-rw-r--r--core/variant/variant_setget.cpp140
-rw-r--r--core/variant/variant_setget.h12
-rw-r--r--core/variant/variant_utility.cpp93
211 files changed, 6686 insertions, 4413 deletions
diff --git a/core/config/engine.h b/core/config/engine.h
index 1adab9b96f..eac96852b3 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -40,7 +40,7 @@ class Engine {
public:
struct Singleton {
StringName name;
- Object *ptr;
+ Object *ptr = nullptr;
StringName class_name; //used for binding generation hinting
bool user_created = false;
Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName());
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 3a7fc828aa..79fa6a0895 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -145,7 +145,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
return p_path.simplify_path();
}
- DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String path = p_path.replace("\\", "/").simplify_path();
@@ -153,8 +153,6 @@ String ProjectSettings::localize_path(const String &p_path) const {
String cwd = dir->get_current_dir();
cwd = cwd.replace("\\", "/");
- memdelete(dir);
-
// Ensure that we end with a '/'.
// This is important to ensure that we do not wrongly localize the resource path
// in an absolute path that just happens to contain this string but points to a
@@ -173,8 +171,6 @@ String ProjectSettings::localize_path(const String &p_path) const {
return cwd.replace_first(res_path, "res://");
} else {
- memdelete(dir);
-
int sep = path.rfind("/");
if (sep == -1) {
return "res://" + path;
@@ -325,9 +321,9 @@ bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const {
struct _VCSort {
String name;
- Variant::Type type;
- int order;
- uint32_t flags;
+ Variant::Type type = Variant::VARIANT_MAX;
+ int order = 0;
+ uint32_t flags = 0;
bool operator<(const _VCSort &p_vcs) const { return order == p_vcs.order ? name < p_vcs.name : order < p_vcs.order; }
};
@@ -541,8 +537,8 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Nothing was found, try to find a project file in provided path (`p_path`)
// or, if requested (`p_upwards`) in parent directories.
- DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V_MSG(!d, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_path + "'.");
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_path + "'.");
d->change_dir(p_path);
String current_dir = d->get_current_dir();
@@ -573,8 +569,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
}
}
- memdelete(d);
-
if (!found) {
return err;
}
@@ -614,26 +608,19 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
bool ProjectSettings::has_setting(String p_var) const {
_THREAD_SAFE_METHOD_
- StringName name = p_var;
- if (!disable_feature_overrides && feature_overrides.has(name)) {
- name = feature_overrides[name];
- }
- return props.has(name);
+ return props.has(p_var);
}
Error ProjectSettings::_load_settings_binary(const String &p_path) {
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err != OK) {
return err;
}
uint8_t hdr[4];
f->get_buffer(hdr, 4);
- if (hdr[0] != 'E' || hdr[1] != 'C' || hdr[2] != 'F' || hdr[3] != 'G') {
- memdelete(f);
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Corrupted header in binary project.binary (not ECFG).");
- }
+ ERR_FAIL_COND_V_MSG((hdr[0] != 'E' || hdr[1] != 'C' || hdr[2] != 'F' || hdr[3] != 'G'), ERR_FILE_CORRUPT, "Corrupted header in binary project.binary (not ECFG).");
uint32_t count = f->get_32();
@@ -656,16 +643,14 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) {
set(key, value);
}
- f->close();
- memdelete(f);
return OK;
}
Error ProjectSettings::_load_settings_text(const String &p_path) {
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
+ if (f.is_null()) {
// FIXME: Above 'err' error code is ERR_FILE_CANT_OPEN if the file is missing
// This needs to be streamlined if we want decent error reporting
return ERR_FILE_NOT_FOUND;
@@ -690,25 +675,18 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
- memdelete(f);
// 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"));
return OK;
- } else if (err != OK) {
- ERR_PRINT("Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
- memdelete(f);
- return err;
}
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
if (!assign.is_empty()) {
if (section.is_empty() && assign == "config_version") {
config_version = value;
- if (config_version > CONFIG_VERSION) {
- memdelete(f);
- ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, vformat("Can't open project at '%s', its `config_version` (%d) is from a more recent and incompatible version of the engine. Expected config version: %d.", p_path, config_version, CONFIG_VERSION));
- }
+ ERR_FAIL_COND_V_MSG(config_version > CONFIG_VERSION, ERR_FILE_CANT_OPEN, vformat("Can't open project at '%s', its `config_version` (%d) is from a more recent and incompatible version of the engine. Expected config version: %d.", p_path, config_version, CONFIG_VERSION));
} else {
if (section.is_empty()) {
set(assign, value);
@@ -788,7 +766,7 @@ Error ProjectSettings::save() {
Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
- FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
+ Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.binary at " + p_file + ".");
uint8_t hdr[4] = { 'E', 'C', 'F', 'G' };
@@ -808,19 +786,13 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
int len;
err = encode_variant(p_custom_features, nullptr, len, false);
- if (err != OK) {
- memdelete(file);
- ERR_FAIL_V(err);
- }
+ ERR_FAIL_COND_V(err != OK, err);
Vector<uint8_t> buff;
buff.resize(len);
err = encode_variant(p_custom_features, buff.ptrw(), len, false);
- if (err != OK) {
- memdelete(file);
- ERR_FAIL_V(err);
- }
+ ERR_FAIL_COND_V(err != OK, err);
file->store_32(len);
file->store_buffer(buff.ptr(), buff.size());
@@ -844,33 +816,24 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
int len;
err = encode_variant(value, nullptr, len, true);
- if (err != OK) {
- memdelete(file);
- }
ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant.");
Vector<uint8_t> buff;
buff.resize(len);
err = encode_variant(value, buff.ptrw(), len, true);
- if (err != OK) {
- memdelete(file);
- }
ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant.");
file->store_32(len);
file->store_buffer(buff.ptr(), buff.size());
}
}
- file->close();
- memdelete(file);
-
return OK;
}
Error ProjectSettings::_save_settings_text(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
- FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
+ Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.godot - " + p_file + ".");
@@ -915,9 +878,6 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin
}
}
- file->close();
- memdelete(file);
-
return OK;
}
@@ -1203,6 +1163,8 @@ ProjectSettings::ProjectSettings() {
singleton = this;
GLOBAL_DEF_BASIC("application/config/name", "");
+ GLOBAL_DEF_BASIC("application/config/name_localized", Dictionary());
+ custom_prop_info["application/config/name_localized"] = PropertyInfo(Variant::DICTIONARY, "application/config/name_localized", PROPERTY_HINT_LOCALIZABLE_STRING);
GLOBAL_DEF_BASIC("application/config/description", "");
custom_prop_info["application/config/description"] = PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT);
GLOBAL_DEF_BASIC("application/run/main_scene", "");
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index bb4b49d9cd..7c3cbfe48d 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -58,15 +58,15 @@ ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const
return (ThreadLoadStatus)tls;
}
-RES ResourceLoader::load_threaded_get(const String &p_path) {
+Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path) {
Error error;
- RES res = ::ResourceLoader::load_threaded_get(p_path, &error);
+ Ref<Resource> res = ::ResourceLoader::load_threaded_get(p_path, &error);
return res;
}
-RES ResourceLoader::load(const String &p_path, const String &p_type_hint, CacheMode p_cache_mode) {
+Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hint, CacheMode p_cache_mode) {
Error err = OK;
- RES ret = ::ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err);
+ Ref<Resource> ret = ::ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err);
ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'.");
return ret;
@@ -137,12 +137,12 @@ void ResourceLoader::_bind_methods() {
////// ResourceSaver //////
-Error ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) {
+Error ResourceSaver::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + String(p_path) + "'.");
return ::ResourceSaver::save(p_path, p_resource, p_flags);
}
-Vector<String> ResourceSaver::get_recognized_extensions(const RES &p_resource) {
+Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource) {
ERR_FAIL_COND_V_MSG(p_resource.is_null(), Vector<String>(), "It's not a reference to a valid Resource object.");
List<String> exts;
::ResourceSaver::get_recognized_extensions(p_resource, &exts);
@@ -156,9 +156,10 @@ Vector<String> ResourceSaver::get_recognized_extensions(const RES &p_resource) {
ResourceSaver *ResourceSaver::singleton = nullptr;
void ResourceSaver::_bind_methods() {
- ClassDB::bind_method(D_METHOD("save", "path", "resource", "flags"), &ResourceSaver::save, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("save", "path", "resource", "flags"), &ResourceSaver::save, DEFVAL((uint32_t)FLAG_NONE));
ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &ResourceSaver::get_recognized_extensions);
+ BIND_ENUM_CONSTANT(FLAG_NONE);
BIND_ENUM_CONSTANT(FLAG_RELATIVE_PATHS);
BIND_ENUM_CONSTANT(FLAG_BUNDLE_RESOURCES);
BIND_ENUM_CONSTANT(FLAG_CHANGE_PATH);
@@ -268,6 +269,10 @@ Error OS::kill(int p_pid) {
return ::OS::get_singleton()->kill(p_pid);
}
+bool OS::is_process_running(int p_pid) const {
+ return ::OS::get_singleton()->is_process_running(p_pid);
+}
+
int OS::get_process_id() const {
return ::OS::get_singleton()->get_process_id();
}
@@ -482,6 +487,10 @@ 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);
+}
+
String OS::get_user_data_dir() const {
return ::OS::get_singleton()->get_user_data_dir();
}
@@ -566,6 +575,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill);
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &OS::shell_open);
+ ClassDB::bind_method(D_METHOD("is_process_running", "pid"), &OS::is_process_running);
ClassDB::bind_method(D_METHOD("get_process_id"), &OS::get_process_id);
ClassDB::bind_method(D_METHOD("get_environment", "variable"), &OS::get_environment);
@@ -596,6 +606,7 @@ void OS::_bind_methods() {
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);
+ ClassDB::bind_method(D_METHOD("move_to_trash", "path"), &OS::move_to_trash);
ClassDB::bind_method(D_METHOD("get_user_data_dir"), &OS::get_user_data_dir);
ClassDB::bind_method(D_METHOD("get_system_dir", "dir", "shared_storage"), &OS::get_system_dir, DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_config_dir"), &OS::get_config_dir);
@@ -1026,10 +1037,10 @@ Error File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const V
return err;
}
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
err = fae->open_and_parse(f, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
if (err) {
- memdelete(fae);
close();
return err;
}
@@ -1043,10 +1054,10 @@ Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, co
return err;
}
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
err = fae->open_and_parse_password(f, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
if (err) {
- memdelete(fae);
close();
return err;
}
@@ -1056,14 +1067,13 @@ Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, co
}
Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
- FileAccessCompressed *fac = memnew(FileAccessCompressed);
-
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
fac->configure("GCPF", (Compression::Mode)p_compress_mode);
Error err = fac->_open(p_path, p_mode_flags);
if (err) {
- memdelete(fac);
return err;
}
@@ -1072,25 +1082,22 @@ Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, Compre
}
Error File::open(const String &p_path, ModeFlags p_mode_flags) {
- close();
Error err;
f = FileAccess::open(p_path, p_mode_flags, &err);
- if (f) {
+ if (f.is_valid()) {
f->set_big_endian(big_endian);
}
return err;
}
void File::flush() {
- ERR_FAIL_COND_MSG(!f, "File must be opened before flushing.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before flushing.");
f->flush();
}
void File::close() {
- if (f) {
- memdelete(f);
- }
- f = nullptr;
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened.");
+ f.unref();
}
bool File::is_open() const {
@@ -1098,79 +1105,79 @@ bool File::is_open() const {
}
String File::get_path() const {
- ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
return f->get_path();
}
String File::get_path_absolute() const {
- ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
return f->get_path_absolute();
}
void File::seek(int64_t p_position) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer.");
f->seek(p_position);
}
void File::seek_end(int64_t p_position) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->seek_end(p_position);
}
uint64_t File::get_position() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_position();
}
uint64_t File::get_length() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_length();
}
bool File::eof_reached() const {
- ERR_FAIL_COND_V_MSG(!f, false, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use, or is lacking read-write permission.");
return f->eof_reached();
}
uint8_t File::get_8() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_8();
}
uint16_t File::get_16() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_16();
}
uint32_t File::get_32() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_32();
}
uint64_t File::get_64() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_64();
}
float File::get_float() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_float();
}
double File::get_double() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_double();
}
real_t File::get_real() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_real();
}
Vector<uint8_t> File::get_buffer(int64_t p_length) const {
Vector<uint8_t> data;
- ERR_FAIL_COND_V_MSG(!f, data, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), data, "File must be opened before use, or is lacking read-write permission.");
ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
if (p_length == 0) {
@@ -1191,11 +1198,11 @@ Vector<uint8_t> File::get_buffer(int64_t p_length) const {
}
String File::get_as_text() const {
- ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
String text;
uint64_t original_pos = f->get_position();
- f->seek(0);
+ const_cast<FileAccess *>(*f)->seek(0);
String l = get_line();
while (!eof_reached()) {
@@ -1204,7 +1211,7 @@ String File::get_as_text() const {
}
text += l;
- f->seek(original_pos);
+ const_cast<FileAccess *>(*f)->seek(original_pos);
return text;
}
@@ -1218,12 +1225,12 @@ String File::get_sha256(const String &p_path) const {
}
String File::get_line() const {
- ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
return f->get_line();
}
Vector<String> File::get_csv_line(const String &p_delim) const {
- ERR_FAIL_COND_V_MSG(!f, Vector<String>(), "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), Vector<String>(), "File must be opened before use, or is lacking read-write permission.");
return f->get_csv_line(p_delim);
}
@@ -1234,7 +1241,7 @@ Vector<String> File::get_csv_line(const String &p_delim) const {
void File::set_big_endian(bool p_big_endian) {
big_endian = p_big_endian;
- if (f) {
+ if (f.is_valid()) {
f->set_big_endian(p_big_endian);
}
}
@@ -1244,84 +1251,84 @@ bool File::is_big_endian() {
}
Error File::get_error() const {
- if (!f) {
+ if (f.is_null()) {
return ERR_UNCONFIGURED;
}
return f->get_error();
}
void File::store_8(uint8_t p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_8(p_dest);
}
void File::store_16(uint16_t p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_16(p_dest);
}
void File::store_32(uint32_t p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_32(p_dest);
}
void File::store_64(uint64_t p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_64(p_dest);
}
void File::store_float(float p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_float(p_dest);
}
void File::store_double(double p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_double(p_dest);
}
void File::store_real(real_t p_real) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_real(p_real);
}
void File::store_string(const String &p_string) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_string(p_string);
}
void File::store_pascal_string(const String &p_string) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_pascal_string(p_string);
}
String File::get_pascal_string() {
- ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
return f->get_pascal_string();
}
void File::store_line(const String &p_string) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_line(p_string);
}
void File::store_csv_line(const Vector<String> &p_values, const String &p_delim) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_csv_line(p_values, p_delim);
}
void File::store_buffer(const Vector<uint8_t> &p_buffer) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
uint64_t len = p_buffer.size();
if (len == 0) {
@@ -1333,12 +1340,12 @@ void File::store_buffer(const Vector<uint8_t> &p_buffer) {
f->store_buffer(&r[0], len);
}
-bool File::file_exists(const String &p_name) const {
+bool File::file_exists(const String &p_name) {
return FileAccess::exists(p_name);
}
void File::store_var(const Variant &p_var, bool p_full_objects) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
int len;
Error err = encode_variant(p_var, nullptr, len, p_full_objects);
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
@@ -1355,7 +1362,7 @@ void File::store_var(const Variant &p_var, bool p_full_objects) {
}
Variant File::get_var(bool p_allow_objects) const {
- ERR_FAIL_COND_V_MSG(!f, Variant(), "File must be opened before use, or is lacking read-write permission.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), Variant(), "File must be opened before use, or is lacking read-write permission.");
uint32_t len = get_32();
Vector<uint8_t> buff = get_buffer(len);
ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
@@ -1423,7 +1430,7 @@ void File::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &File::store_pascal_string);
ClassDB::bind_method(D_METHOD("get_pascal_string"), &File::get_pascal_string);
- ClassDB::bind_method(D_METHOD("file_exists", "path"), &File::file_exists);
+ ClassDB::bind_static_method("File", D_METHOD("file_exists", "path"), &File::file_exists);
ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &File::get_modified_time);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
@@ -1439,24 +1446,14 @@ void File::_bind_methods() {
BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
}
-File::~File() {
- if (f) {
- memdelete(f);
- }
-}
-
////// Directory //////
Error Directory::open(const String &p_path) {
Error err;
- DirAccess *alt = DirAccess::open(p_path, &err);
-
- if (!alt) {
+ Ref<DirAccess> alt = DirAccess::open(p_path, &err);
+ if (alt.is_null()) {
return err;
}
- if (d) {
- memdelete(d);
- }
d = alt;
dir_open = true;
@@ -1464,7 +1461,7 @@ Error Directory::open(const String &p_path) {
}
bool Directory::is_open() const {
- return d && dir_open;
+ return d.is_valid() && dir_open;
}
Error Directory::list_dir_begin() {
@@ -1549,7 +1546,7 @@ int Directory::get_current_drive() {
}
Error Directory::change_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
+ ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
Error err = d->change_dir(p_dir);
if (err != OK) {
@@ -1566,50 +1563,41 @@ String Directory::get_current_dir() {
}
Error Directory::make_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
+ ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_dir);
- Error err = d->make_dir(p_dir);
- memdelete(d);
- return err;
+ Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
+ return da->make_dir(p_dir);
}
return d->make_dir(p_dir);
}
Error Directory::make_dir_recursive(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
+ ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_dir);
- Error err = d->make_dir_recursive(p_dir);
- memdelete(d);
- return err;
+ Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
+ return da->make_dir_recursive(p_dir);
}
return d->make_dir_recursive(p_dir);
}
bool Directory::file_exists(String p_file) {
- ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly.");
+ ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
if (!p_file.is_relative_path()) {
return FileAccess::exists(p_file);
}
-
return d->file_exists(p_file);
}
bool Directory::dir_exists(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly.");
+ ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_dir);
- bool exists = d->dir_exists(p_dir);
- memdelete(d);
- return exists;
+ return DirAccess::exists(p_dir);
}
-
return d->dir_exists(p_dir);
}
uint64_t Directory::get_space_left() {
- ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(d.is_null(), 0, "Directory must be opened before use.");
return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB.
}
@@ -1623,11 +1611,9 @@ Error Directory::rename(String p_from, String p_to) {
ERR_FAIL_COND_V_MSG(p_from.is_empty() || p_from == "." || p_from == "..", ERR_INVALID_PARAMETER, "Invalid path to rename.");
if (!p_from.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_from);
- ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
- Error err = d->rename(p_from, p_to);
- memdelete(d);
- return err;
+ Ref<DirAccess> da = DirAccess::create_for_path(p_from);
+ ERR_FAIL_COND_V_MSG(!da->file_exists(p_from) && !da->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
+ return da->rename(p_from, p_to);
}
ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
@@ -1637,10 +1623,8 @@ Error Directory::rename(String p_from, String p_to) {
Error Directory::remove(String p_name) {
ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
if (!p_name.is_relative_path()) {
- DirAccess *d = DirAccess::create_for_path(p_name);
- Error err = d->remove(p_name);
- memdelete(d);
- return err;
+ Ref<DirAccess> da = DirAccess::create_for_path(p_name);
+ return da->remove(p_name);
}
return d->remove(p_name);
@@ -1663,7 +1647,6 @@ void Directory::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &Directory::make_dir_recursive);
ClassDB::bind_method(D_METHOD("file_exists", "path"), &Directory::file_exists);
ClassDB::bind_method(D_METHOD("dir_exists", "path"), &Directory::dir_exists);
- //ClassDB::bind_method(D_METHOD("get_modified_time","file"),&Directory::get_modified_time);
ClassDB::bind_method(D_METHOD("get_space_left"), &Directory::get_space_left);
ClassDB::bind_method(D_METHOD("copy", "from", "to"), &Directory::copy);
ClassDB::bind_method(D_METHOD("rename", "from", "to"), &Directory::rename);
@@ -1682,12 +1665,6 @@ Directory::Directory() {
d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
}
-Directory::~Directory() {
- if (d) {
- memdelete(d);
- }
-}
-
////// Marshalls //////
Marshalls *Marshalls::singleton = nullptr;
@@ -1998,7 +1975,7 @@ Variant ClassDB::instantiate(const StringName &p_class) const {
RefCounted *r = Object::cast_to<RefCounted>(obj);
if (r) {
- return REF(r);
+ return Ref<RefCounted>(r);
} else {
return obj;
}
@@ -2106,10 +2083,6 @@ int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p
return c;
}
-StringName ClassDB::get_category(const StringName &p_node) const {
- return ::ClassDB::get_category(p_node);
-}
-
bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) const {
return ::ClassDB::has_enum(p_class, p_name, p_no_inheritance);
}
@@ -2181,7 +2154,6 @@ void ClassDB::_bind_methods() {
::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::get_enum_constants, DEFVAL(false));
::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::get_integer_constant_enum, DEFVAL(false));
- ::ClassDB::bind_method(D_METHOD("class_get_category", "class"), &ClassDB::get_category);
::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled);
}
@@ -2309,6 +2281,18 @@ Vector<String> Engine::get_singleton_list() const {
return ret;
}
+void Engine::register_script_language(ScriptLanguage *p_language) {
+ ScriptServer::register_language(p_language);
+}
+
+int Engine::get_script_language_count() {
+ return ScriptServer::get_language_count();
+}
+
+ScriptLanguage *Engine::get_script_language(int p_index) const {
+ return ScriptServer::get_language(p_index);
+}
+
void Engine::set_editor_hint(bool p_enabled) {
::Engine::get_singleton()->set_editor_hint(p_enabled);
}
@@ -2360,6 +2344,10 @@ void Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("unregister_singleton", "name"), &Engine::unregister_singleton);
ClassDB::bind_method(D_METHOD("get_singleton_list"), &Engine::get_singleton_list);
+ ClassDB::bind_method(D_METHOD("register_script_language", "language"), &Engine::register_script_language);
+ ClassDB::bind_method(D_METHOD("get_script_language_count"), &Engine::get_script_language_count);
+ ClassDB::bind_method(D_METHOD("get_script_language", "index"), &Engine::get_script_language);
+
ClassDB::bind_method(D_METHOD("is_editor_hint"), &Engine::is_editor_hint);
ClassDB::bind_method(D_METHOD("set_print_error_messages", "enabled"), &Engine::set_print_error_messages);
diff --git a/core/core_bind.h b/core/core_bind.h
index 1ed243206b..76313dc1a8 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -38,6 +38,7 @@
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
+#include "core/object/script_language.h"
#include "core/os/os.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
@@ -72,9 +73,9 @@ public:
Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false);
ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = Array());
- RES load_threaded_get(const String &p_path);
+ Ref<Resource> load_threaded_get(const String &p_path);
- RES load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
Vector<String> get_recognized_extensions_for_type(const String &p_type);
void set_abort_on_missing_resources(bool p_abort);
PackedStringArray get_dependencies(const String &p_path);
@@ -94,6 +95,7 @@ protected:
public:
enum SaverFlags {
+ FLAG_NONE = 0,
FLAG_RELATIVE_PATHS = 1,
FLAG_BUNDLE_RESOURCES = 2,
FLAG_CHANGE_PATH = 4,
@@ -105,8 +107,8 @@ public:
static ResourceSaver *get_singleton() { return singleton; }
- Error save(const String &p_path, const RES &p_resource, SaverFlags p_flags);
- Vector<String> get_recognized_extensions(const RES &p_resource);
+ Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags);
+ Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource);
ResourceSaver() { singleton = this; }
};
@@ -171,6 +173,7 @@ public:
Error kill(int p_pid);
Error shell_open(String p_uri);
+ bool is_process_running(int p_pid) const;
int get_process_id() const;
bool has_environment(const String &p_var) const;
@@ -233,6 +236,7 @@ public:
String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const;
+ Error move_to_trash(const String &p_path) const;
String get_user_data_dir() const;
String get_config_dir() const;
String get_data_dir() const;
@@ -347,7 +351,7 @@ public:
class File : public RefCounted {
GDCLASS(File, RefCounted);
- FileAccess *f = nullptr;
+ Ref<FileAccess> f;
bool big_endian = false;
protected:
@@ -435,17 +439,16 @@ public:
void store_var(const Variant &p_var, bool p_full_objects = false);
- bool file_exists(const String &p_name) const; // Return true if a file exists.
+ static bool file_exists(const String &p_name); // Return true if a file exists.
uint64_t get_modified_time(const String &p_file) const;
File() {}
- virtual ~File();
};
class Directory : public RefCounted {
GDCLASS(Directory, RefCounted);
- DirAccess *d;
+ Ref<DirAccess> d;
bool dir_open = false;
bool include_navigational = false;
@@ -493,7 +496,6 @@ public:
Error remove(String p_name);
Directory();
- virtual ~Directory();
};
class Marshalls : public Object {
@@ -603,7 +605,6 @@ public:
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;
int get_integer_constant(const StringName &p_class, const StringName &p_name) const;
- StringName get_category(const StringName &p_node) const;
bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
PackedStringArray get_enum_list(const StringName &p_class, bool p_no_inheritance = false) const;
@@ -663,6 +664,10 @@ public:
void unregister_singleton(const StringName &p_name);
Vector<String> get_singleton_list() const;
+ void register_script_language(ScriptLanguage *p_language);
+ int get_script_language_count();
+ ScriptLanguage *get_script_language(int p_index) const;
+
void set_editor_hint(bool p_enabled);
bool is_editor_hint() const;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 63e7323f7a..2a514b68d8 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -41,7 +41,7 @@ struct _CoreConstant {
StringName enum_name;
bool ignore_value_in_docs = false;
#endif
- const char *name;
+ const char *name = nullptr;
int value = 0;
_CoreConstant() {}
@@ -168,6 +168,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_IMAGE_MASK);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TEXT_MASK);
+ BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPECIAL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ESCAPE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TAB);
@@ -422,6 +423,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, KPAD);
BIND_CORE_ENUM_CLASS_CONSTANT(KeyModifierMask, KEY_MASK, GROUP_SWITCH);
+ BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, LEFT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, RIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, MIDDLE);
@@ -472,6 +474,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, SDL_MAX);
BIND_CORE_ENUM_CLASS_CONSTANT(JoyAxis, JOY_AXIS, MAX);
+ BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_OFF);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, NOTE_ON);
BIND_CORE_ENUM_CLASS_CONSTANT(MIDIMessage, MIDI_MESSAGE, AFTERTOUCH);
@@ -588,6 +591,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE);
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 5b5bfaecb5..5ac86798a6 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -35,7 +35,6 @@ CoreStringNames *CoreStringNames::singleton = nullptr;
CoreStringNames::CoreStringNames() :
_free(StaticCString::create("free")),
changed(StaticCString::create("changed")),
- _meta(StaticCString::create("__meta__")),
_script(StaticCString::create("script")),
script_changed(StaticCString::create("script_changed")),
___pdcdata(StaticCString::create("___pdcdata")),
diff --git a/core/core_string_names.h b/core/core_string_names.h
index 2cd4e335b2..6d4edabc68 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -52,7 +52,6 @@ public:
StringName _free;
StringName changed;
- StringName _meta;
StringName _script;
StringName script_changed;
StringName ___pdcdata;
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index f62d2cce1f..d0fd4feaa5 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -141,7 +141,7 @@ void Crypto::_bind_methods() {
/// Resource loader/saver
-RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
String el = p_path.get_extension().to_lower();
if (el == "crt") {
X509Certificate *cert = X509Certificate::create();
@@ -185,7 +185,7 @@ String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const
return "";
}
-Error ResourceFormatSaverCrypto::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverCrypto::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Error err;
Ref<X509Certificate> cert = p_resource;
Ref<CryptoKey> key = p_resource;
@@ -201,7 +201,7 @@ Error ResourceFormatSaverCrypto::save(const String &p_path, const RES &p_resourc
return OK;
}
-void ResourceFormatSaverCrypto::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverCrypto::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
const X509Certificate *cert = Object::cast_to<X509Certificate>(*p_resource);
const CryptoKey *key = Object::cast_to<CryptoKey>(*p_resource);
if (cert) {
@@ -215,6 +215,6 @@ void ResourceFormatSaverCrypto::get_recognized_extensions(const RES &p_resource,
}
}
-bool ResourceFormatSaverCrypto::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverCrypto::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<X509Certificate>(*p_resource) || Object::cast_to<CryptoKey>(*p_resource);
}
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 9de2c16fbc..fb4f7dd88f 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -117,7 +117,7 @@ public:
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -125,9 +125,9 @@ public:
class ResourceFormatSaverCrypto : public ResourceFormatSaver {
public:
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
- virtual bool recognize(const RES &p_resource) const;
+ virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
};
#endif // CRYPTO_H
diff --git a/core/debugger/engine_profiler.cpp b/core/debugger/engine_profiler.cpp
index c858b1febd..b99ee7dd5a 100644
--- a/core/debugger/engine_profiler.cpp
+++ b/core/debugger/engine_profiler.cpp
@@ -35,7 +35,7 @@
void EngineProfiler::_bind_methods() {
GDVIRTUAL_BIND(_toggle, "enable", "options");
GDVIRTUAL_BIND(_add_frame, "data");
- GDVIRTUAL_BIND(_tick, "frame_time", "idle_time", "physics_time", "physics_frame_time");
+ GDVIRTUAL_BIND(_tick, "frame_time", "process_time", "physics_time", "physics_frame_time");
}
void EngineProfiler::toggle(bool p_enable, const Array &p_array) {
@@ -46,8 +46,8 @@ void EngineProfiler::add(const Array &p_data) {
GDVIRTUAL_CALL(_add_frame, p_data);
}
-void EngineProfiler::tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
- GDVIRTUAL_CALL(_tick, p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time);
+void EngineProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
+ GDVIRTUAL_CALL(_tick, p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
}
Error EngineProfiler::bind(const String &p_name) {
@@ -55,13 +55,13 @@ Error EngineProfiler::bind(const String &p_name) {
EngineDebugger::Profiler prof(
this,
[](void *p_user, bool p_enable, const Array &p_opts) {
- ((EngineProfiler *)p_user)->toggle(p_enable, p_opts);
+ static_cast<EngineProfiler *>(p_user)->toggle(p_enable, p_opts);
},
[](void *p_user, const Array &p_data) {
- ((EngineProfiler *)p_user)->add(p_data);
+ static_cast<EngineProfiler *>(p_user)->add(p_data);
},
- [](void *p_user, double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
- ((EngineProfiler *)p_user)->tick(p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time);
+ [](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
+ static_cast<EngineProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
});
registration = p_name;
EngineDebugger::register_profiler(p_name, prof);
diff --git a/core/debugger/engine_profiler.h b/core/debugger/engine_profiler.h
index ade280a7bb..e50924a1ed 100644
--- a/core/debugger/engine_profiler.h
+++ b/core/debugger/engine_profiler.h
@@ -48,7 +48,7 @@ protected:
public:
virtual void toggle(bool p_enable, const Array &p_opts);
virtual void add(const Array &p_data);
- virtual void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time);
+ virtual void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time);
Error bind(const String &p_name);
Error unbind();
diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp
index c9f7d81a90..4ed4c97c64 100644
--- a/core/debugger/local_debugger.cpp
+++ b/core/debugger/local_debugger.cpp
@@ -60,7 +60,7 @@ struct LocalDebugger::ScriptsProfiler {
}
}
- void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
+ void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
frame_time = p_frame_time;
_print_frame_data(false);
}
@@ -369,11 +369,11 @@ LocalDebugger::LocalDebugger() {
Profiler scr_prof(
scripts_profiler,
[](void *p_user, bool p_enable, const Array &p_opts) {
- ((ScriptsProfiler *)p_user)->toggle(p_enable, p_opts);
+ static_cast<ScriptsProfiler *>(p_user)->toggle(p_enable, p_opts);
},
nullptr,
- [](void *p_user, double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
- ((ScriptsProfiler *)p_user)->tick(p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time);
+ [](void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
+ static_cast<ScriptsProfiler *>(p_user)->tick(p_frame_time, p_process_time, p_physics_time, p_physics_frame_time);
});
register_profiler("scripts", scr_prof);
}
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index 2fce23d003..5ee4e2c368 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -107,7 +107,7 @@ public:
}
}
- void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
+ void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
uint64_t pt = OS::get_singleton()->get_ticks_msec();
if (pt - last_bandwidth_time > 200) {
last_bandwidth_time = pt;
@@ -130,7 +130,7 @@ class RemoteDebugger::PerformanceProfiler : public EngineProfiler {
public:
void toggle(bool p_enable, const Array &p_opts) {}
void add(const Array &p_data) {}
- void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
+ void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
if (!performance) {
return;
}
@@ -161,14 +161,15 @@ public:
if (!monitor_value.is_num()) {
ERR_PRINT("Value of custom monitor '" + String(custom_monitor_names[i]) + "' is not a number");
arr[i + max] = Variant();
+ } else {
+ arr[i + max] = monitor_value;
}
- arr[i + max] = monitor_value;
}
EngineDebugger::get_singleton()->send_message("performance:profile_frame", arr);
}
- PerformanceProfiler(Object *p_performance) {
+ explicit PerformanceProfiler(Object *p_performance) {
performance = p_performance;
}
};
@@ -189,7 +190,7 @@ void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *
return; //ignore script errors, those go through debugger
}
- RemoteDebugger *rd = (RemoteDebugger *)p_this;
+ RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive errors during flush.
return;
}
@@ -208,7 +209,7 @@ void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *
}
void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error) {
- RemoteDebugger *rd = (RemoteDebugger *)p_this;
+ RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this);
if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive prints during flush.
return;
@@ -656,12 +657,12 @@ RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
// Core and profiler captures.
Capture core_cap(this,
[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
- return ((RemoteDebugger *)p_user)->_core_capture(p_cmd, p_data, r_captured);
+ return static_cast<RemoteDebugger *>(p_user)->_core_capture(p_cmd, p_data, r_captured);
});
register_message_capture("core", core_cap);
Capture profiler_cap(this,
[](void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
- return ((RemoteDebugger *)p_user)->_profiler_capture(p_cmd, p_data, r_captured);
+ return static_cast<RemoteDebugger *>(p_user)->_profiler_capture(p_cmd, p_data, r_captured);
});
register_message_capture("profiler", profiler_cap);
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index aada92da60..fdb312ae68 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -108,7 +108,7 @@ public:
void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type);
void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
- RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer);
+ explicit RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer);
~RemoteDebugger();
};
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 7c7d38ab0a..e9362b4ea4 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -93,7 +93,7 @@ RemoteDebuggerPeerTCP::~RemoteDebuggerPeerTCP() {
}
void RemoteDebuggerPeerTCP::_write_out() {
- while (tcp_client->poll(NetSocket::POLL_TYPE_OUT) == OK) {
+ while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_OUT) == OK) {
uint8_t *buf = out_buf.ptrw();
if (out_left <= 0) {
if (out_queue.size() == 0) {
@@ -119,7 +119,7 @@ void RemoteDebuggerPeerTCP::_write_out() {
}
void RemoteDebuggerPeerTCP::_read_in() {
- while (tcp_client->poll(NetSocket::POLL_TYPE_IN) == OK) {
+ while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_IN) == OK) {
uint8_t *buf = in_buf.ptrw();
if (in_left <= 0) {
if (in_queue.size() > max_queued_messages) {
@@ -162,11 +162,12 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
int port = p_port;
const int tries = 6;
- int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 };
+ const int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 };
tcp_client->connect_to_host(ip, port);
for (int i = 0; i < tries; i++) {
+ tcp_client->poll();
if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) {
print_verbose("Remote Debugger: Connected!");
break;
@@ -192,7 +193,7 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) {
// Update in time for 144hz monitors
const uint64_t min_tick = 6900;
- RemoteDebuggerPeerTCP *peer = (RemoteDebuggerPeerTCP *)p_ud;
+ RemoteDebuggerPeerTCP *peer = static_cast<RemoteDebuggerPeerTCP *>(p_ud);
while (peer->running && peer->is_peer_connected()) {
uint64_t ticks_usec = OS::get_singleton()->get_ticks_usec();
peer->_poll();
@@ -213,6 +214,7 @@ void RemoteDebuggerPeerTCP::poll() {
}
void RemoteDebuggerPeerTCP::_poll() {
+ tcp_client->poll();
if (connected) {
_write_out();
_read_in();
diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h
index 010336ffd3..473fd8d712 100644
--- a/core/debugger/remote_debugger_peer.h
+++ b/core/debugger/remote_debugger_peer.h
@@ -81,13 +81,13 @@ public:
Error connect_to_host(const String &p_host, uint16_t p_port);
- void poll();
- bool is_peer_connected();
- bool has_message();
- Array get_message();
- Error put_message(const Array &p_arr);
- int get_max_message_size() const;
- void close();
+ void poll() override;
+ bool is_peer_connected() override;
+ bool has_message() override;
+ Array get_message() override;
+ Error put_message(const Array &p_arr) override;
+ int get_max_message_size() const override;
+ void close() override;
RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
~RemoteDebuggerPeerTCP();
diff --git a/core/doc_data.h b/core/doc_data.h
index 9286b843be..194a39a729 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -152,7 +152,7 @@ public:
struct ClassDoc {
String name;
String inherits;
- String category;
+ String category; // FIXME: Wrongly used by VisualScriptPropertySelector, should be removed.
String brief_description;
String description;
Vector<TutorialDoc> tutorials;
diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp
index ceccd43259..8add4b9a3a 100644
--- a/core/error/error_macros.cpp
+++ b/core/error/error_macros.cpp
@@ -50,7 +50,7 @@ void add_error_handler(ErrorHandlerList *p_handler) {
_global_unlock();
}
-void remove_error_handler(ErrorHandlerList *p_handler) {
+void remove_error_handler(const ErrorHandlerList *p_handler) {
_global_lock();
ErrorHandlerList *prev = nullptr;
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 7b032fb4cd..2cfb5421c6 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -58,7 +58,7 @@ struct ErrorHandlerList {
};
void add_error_handler(ErrorHandlerList *p_handler);
-void remove_error_handler(ErrorHandlerList *p_handler);
+void remove_error_handler(const ErrorHandlerList *p_handler);
// Functions used by the error macros.
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR);
@@ -194,6 +194,7 @@ void _err_flush_stdout();
#define CRASH_BAD_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -208,6 +209,7 @@ void _err_flush_stdout();
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -296,6 +298,7 @@ void _err_flush_stdout();
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -310,6 +313,7 @@ void _err_flush_stdout();
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -559,6 +563,7 @@ void _err_flush_stdout();
#define CRASH_COND(m_cond) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -573,6 +578,7 @@ void _err_flush_stdout();
#define CRASH_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
+ _err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
@@ -808,4 +814,20 @@ void _err_flush_stdout();
} else \
((void)0)
+/**
+ * This should be a 'free' assert for program flow and should not be needed in any releases,
+ * only used in dev builds.
+ */
+#ifdef DEV_ENABLED
+#define DEV_ASSERT(m_cond) \
+ if (unlikely(!(m_cond))) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
+ _err_flush_stdout(); \
+ GENERATE_TRAP(); \
+ } else \
+ ((void)0)
+#else
+#define DEV_ASSERT(m_cond)
+#endif
+
#endif // ERROR_MACROS_H
diff --git a/core/extension/SCsub b/core/extension/SCsub
index a3a54250c1..23727c1b76 100644
--- a/core/extension/SCsub
+++ b/core/extension/SCsub
@@ -2,6 +2,12 @@
Import("env")
+import make_wrappers
+from platform_methods import run_in_subprocess
+
+env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", run_in_subprocess(make_wrappers.run))
+
+
env_extension = env.Clone()
env_extension.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 3687e4f7e5..f64c30dca5 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -666,6 +666,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d2;
d2["name"] = String(method_name);
d2["is_const"] = (F.flags & METHOD_FLAG_CONST) ? true : false;
+ d2["is_static"] = (F.flags & METHOD_FLAG_STATIC) ? true : false;
d2["is_vararg"] = false;
d2["is_virtual"] = true;
// virtual functions have no hash since no MethodBind is involved
@@ -708,6 +709,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d2["is_const"] = method->is_const();
d2["is_vararg"] = method->is_vararg();
+ d2["is_static"] = method->is_static();
d2["is_virtual"] = false;
d2["hash"] = method->get_hash();
@@ -841,27 +843,16 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
{
Array native_structures;
- // AudioStream structures
- {
- Dictionary d;
- d["name"] = "AudioFrame";
- d["format"] = "float left,float right";
+ List<StringName> native_structs;
+ ClassDB::get_native_struct_list(&native_structs);
+ native_structs.sort_custom<StringName::AlphCompare>();
- native_structures.push_back(d);
- }
+ for (const StringName &E : native_structs) {
+ String code = ClassDB::get_native_struct_code(E);
- // TextServer structures
- {
- Dictionary d;
- d["name"] = "Glyph";
- d["format"] = "int start,int end,uint8_t count,uint8_t repeat,uint16_t flags,float x_off,float y_off,float advance,RID font_rid,int font_size,int32_t index";
-
- native_structures.push_back(d);
- }
- {
Dictionary d;
- d["name"] = "CaretInfo";
- d["format"] = "Rect2 leading_caret,Rect2 trailing_caret,TextServer::Direction leading_direction,TextServer::Direction trailing_direction";
+ d["name"] = String(E);
+ d["format"] = code;
native_structures.push_back(d);
}
@@ -878,9 +869,8 @@ void NativeExtensionAPIDump::generate_extension_json_file(const String &p_path)
json.instantiate();
String text = json->stringify(api, "\t", false);
- FileAccessRef fa = FileAccess::open(p_path, FileAccess::WRITE);
+ Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
CharString cs = text.ascii();
fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
- fa->close();
}
#endif
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 385117eed1..a1d54f9c6d 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -32,6 +32,7 @@
#include "core/config/engine.h"
#include "core/object/class_db.h"
+#include "core/object/script_language_extension.h"
#include "core/os/memory.h"
#include "core/variant/variant.h"
#include "core/version.h"
@@ -60,6 +61,10 @@ static void gdnative_print_script_error(const char *p_description, const char *p
_err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT);
}
+uint64_t gdnative_get_native_struct_size(const char *p_name) {
+ return ClassDB::get_native_struct_size(p_name);
+}
+
// Variant functions
static void gdnative_variant_new_copy(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src) {
@@ -80,7 +85,7 @@ static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStrin
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
- self->call(*method, args, p_argcount, ret, error);
+ self->callp(*method, args, p_argcount, ret, error);
memnew_placement(r_return, Variant(ret));
if (r_error) {
@@ -152,7 +157,7 @@ static void gdnative_variant_set_indexed(GDNativeVariantPtr p_self, GDNativeInt
bool valid;
bool oob;
- self->set_indexed(p_index, value, valid, oob);
+ self->set_indexed(p_index, *value, valid, oob);
*r_valid = valid;
*r_oob = oob;
}
@@ -236,6 +241,13 @@ static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self)
return self->booleanize();
}
+static void gdnative_variant_sub(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst) {
+ const Variant *a = (const Variant *)p_a;
+ const Variant *b = (const Variant *)p_b;
+ memnew_placement(r_dst, Variant);
+ Variant::sub(*a, *b, *(Variant *)r_dst);
+}
+
static void gdnative_variant_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b;
@@ -860,6 +872,13 @@ static GDObjectInstanceID gdnative_object_get_instance_id(const GDNativeObjectPt
return (GDObjectInstanceID)o->get_instance_id();
}
+static GDNativeScriptInstancePtr gdnative_script_instance_create(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data) {
+ ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension);
+ script_instance_extension->instance = p_instance_data;
+ script_instance_extension->native_info = p_info;
+ return reinterpret_cast<GDNativeScriptInstancePtr>(script_instance_extension);
+}
+
static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_classname, const char *p_methodname, GDNativeInt p_hash) {
MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
ERR_FAIL_COND_V(!mb, nullptr);
@@ -902,6 +921,8 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.print_warning = gdnative_print_warning;
gdni.print_script_error = gdnative_print_script_error;
+ gdni.get_native_struct_size = gdnative_get_native_struct_size;
+
/* GODOT VARIANT */
// variant general
@@ -925,6 +946,7 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.variant_iter_get = gdnative_variant_iter_get;
gdni.variant_hash_compare = gdnative_variant_hash_compare;
gdni.variant_booleanize = gdnative_variant_booleanize;
+ gdni.variant_sub = gdnative_variant_sub;
gdni.variant_blend = gdnative_variant_blend;
gdni.variant_interpolate = gdnative_variant_interpolate;
gdni.variant_duplicate = gdnative_variant_duplicate;
@@ -1026,6 +1048,10 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id;
gdni.object_get_instance_id = gdnative_object_get_instance_id;
+ /* SCRIPT INSTANCE */
+
+ gdni.script_instance_create = gdnative_script_instance_create;
+
/* CLASSDB */
gdni.classdb_construct_object = gdnative_classdb_construct_object;
@@ -1043,4 +1069,6 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.classdb_register_extension_class_property_subgroup = nullptr;
gdni.classdb_register_extension_class_signal = nullptr;
gdni.classdb_unregister_extension_class = nullptr;
+
+ gdni.get_library_path = nullptr;
}
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index a2e0c7cc73..4d2682b253 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -194,6 +194,7 @@ typedef void *GDExtensionClassInstancePtr;
typedef GDNativeBool (*GDNativeExtensionClassSet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value);
typedef GDNativeBool (*GDNativeExtensionClassGet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
+typedef uint64_t (*GDNativeExtensionClassGetRID)(GDExtensionClassInstancePtr p_instance);
typedef struct {
uint32_t type;
@@ -204,10 +205,21 @@ typedef struct {
uint32_t usage;
} GDNativePropertyInfo;
+typedef struct {
+ const char *name;
+ GDNativePropertyInfo return_value;
+ uint32_t flags; // From GDNativeExtensionClassMethodFlags
+ int32_t id;
+ GDNativePropertyInfo *arguments;
+ uint32_t argument_count;
+ GDNativeVariantPtr default_arguments;
+ uint32_t default_argument_count;
+} GDNativeMethodInfo;
+
typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list);
typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
-typedef const char *(*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance);
+typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr p_out);
typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
@@ -228,6 +240,7 @@ typedef struct {
GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
GDNativeExtensionClassGetVirtual get_virtual_func;
+ GDNativeExtensionClassGetRID get_rid_func;
void *class_userdata;
} GDNativeExtensionClassCreationInfo;
@@ -287,6 +300,79 @@ typedef struct {
GDNativeVariantPtr *default_arguments;
} GDNativeExtensionClassMethodInfo;
+/* SCRIPT INSTANCE EXTENSION */
+
+typedef void *GDNativeExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation
+
+typedef GDNativeBool (*GDNativeExtensionScriptInstanceSet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value);
+typedef GDNativeBool (*GDNativeExtensionScriptInstanceGet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
+typedef const GDNativePropertyInfo *(*GDNativeExtensionScriptInstanceGetPropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
+typedef void (*GDNativeExtensionScriptInstanceFreePropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativePropertyInfo *p_list);
+typedef GDNativeVariantType (*GDNativeExtensionScriptInstanceGetPropertyType)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeBool *r_is_valid);
+
+typedef 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);
+
+typedef const GDNativeMethodInfo *(*GDNativeExtensionScriptInstanceGetMethodList)(GDNativeExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
+typedef void (*GDNativeExtensionScriptInstanceFreeMethodList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeMethodInfo *p_list);
+
+typedef GDNativeBool (*GDNativeExtensionScriptInstanceHasMethod)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name);
+
+typedef void (*GDNativeExtensionScriptInstanceCall)(GDNativeExtensionScriptInstanceDataPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
+typedef void (*GDNativeExtensionScriptInstanceNotification)(GDNativeExtensionScriptInstanceDataPtr p_instance, int32_t p_what);
+typedef const char *(*GDNativeExtensionScriptInstanceToString)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeBool *r_is_valid);
+
+typedef void (*GDNativeExtensionScriptInstanceRefCountIncremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
+typedef GDNativeBool (*GDNativeExtensionScriptInstanceRefCountDecremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
+
+typedef GDNativeObjectPtr (*GDNativeExtensionScriptInstanceGetScript)(GDNativeExtensionScriptInstanceDataPtr p_instance);
+typedef GDNativeBool (*GDNativeExtensionScriptInstanceIsPlaceholder)(GDNativeExtensionScriptInstanceDataPtr p_instance);
+
+typedef void *GDNativeExtensionScriptLanguagePtr;
+
+typedef GDNativeExtensionScriptLanguagePtr (*GDNativeExtensionScriptInstanceGetLanguage)(GDNativeExtensionScriptInstanceDataPtr p_instance);
+
+typedef void (*GDNativeExtensionScriptInstanceFree)(GDNativeExtensionScriptInstanceDataPtr p_instance);
+
+typedef void *GDNativeScriptInstancePtr; // Pointer to ScriptInstance.
+
+typedef struct {
+ GDNativeExtensionScriptInstanceSet set_func;
+ GDNativeExtensionScriptInstanceGet get_func;
+ GDNativeExtensionScriptInstanceGetPropertyList get_property_list_func;
+ GDNativeExtensionScriptInstanceFreePropertyList free_property_list_func;
+ GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
+
+ GDNativeExtensionScriptInstanceGetOwner get_owner_func;
+ GDNativeExtensionScriptInstanceGetPropertyState get_property_state_func;
+
+ GDNativeExtensionScriptInstanceGetMethodList get_method_list_func;
+ GDNativeExtensionScriptInstanceFreeMethodList free_method_list_func;
+
+ GDNativeExtensionScriptInstanceHasMethod has_method_func;
+
+ GDNativeExtensionScriptInstanceCall call_func;
+ GDNativeExtensionScriptInstanceNotification notification_func;
+
+ GDNativeExtensionScriptInstanceToString to_string_func;
+
+ GDNativeExtensionScriptInstanceRefCountIncremented refcount_incremented_func;
+ GDNativeExtensionScriptInstanceRefCountDecremented refcount_decremented_func;
+
+ GDNativeExtensionScriptInstanceGetScript get_script_func;
+
+ GDNativeExtensionScriptInstanceIsPlaceholder is_placeholder_func;
+
+ GDNativeExtensionScriptInstanceSet set_fallback_func;
+ GDNativeExtensionScriptInstanceGet get_fallback_func;
+
+ GDNativeExtensionScriptInstanceGetLanguage get_language_func;
+
+ GDNativeExtensionScriptInstanceFree free_func;
+
+} GDNativeExtensionScriptInstanceInfo;
+
/* INTERFACE */
typedef struct {
@@ -304,6 +390,8 @@ typedef struct {
void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
+ uint64_t (*get_native_struct_size)(const char *p_name);
+
/* GODOT VARIANT */
/* variant general */
@@ -328,6 +416,7 @@ typedef struct {
void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
+ void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep);
@@ -437,6 +526,10 @@ typedef struct {
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
GDObjectInstanceID (*object_get_instance_id)(const GDNativeObjectPtr p_object);
+ /* SCRIPT INSTANCE */
+
+ GDNativeScriptInstancePtr (*script_instance_create)(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data);
+
/* CLASSDB */
GDNativeObjectPtr (*classdb_construct_object)(const char *p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash);
@@ -452,6 +545,9 @@ typedef struct {
void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
+
+ void (*get_library_path)(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
+
} GDNativeInterface;
/* INITIALIZATION */
@@ -461,7 +557,6 @@ typedef enum {
GDNATIVE_INITIALIZATION_SERVERS,
GDNATIVE_INITIALIZATION_SCENE,
GDNATIVE_INITIALIZATION_EDITOR,
- GDNATIVE_INITIALIZATION_DRIVER,
GDNATIVE_MAX_INITIALIZATION_LEVEL,
} GDNativeInitializationLevel;
diff --git a/core/extension/make_wrappers.py b/core/extension/make_wrappers.py
new file mode 100644
index 0000000000..862d313fba
--- /dev/null
+++ b/core/extension/make_wrappers.py
@@ -0,0 +1,93 @@
+proto = """
+#define EXBIND$VER($RETTYPE m_name$ARG) \\
+GDVIRTUAL$VER($RETTYPE_##m_name$ARG)\\
+virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
+ $RETPRE\\
+ GDVIRTUAL_REQUIRED_CALL(_##m_name$CALLARGS$RETREF);\\
+ $RETPOST\\
+}
+"""
+
+
+def generate_version(argcount, const=False, returns=False):
+ s = proto
+ sproto = str(argcount)
+ method_info = ""
+ if returns:
+ sproto += "R"
+ s = s.replace("$RETTYPE", "m_ret, ")
+ s = s.replace("$RETVAL", "m_ret")
+ s = s.replace("$RETPRE", "m_ret ret; ZeroInitializer<m_ret>::initialize(ret);\\\n")
+ s = s.replace("$RETPOST", "return ret;\\\n")
+
+ else:
+ s = s.replace("$RETTYPE", "")
+ s = s.replace("$RETVAL", "void")
+ s = s.replace("$RETPRE", "")
+ s = s.replace("$RETPOST", "return;")
+
+ if const:
+ sproto += "C"
+ s = s.replace("$CONST", "const")
+ else:
+ s = s.replace("$CONST", "")
+
+ s = s.replace("$VER", sproto)
+ argtext = ""
+ funcargs = ""
+ callargs = ""
+
+ for i in range(argcount):
+ if i > 0:
+ funcargs += ", "
+
+ argtext += ", m_type" + str(i + 1)
+ funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
+ callargs += ", arg" + str(i + 1)
+
+ if argcount:
+ s = s.replace("$ARG", argtext)
+ s = s.replace("$FUNCARGS", funcargs)
+ s = s.replace("$CALLARGS", callargs)
+ else:
+ s = s.replace("$ARG", "")
+ s = s.replace("$FUNCARGS", funcargs)
+ s = s.replace("$CALLARGS", callargs)
+
+ if returns:
+ s = s.replace("$RETREF", ", ret")
+ else:
+ s = s.replace("$RETREF", "")
+
+ return s
+
+
+def run(target, source, env):
+
+ max_versions = 12
+
+ txt = """
+#ifndef GDEXTENSION_WRAPPERS_GEN_H
+#define GDEXTENSION_WRAPPERS_GEN_H
+
+
+"""
+
+ for i in range(max_versions + 1):
+
+ txt += "/* " + str(i) + " Arguments */\n\n"
+ txt += generate_version(i, False, False)
+ txt += generate_version(i, False, True)
+ txt += generate_version(i, True, False)
+ txt += generate_version(i, True, True)
+
+ txt += "#endif"
+
+ with open(target[0], "w") as f:
+ f.write(txt)
+
+
+if __name__ == "__main__":
+ from platform_methods import subprocess_main
+
+ subprocess_main(globals())
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index 1512852234..db1cbd53b4 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -49,10 +49,10 @@ class NativeExtensionMethodBind : public MethodBind {
bool vararg;
protected:
- virtual Variant::Type _gen_argument_type(int p_arg) const {
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
return Variant::Type(get_argument_type_func(method_userdata, p_arg));
}
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
GDNativePropertyInfo pinfo;
get_argument_info_func(method_userdata, p_arg, &pinfo);
PropertyInfo ret;
@@ -66,13 +66,15 @@ protected:
}
public:
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
return GodotTypeInfo::Metadata(get_argument_metadata_func(method_userdata, p_arg));
}
+#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
Variant ret;
- GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
+ GDExtensionClassInstancePtr extension_instance = is_static() ? nullptr : p_object->_get_extension_instance();
GDNativeCallError ce{ GDNATIVE_CALL_OK, 0, 0 };
call_func(method_userdata, extension_instance, (const GDNativeVariantPtr *)p_args, p_arg_count, (GDNativeVariantPtr)&ret, &ce);
r_error.error = Callable::CallError::Error(ce.error);
@@ -80,16 +82,17 @@ public:
r_error.expected = ce.expected;
return ret;
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug.");
GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
ptrcall_func(method_userdata, extension_instance, (const GDNativeTypePtr *)p_args, (GDNativeTypePtr)r_ret);
}
- virtual bool is_vararg() const {
+ virtual bool is_vararg() const override {
return false;
}
- NativeExtensionMethodBind(const GDNativeExtensionClassMethodInfo *p_method_info) {
+
+ explicit NativeExtensionMethodBind(const GDNativeExtensionClassMethodInfo *p_method_info) {
method_userdata = p_method_info->method_userdata;
call_func = p_method_info->call_func;
ptrcall_func = p_method_info->ptrcall_func;
@@ -98,21 +101,31 @@ public:
get_argument_metadata_func = p_method_info->get_argument_metadata_func;
set_name(p_method_info->name);
- vararg = p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_VARARG;
+ set_hint_flags(p_method_info->method_flags);
+ vararg = p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_VARARG;
_set_returns(p_method_info->has_return_value);
_set_const(p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_CONST);
+ _set_static(p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_STATIC);
#ifdef DEBUG_METHODS_ENABLED
_generate_argument_types(p_method_info->argument_count);
#endif
set_argument_count(p_method_info->argument_count);
+
+ Vector<Variant> defargs;
+ defargs.resize(p_method_info->default_argument_count);
+ for (uint32_t i = 0; i < p_method_info->default_argument_count; i++) {
+ defargs.write[i] = *static_cast<Variant *>(p_method_info->default_arguments[i]);
+ }
+
+ set_default_arguments(defargs);
}
};
static GDNativeInterface gdnative_interface;
void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(!String(class_name).is_valid_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier.");
@@ -158,11 +171,12 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
extension->native_extension.create_instance = p_extension_funcs->create_instance_func;
extension->native_extension.free_instance = p_extension_funcs->free_instance_func;
extension->native_extension.get_virtual = p_extension_funcs->get_virtual_func;
+ extension->native_extension.get_rid = p_extension_funcs->get_rid_func;
ClassDB::register_extension_class(&extension->native_extension);
}
void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
StringName method_name = p_method_info->name;
@@ -176,7 +190,7 @@ void NativeExtension::_register_extension_class_method(const GDNativeExtensionCl
ClassDB::bind_method_custom(class_name, method);
}
void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'.");
@@ -187,7 +201,7 @@ void NativeExtension::_register_extension_class_integer_constant(const GDNativeE
}
void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + String(p_info->name) + "' for unexisting class '" + class_name + "'.");
@@ -205,7 +219,7 @@ void NativeExtension::_register_extension_class_property(const GDNativeExtension
}
void NativeExtension::_register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + String(p_group_name) + "' for unexisting class '" + class_name + "'.");
@@ -214,7 +228,7 @@ void NativeExtension::_register_extension_class_property_group(const GDNativeExt
}
void NativeExtension::_register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + String(p_subgroup_name) + "' for unexisting class '" + class_name + "'.");
@@ -223,7 +237,7 @@ void NativeExtension::_register_extension_class_property_subgroup(const GDNative
}
void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'.");
@@ -244,7 +258,7 @@ void NativeExtension::_register_extension_class_signal(const GDNativeExtensionCl
}
void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name) {
- NativeExtension *self = (NativeExtension *)p_library;
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
@@ -258,8 +272,14 @@ void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLi
self->extension_classes.erase(class_name);
}
+void NativeExtension::_get_library_path(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path) {
+ NativeExtension *self = static_cast<NativeExtension *>(p_library);
+
+ *(String *)r_path = self->library_path;
+}
+
Error NativeExtension::open_library(const String &p_path, const String &p_entry_symbol) {
- Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true);
+ Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true, &library_path);
if (err != OK) {
return err;
}
@@ -295,9 +315,10 @@ NativeExtension::InitializationLevel NativeExtension::get_minimum_library_initia
ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE);
return InitializationLevel(initialization.minimum_initialization_level);
}
+
void NativeExtension::initialize_library(InitializationLevel p_level) {
ERR_FAIL_COND(library == nullptr);
- ERR_FAIL_COND(p_level <= int32_t(level_initialized));
+ ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized));
level_initialized = int32_t(p_level);
@@ -349,9 +370,10 @@ void NativeExtension::initialize_native_extensions() {
gdnative_interface.classdb_register_extension_class_property_subgroup = _register_extension_class_property_subgroup;
gdnative_interface.classdb_register_extension_class_signal = _register_extension_class_signal;
gdnative_interface.classdb_unregister_extension_class = _unregister_extension_class;
+ gdnative_interface.get_library_path = _get_library_path;
}
-RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<ConfigFile> config;
config.instantiate();
@@ -362,14 +384,14 @@ RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_or
}
if (err != OK) {
- return RES();
+ return Ref<Resource>();
}
if (!config->has_section_key("configuration", "entry_symbol")) {
if (r_error) {
*r_error = ERR_INVALID_DATA;
}
- return RES();
+ return Ref<Resource>();
}
String entry_symbol = config->get_value("configuration", "entry_symbol");
@@ -401,7 +423,7 @@ RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_or
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
- return RES();
+ return Ref<Resource>();
}
if (!library_path.is_resource_file()) {
@@ -418,7 +440,7 @@ RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_or
}
if (err != OK) {
- return RES();
+ return Ref<Resource>();
}
return lib;
diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h
index b98e4925d2..af5a474e79 100644
--- a/core/extension/native_extension.h
+++ b/core/extension/native_extension.h
@@ -39,6 +39,7 @@ class NativeExtension : public Resource {
GDCLASS(NativeExtension, Resource)
void *library = nullptr; // pointer if valid,
+ String library_path;
struct Extension {
ObjectNativeExtension native_extension;
@@ -54,6 +55,7 @@ class NativeExtension : public Resource {
static void _register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name);
+ static void _get_library_path(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
GDNativeInitialization initialization;
int32_t level_initialized = -1;
@@ -68,11 +70,10 @@ public:
void close_library();
enum InitializationLevel {
- INITIALIZATION_LEVEL_CORE,
- INITIALIZATION_LEVEL_SERVERS,
- INITIALIZATION_LEVEL_SCENE,
- INITIALIZATION_LEVEL_EDITOR,
- INITIALIZATION_LEVEL_DRIVER,
+ INITIALIZATION_LEVEL_CORE = GDNATIVE_INITIALIZATION_CORE,
+ INITIALIZATION_LEVEL_SERVERS = GDNATIVE_INITIALIZATION_SERVERS,
+ INITIALIZATION_LEVEL_SCENE = GDNATIVE_INITIALIZATION_SCENE,
+ INITIALIZATION_LEVEL_EDITOR = GDNATIVE_INITIALIZATION_EDITOR
};
bool is_library_open() const;
@@ -90,7 +91,7 @@ VARIANT_ENUM_CAST(NativeExtension::InitializationLevel)
class NativeExtensionResourceLoader : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/extension/native_extension_manager.cpp b/core/extension/native_extension_manager.cpp
index 87737858a8..5436f7d51e 100644
--- a/core/extension/native_extension_manager.cpp
+++ b/core/extension/native_extension_manager.cpp
@@ -40,14 +40,14 @@ NativeExtensionManager::LoadStatus NativeExtensionManager::load_extension(const
return LOAD_STATUS_FAILED;
}
- if (level >= 0) { //already initialized up to some level
+ if (level >= 0) { // Already initialized up to some level.
int32_t minimum_level = extension->get_minimum_library_initialization_level();
if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) {
return LOAD_STATUS_NEEDS_RESTART;
}
- //initialize up to current level
- for (int32_t i = minimum_level; i < level; i++) {
- extension->initialize_library(NativeExtension::InitializationLevel(level));
+ // Initialize up to current level.
+ for (int32_t i = minimum_level; i <= level; i++) {
+ extension->initialize_library(NativeExtension::InitializationLevel(i));
}
}
native_extension_map[p_path] = extension;
@@ -64,14 +64,14 @@ NativeExtensionManager::LoadStatus NativeExtensionManager::unload_extension(cons
Ref<NativeExtension> extension = native_extension_map[p_path];
- if (level >= 0) { //already initialized up to some level
+ if (level >= 0) { // Already initialized up to some level.
int32_t minimum_level = extension->get_minimum_library_initialization_level();
if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) {
return LOAD_STATUS_NEEDS_RESTART;
}
- //initialize up to current level
+ // Deinitialize down to current level.
for (int32_t i = level; i >= minimum_level; i--) {
- extension->deinitialize_library(NativeExtension::InitializationLevel(level));
+ extension->deinitialize_library(NativeExtension::InitializationLevel(i));
}
}
native_extension_map.erase(p_path);
@@ -112,8 +112,8 @@ void NativeExtensionManager::deinitialize_extensions(NativeExtension::Initializa
}
void NativeExtensionManager::load_extensions() {
- FileAccessRef f = FileAccess::open(NativeExtension::get_extension_list_config_file(), FileAccess::READ);
- while (f && !f->eof_reached()) {
+ Ref<FileAccess> f = FileAccess::open(NativeExtension::get_extension_list_config_file(), FileAccess::READ);
+ while (f.is_valid() && !f->eof_reached()) {
String s = f->get_line().strip_edges();
if (!s.is_empty()) {
LoadStatus err = load_extension(s);
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 58014e976e..5a71bcbef3 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -2,12 +2,14 @@
# Source: https://github.com/gabomdq/SDL_GameControllerDB
# Windows
-03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,
-03000000d0160000040d000000000000,4Play,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,
-03000000d0160000050d000000000000,4Play,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,
-03000000d0160000060d000000000000,4Play,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,
-03000000d0160000070d000000000000,4Play,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,
-03000000d0160000600a000000000000,4Play,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,
+03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,
+03000000d0160000040d000000000000,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,
+03000000d0160000050d000000000000,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,
+03000000d0160000060d000000000000,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,
+03000000d0160000070d000000000000,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,
+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,
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,
@@ -16,9 +18,9 @@
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,
-03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,guide:b2,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:Windows,
-03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,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,
+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,
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,
@@ -27,21 +29,27 @@
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,
-03000000c82d00000290000000000000,8Bitdo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
-03000000c82d00003038000000000000,8Bitdo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
+03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
+03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
-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,
+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,
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,
+03000000c82d00000131000000000000,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,
+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,
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,
+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,
+03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
-03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00003028000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,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,
@@ -54,23 +62,22 @@
03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,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,
03000000c82d00000260000000000000,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,
03000000c82d00000261000000000000,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,
-03000000c82d00000031000000000000,8BitDo Wireless 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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003032000000000000,8BitDo Zero 2,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:Windows,
-03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
-03000000d81d00000e00000000000000,AC02,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
+03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000c01100000355000000000000,Acrux,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,
03000000fa190000f0ff000000000000,Acteck AGJ 3200,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,
-030000006d0400000bc2000000000000,Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows,
+030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows,
03000000d1180000402c000000000000,ADT1,a:b0,b:b1,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:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows,
-030000006f0e00001301000000000000,Afterglow,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,
-030000006f0e00001302000000000000,Afterglow,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,
-030000006f0e00001304000000000000,Afterglow,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,
-030000006f0e00001413000000000000,Afterglow,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,
-030000006f0e00003901000000000000,Afterglow,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,
-03000000ab1200000103000000000000,Afterglow,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:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000ad1b000000f9000000000000,Afterglow,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,
+030000006f0e00001301000000000000,Afterglow Xbox Controller,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,
+030000006f0e00001302000000000000,Afterglow Xbox Controller,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,
+030000006f0e00001304000000000000,Afterglow Xbox Controller,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,
+030000006f0e00001413000000000000,Afterglow Xbox 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,
+030000006f0e00003901000000000000,Afterglow Xbox Controller,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,
+03000000ab1200000103000000000000,Afterglow Xbox Controller,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:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b000000f9000000000000,Afterglow Xbox Controller,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,
03000000341a00003608000000000000,Afterglow 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,
030000006f0e00000263000000000000,Afterglow 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,
030000006f0e00001101000000000000,Afterglow 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,
@@ -78,17 +85,20 @@
030000006f0e00001402000000000000,Afterglow 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,
030000006f0e00001901000000000000,Afterglow 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,
030000006f0e00001a01000000000000,Afterglow 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,
+03000000100000008200000000000000,Akishop Customs PS360,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,
+030000007c1800000006000000000000,Alienware Dual Compatible 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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows,
03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows,
03000000120c0000100e000000000000,Armor 3,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,
+03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
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,leftx:a3,lefty: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,
-03000000ef0500000300000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
-03000000fd0500000230000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
-03000000d6200000e557000000000000,Batarang,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,
+03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
+03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,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,
030000006f0e00003201000000000000,Battlefield 4 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,
03000000ad1b000001f9000000000000,BB 070,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,
@@ -96,7 +106,7 @@
03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows,
030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000bc2000006012000000000000,Betop 2126F,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,
-03000000bc2000000055000000000000,Betop BFM Gamepad,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,
+03000000bc2000000055000000000000,Betop BFM,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,
03000000bc2000006312000000000000,Betop 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,
03000000bc2000006321000000000000,Betop 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,
03000000bc2000006412000000000000,Betop 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,
@@ -109,11 +119,9 @@
030000006b1400000209000000000000,Bigben,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,
030000006b1400000055000000000000,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:b2,y:b3,platform:Windows,
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,
-03000000380700008232000000000000,Brawlpad,a:b1,b:b2,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:b3,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,
-0300000066f700000500000000000000,BrutalLegendTest,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:a3,righty:a2,start:b9,x:b0,y:b3,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,
+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,
030000006d04000042c2000000000000,ChillStream,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,
03000000e82000006058000000000000,Cideko AK08b,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,
03000000457500000401000000000000,Cobra,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:Windows,
@@ -123,29 +131,28 @@
03000000d8140000cefa000000000000,Cthulhu,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,
03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,
030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,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:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,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:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000a306000022f6000000000000,Cyborg V.3 Rumble,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:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows,
-030000001a1c00000001000000000000,Datel,a:b1,b:b2,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:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000001a1c00000001000000000000,Datel Arcade Joystick,a:b1,b:b2,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:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000451300000830000000000000,Defender Game Racer X7,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:Windows,
030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,
-03000000c0160000e105000000000000,Dual,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
-030000007c1800000006000000000000,Dual Compat,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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
+03000000c0160000e105000000000000,Dual 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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,platform:Windows,
030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
-03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
+03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000ff1100003133000000000000,DualForce,a:b2,b:b3,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:b0,y:b1,platform:Windows,
030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000317300000100000000000000,DualShock 3,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,
030000006f0e00003001000000000000,EA Sports 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,
03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
-030000006e0500000a20000000000000,Elecom DUX60 MMO Gamepad,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows,
+030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows,
03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,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:b1,platform:Windows,
03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,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:b1,platform:Windows,
-030000006e0500000520000000000000,Elecom P301U,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
+030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
-030000006e0500000320000000000000,Elecom U3613M (DInput),a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
+030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
030000006e0500001320000000000000,Elecom U4113,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,
@@ -156,104 +163,102 @@
03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows,
03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000008f0e00000f31000000000000,EXEQ,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:b3,y:b2,platform:Windows,
-03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-03000000790000003018000000000000,F300,a:b1,b:b2,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,start:b9,x:b0,y:b3,platform:Windows,
-03000000242f00003900000000000000,F300 Elite,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,
-030000006f0e00008401000000000000,Faceoff Deluxe Audio Wired 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:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-030000006f0e00008001000000000000,Faceoff 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:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,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,start:b9,x:b0,y:b3,platform:Windows,
+03000000242f00003900000000000000,Mayflash F300 Elite 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,
+030000006f0e00008401000000000000,Faceoff Deluxe Nintendo 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,
+030000006f0e00008001000000000000,Faceoff Pro Nintendo 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,
03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
-030000004f04000008d0000000000000,Ferrari 150,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000852100000201000000000000,FF GP1,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,
-030000000d0f00008500000000000000,Fighting Commander 2016 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:Windows,
-030000000d0f00008400000000000000,Fighting Commander 5,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:Windows,
-030000000d0f00008700000000000000,Fighting Stick 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,Fighting Stick 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,
-030000000d0f00002700000000000000,FIGHTING STICK 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,
-03000000380700002847000000000000,FightPad,a:b0,b:b1,back:b6,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:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,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:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,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:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
-03000000380700001847000000000000,FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
-03000000380700008031000000000000,FightStick,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,
-03000000380700008731000000000000,FightStick,a:b1,b:b2,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:b3,platform:Windows,
-030000003807000038b7000000000000,FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
-78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,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,
03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows,
03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,
03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,
03000000b40400001024000000000000,Flydigi Apex,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,
03000000151900004000000000000000,Flydigi Vader 2,a:b11,b:b10,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,leftstick:b1,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b0,righttrigger:b4,rightx:a3,righty:a4,start:b2,x:b9,y:b8,platform:Windows,
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,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,
+03000000b40400001224000000000000,Flydigi Vader 2 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,paddle3:b17,paddle4:b18,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
-03000000ac0500002d02000000000000,G2U,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,
-03000000790000002201000000000000,Game Controller for PC,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,
0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
-03000000341a000005f7000000000000,GameCube,a:b2,b:b3,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:b1,y:b0,platform:Windows,
-03000000430b00000500000000000000,GameCube,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows,
-03000000790000004718000000000000,GameCube,a:b1,b:b0,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:b2,y:b3,platform:Windows,
-03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,
-03000000790000004618000000000000,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:Windows,
+03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,
+03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,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:b1,y:b0,platform:Windows,
+03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows,
+03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,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:b2,y:b3,platform:Windows,
+03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,x:b2,y:b3,start:b9,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,rightshoulder:b7,lefttrigger:a3,righttrigger:a4,platform:Windows,
030000008f0e00000d31000000000000,Gamepad 3 Turbo,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,
-03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
-03000000ac0500003d03000000000000,GameSir,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
-03000000ac0500004d04000000000000,GameSir,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000280400000140000000000000,GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+03000000ac0500003d03000000000000,GameSir G3,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000ac0500005b05000000000000,GameSir G3w,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,
+03000000ac0500002d02000000000000,GameSir G4,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,
+03000000ac0500004d04000000000000,GameSir G4,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000004c0e00001035000000000000,Gamester,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,
-030000000d0f00001110000000000000,GameStick Bluetooth Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
0300000047530000616d000000000000,GameStop,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:Windows,
-03000000ffff00000000000000000000,GameStop Gamepad,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:Windows,
03000000c01100000140000000000000,GameStop PS4 Fun 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows,
-030000008f0e00001411000000000000,Gamo2 Divaller 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,
+030000008f0e00001411000000000000,Gamo2 Divaller,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,
03000000120c0000a857000000000000,Gator Claw,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,
03000000c9110000f055000000000000,GC100XF,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:Windows,
030000008305000009a0000000000000,Genius,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:Windows,
030000008305000031b0000000000000,Genius Maxfire Blaze 3,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:Windows,
03000000451300000010000000000000,Genius Maxfire Grandias 12,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:Windows,
030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
-03000000300f00000b01000000000000,GGE909 Recoil Pad,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,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,
+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,
-03000000f0250000c383000000000000,Gioteck VX2 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 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,
0300000079000000d418000000000000,GPD Win,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,
03000000c6240000025b000000000000,GPX,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,
-030000007d0400000540000000000000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000007d0400000340000000000000,Gravis G44011 Xterminator,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a2,start:b9,x:b3,y:b4,platform:Windows,
030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000ac0500006b05000000000000,GT2a,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,
03000000341a00000302000000000000,Hama Scorpad,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,
-03000000fd0500003902000000000000,Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows,
-03000000fd0500002a26000000000000,Hammerhead FX,a:b3,b:b4,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:b0,y:b1,platform:Windows,
-03000000fd0500002f26000000000000,Hammerhead FX,a:b4,b:b5,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:b1,y:b2,platform:Windows,
-030000000d0f00004900000000000000,Hatsune Miku Sho 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,
+03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows,
+03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,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:b0,y:b1,platform:Windows,
+03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,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:b1,y:b2,platform:Windows,
+030000000d0f00004900000000000000,Hatsune Miku Sho 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,
030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
030000000d0f00000c00000000000000,HEXT,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,
03000000d81400000862000000000000,HitBox Edition Cthulhu,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,
03000000632500002605000000000000,HJD X,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,
030000000d0f00000a00000000000000,Hori DOA,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,
+030000000d0f00005100000000000000,Hori Fighting,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,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,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,
+030000000d0f00008500000000000000,Hori Fighting Commander 2016 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:Windows,
+030000000d0f00002500000000000000,Hori Fighting Commander 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:Windows,
030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00005e00000000000000,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:Windows,
-030000000d0f00005100000000000000,Hori Fighting Pad,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,
-030000000d0f00001000000000000000,Hori Fighting Stick,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,
-030000000f0d00000010000000000000,Hori Fighting Stick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f00003200000000000000,Hori Fighting Stick 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 Fighting Stick 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 Fighting Stick 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 Fighting Stick 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 Fighting Stick 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,
-030000000d0f00002100000000000000,Hori Fighting Stick 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,
+030000000d0f00008400000000000000,Hori Fighting Commander 5,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: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,
+030000000f0d00000010000000000000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,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,
030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,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,
030000000d0f00005400000000000000,Hori 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:Windows,
030000000d0f00000900000000000000,Hori Pad 3 Turbo,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,
030000000d0f00004d00000000000000,Hori Pad A,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,
030000000d0f00003801000000000000,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:Windows,
-030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro Pad,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:Windows,
+030000000d0f00009200000000000000,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:Windows,
+030000000d0f00002301000000000000,Hori PS4 Controller Light,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,
030000000d0f00001100000000000000,Hori Real Arcade Pro 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,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,
030000000d0f00004b00000000000000,Hori Real Arcade Pro 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,
@@ -276,7 +281,6 @@
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,
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,
-030000000d0f00002301000000000000,Hori Wired PS4 Controller Light,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,
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,
030000000d0f00006400000000000000,Horipad 3TP,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,
030000000d0f00001300000000000000,Horipad 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,
@@ -285,29 +289,30 @@
030000000d0f00006600000000000000,Horipad 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00004200000000000000,Horipad A,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,
03000000ad1b000001f5000000000000,Horipad EXT2,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,
-030000005b1c00002400000000000000,Horipad Mini,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,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,
030000000d0f0000ee00000000000000,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:Windows,
030000000d0f00006700000000000000,Horipad One,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:Windows,
030000000d0f0000dc00000000000000,Horipad Switch,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,
030000008f0e00001330000000000000,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:Windows,
-03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
-03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000790000004e95000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
+03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
030000005c0a00000285000000000000,iDroidCon,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:b4,y:b6,platform:Windows,
-03000000696400006964000000000000,iDroidCon Bluetooth 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,
+03000000696400006964000000000000,iDroidCon 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,
03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
-030000006f0e00002401000000000000,Injustice FightStick PS3 Controller,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,
+030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,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,
03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows,
03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000491900000204000000000000,Ipega PG9023,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
-03000000491900000304000000000000,Ipega PG9087 - Bluetooth Gamepad,+righty:+a5,-righty:-a4,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:a3,start:b11,x:b3,y:b4,platform:Windows,
+03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,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:a3,start:b11,x:b3,y:b4,platform:Windows,
030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows,
030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,
03000000bd12000003c0000000000000,Joypad Alpha Shock,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,
-03000000250900000017000000000000,Joypad to USB Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,
+03000000250900000017000000000000,Joypad to Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,
03000000ff1100004033000000000000,JPD FFB,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:a2,start:b15,x:b3,y:b0,platform:Windows,
-03000000242f00002d00000000000000,JYS Wireless Adapter,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,
-03000000242f00008a00000000000000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
+03000000242f00002d00000000000000,JYS Adapter,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,
+03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
03000000c4100000c082000000000000,KADE,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,
03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,platform:Windows,
03000000790000000200000000000000,King 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:a4,start:b9,x:b3,y:b0,platform:Windows,
@@ -320,11 +325,11 @@
030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
030000006d04000016c2000000000000,Logitech Dual Action,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,
030000006d0400001dc2000000000000,Logitech F310,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,
+030000006d04000018c2000000000000,Logitech F510,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,
030000006d0400001ec2000000000000,Logitech F510,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,
-030000006d04000018c2000000000000,Logitech F510 Gamepad,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,
+030000006d04000019c2000000000000,Logitech F710,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,
030000006d0400001fc2000000000000,Logitech F710,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,
-030000006d04000019c2000000000000,Logitech F710 Gamepad,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,
-030000006d0400001ac2000000000000,Logitech Precision Gamepad,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:Windows,
+030000006d0400001ac2000000000000,Logitech Precision,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:Windows,
030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
03000000380700005645000000000000,Lynx,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,
@@ -333,40 +338,47 @@
03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000380700006352000000000000,Mad Catz CTRLR,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,
03000000380700006652000000000000,Mad Catz CTRLR,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700005032000000000000,Mad Catz FightPad Pro 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:Windows,
-03000000380700005082000000000000,Mad Catz FightPad PRO 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700008433000000000000,Mad Catz FightStick TE S 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:Windows,
-03000000380700008483000000000000,Mad Catz FightStick TE S 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700008134000000000000,Mad Catz FightStick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700008184000000000000,Mad Catz FightStick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700005032000000000000,Mad Catz Fightpad Pro 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:Windows,
+03000000380700005082000000000000,Mad Catz Fightpad Pro 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700008433000000000000,Mad Catz Fightstick TE S 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:Windows,
+03000000380700008483000000000000,Mad Catz Fightstick TE S 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+78696e70757403000000000000000000,Mad Catz Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,
03000000380700006252000000000000,Mad Catz Micro CTRLR,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700001888000000000000,Mad Catz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-03000000380700008081000000000000,Mad Catz SFV Arcade FightStick Alpha 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,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,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:b3,platform:Windows,
+03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,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:b3,platform:Windows,
+030000003807000056a8000000000000,Mad Catz 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,
+03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha 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,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,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:Windows,
030000002a0600001024000000000000,Matricom,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:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,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:b8,x:b3,y:b0,platform:Windows,
03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,
03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
-03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
0300000079000000d218000000000000,Mayflash Magic NS,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,
03000000d620000010a7000000000000,Mayflash Magic NS,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,
-030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,
+030000008f0e00001030000000000000,Mayflash Sega Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,
0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
-03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),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,
-03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,
-0300000079000000ae18000000000000,Mega Drive,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
-03000000c0160000990a000000000000,Mega Drive,a:b0,b:b1,leftx:a0,lefty:a1,righttrigger:b2,start:b3,platform:Windows,
+03000000790000000018000000000000,Mayflash WiiU Pro Adapter,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,
+03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,
+0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,leftx:a0,lefty:a1,righttrigger:b2,start:b3,platform:Windows,
+030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows,
030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows,
030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Windows,
03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows,
-030000005b1c00002500000000000000,Mini,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
+030000005b1c00002500000000000000,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,
03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
-03000000ad1b00003ef0000000000000,MLG FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
-03000000380700006382000000000000,MLG GamePad 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,
+03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700006382000000000000,MLG 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,
+03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows,
03000000d6200000e589000000000000,Moga 2,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:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
03000000d62000007162000000000000,Moga Pro,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:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
03000000d6200000ad0d000000000000,Moga Pro,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,
@@ -382,8 +394,9 @@
030000006b140000100d000000000000,Nacon Revolution Infinity 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,
030000006b140000080d000000000000,Nacon Revolution Unlimited Pro 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,
03000000bd12000001c0000000000000,Nebular,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:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
-03000000eb0300000000000000000000,NeGcon USB Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows,
+03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows,
0300000038070000efbe000000000000,NEO SE,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:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows,
03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,
03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
03000000571d00002100000000000000,NES Controller,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
@@ -392,48 +405,51 @@
030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,
03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,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:b10,x:b2,y:b3,platform:Windows,
03000000152000000182000000000000,NGDS,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:a4,start:b9,x:b3,y:b0,platform:Windows,
-030000007e0500001920000000000000,Nintendo Switch N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,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,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows,
-030000007e0500001720000000000000,Nintendo Switch Online Controller,a:b0,b:b1,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:b2,y:b3,platform:Windows,
-030000007e0500000920000000000000,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:Windows,
+030000007e0500000920000000000000,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:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000000d0500000308000000000000,Nostromo N45,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:Windows,
-03000000d620000013a7000000000000,NSW wired 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,
-03000000550900001472000000000000,NVIDIA Controller v01.04,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,
+030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,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:Windows,
+030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows,
+03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,
03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows,
-030000005509000000b4000000000000,NVIDIA Virtual Gamepad,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:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005509000000b4000000000000,NVIDIA Virtual,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:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,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,
030000004b120000014d000000000000,Nyko Airflo,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows,
03000000d62000001d57000000000000,Nyko Airflo 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,
-03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows,
+03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows,
030000000d0f00000401000000000000,Onyx,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,
030000008916000001fd000000000000,Onza CE,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:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000008916000000fd000000000000,Onza TE,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,
03000000d62000006d57000000000000,OPP 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,
030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
-03000000362800000100000000000000,OUYA Game 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:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
-03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
+03000000362800000100000000000000,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:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
+03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000002201000000000000,PC 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,
030000006f0e00008501000000000000,PDP Fightpad Pro,a:b2,b:b3,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:b1,y:b0,platform:Windows,
-030000006f0e00000901000000000000,PDP Versus Fighting Pad,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,
+030000006f0e00000901000000000000,PDP Versus Fighting,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,
+03000000e30500009605000000000000,PlayStation Adapter,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,
030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
-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,
+03000000632500002306000000000000,PlayStation Controller,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:Windows,
+03000000f0250000c183000000000000,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,
+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,
+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,
03000000c62400001a53000000000000,Pro Ex Mini,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,
03000000d62000009f31000000000000,Pro Ex mini 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,
03000000d6200000c757000000000000,Pro Ex mini 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,
03000000120c0000110e000000000000,Pro5,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,
-03000000632500002306000000000000,PS Controller,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:Windows,
-03000000e30500009605000000000000,PS to USB convert cable,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,
03000000100800000100000000000000,PS1 Controller,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,
030000008f0e00007530000000000000,PS1 Controller,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:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000100800000300000000000000,PS2 Controller,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:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000250900000088000000000000,PS2 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,
+03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900008888000000000000,PS2 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,
03000000666600006706000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
030000006b1400000303000000000000,PS2 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,
030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-03000000250900000088000000000000,PS2 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,
-03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000120a00000100000000000000,PS3 Controller,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,
03000000120c00001307000000000000,PS3 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,
03000000120c00001cf1000000000000,PS3 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,
@@ -449,8 +465,6 @@
030000008f0e00000300000000000000,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:a5,start:b9,x:b3,y:b0,platform:Windows,
030000008f0e00001431000000000000,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,
03000000ba2200002010000000000000,PS3 Controller,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:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
-030000003807000056a8000000000000,PS3 RF pad,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,
-03000000100000008200000000000000,PS360 v1.66,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:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000120c00000807000000000000,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,
03000000120c0000111e000000000000,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,
03000000120c0000121e000000000000,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,
@@ -474,8 +488,7 @@
030000004c050000a00b000000000000,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004c050000c405000000000000,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000004c050000cc09000000000000,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-030000004c050000e60c000000000000,PS5 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000ff000000cb01000000000000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+030000004c050000e60c000000000000,PS5 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:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows,
03000000300f00000111000000000000,Qanba 2,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,
03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,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:Windows,
@@ -489,23 +502,23 @@
03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,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,
030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows,
03000000086700006626000000000000,RadioShack,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,
-030000009b2800002300000000000000,Raphnet Technologies 3DO USB Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
-030000009b2800006900000000000000,Raphnet Technologies 3DO USB Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
-030000009b2800000800000000000000,Raphnet Technologies Dreamcast USB Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows,
-030000009b2800003200000000000000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
-030000009b2800006000000000000000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
-030000009b2800001800000000000000,Raphnet Technologies Jaguar USB Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
-030000009b2800000200000000000000,Raphnet Technologies NES USB Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
-030000009b2800004300000000000000,Raphnet Technologies Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
-030000009b2800000500000000000000,Raphnet Technologies Saturn Adapter 2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
-030000009b2800000300000000000000,Raphnet Technologies SNES USB Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
-030000009b2800005600000000000000,Raphnet Technologies SNES USB Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
-030000009b2800005700000000000000,Raphnet Technologies SNES USB Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
-030000009b2800001e00000000000000,Raphnet Technologies Vectrex USB Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,
-030000009b2800002b00000000000000,Raphnet Technologies Wii Classic USB Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
-030000009b2800002c00000000000000,Raphnet Technologies Wii Classic USB Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
+030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
+030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows,
+030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
+030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
+030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
+030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
+030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
+030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,
+030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
03000000321500000003000000000000,Razer Hydra,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,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000321500000204000000000000,Razer Panthera 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:Windows,
+03000000321500000204000000000000,Razer Panthera 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,
03000000321500000104000000000000,Razer Panthera 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000010000000000000,Razer Raiju,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,
03000000321500000507000000000000,Razer Raiju Mobile,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
@@ -514,14 +527,14 @@
03000000321500000a10000000000000,Razer Raiju TE,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,
03000000321500000410000000000000,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,
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 Fightpad for 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,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,
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,
-03000000bd12000013d0000000000000,Retrolink USB Sega Saturn Classic,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
-03000000bd12000015d0000000000000,Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
-0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
-0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
+03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
+03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
+0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
+0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows,
030000006b140000010d000000000000,Revolution Pro 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000006b140000020d000000000000,Revolution Pro Controller 2,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,
@@ -532,26 +545,31 @@
030000006f0e00001e01000000000000,Rock Candy 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,
030000006f0e00002801000000000000,Rock Candy 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,
030000006f0e00002f01000000000000,Rock Candy 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,
+030000006f0e00008701000000000000,Rock Candy Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
-030000004f04000003d0000000000000,Run N Drive,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,Run N Drive,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,
030000008916000000fe000000000000,Sabertooth,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,
03000000c6240000045d000000000000,Sabertooth,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,
03000000a30600001af5000000000000,Saitek Cyborg,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,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:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,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:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,
-03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,
+03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,
03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,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:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,
03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,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:a5,righty:a2,start:b8,x:b0,y:b3,platform:Windows,
03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000a306000018f5000000000000,Saitek P3200,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,platform:Windows,
03000000a30600000b04000000000000,Saitek P990,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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
-03000000a30600002106000000000000,Saitek PS1000,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:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000a306000020f6000000000000,Saitek PS2700,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:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000a30600002106000000000000,Saitek PS1000 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:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000a306000020f6000000000000,Saitek PS2700 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:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000e804000000a0000000000000,Samsung EIGP20,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,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows,
@@ -560,25 +578,27 @@
03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows,
03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows,
-03000000c01100000051000000000000,Satechi Bluetooth Controller,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,
+03000000c01100000051000000000000,Satechi Controller,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,
030000004f04000028b3000000000000,Score A,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,
03000000952e00002577000000000000,Scuf 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,
03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
-0300000000050000289b000000000000,Sega Saturn Adapter 2,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
+0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
-03000000120c00001c1e000000000000,SnakeByte GamePad 4S 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,
+03000000120c00001c1e000000000000,SnakeByte 4S 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,
0300000003040000c197000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
03000000571d00002000000000000000,SNES Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows,
03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
+03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000908000000000000,Speedlink 6566,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:Windows,
+03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows,
030000008f0e00000800000000000000,Speedlink Strike FX,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,
03000000c01100000591000000000000,Speedlink 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:Windows,
03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
@@ -592,11 +612,11 @@
03000000790000001c18000000000000,STK 7024X,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000381000003014000000000000,Stratus Duo,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,
03000000381000003114000000000000,Stratus Duo,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,
-03000000380700003847000000000000,Street Fighter Fighting Stick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
-03000000d620000011a7000000000000,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:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f0000f600000000000000,Switch Hori Pad,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:Windows,
+03000000d620000011a7000000000000,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,
+030000000d0f0000f600000000000000,Switch Hori,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:Windows,
03000000457500002211000000000000,Szmy Power PC Gamepad,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,
030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,
030000000d0f00007b00000000000000,TAC GEAR,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,
@@ -607,45 +627,45 @@
03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,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,x:b3,y:b4,platform:Windows,
03000000790000002601000000000000,TGZ,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,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
-030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3 in 1,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,
-030000004f0400000ed0000000000000,ThrustMaster eSwap PRO 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f04000023b3000000000000,Thrustmaster Dual Trigger 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:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f0400000ed0000000000000,ThrustMaster eSwap Pro 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f04000008d0000000000000,ThrustMaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,
030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
+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,
-03000000666600000488000000000000,TigerGame PS/PS2 Game Controller 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 Wireless,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,
+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,
03000000d62000006000000000000000,Tournament 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,
03000000c01100000055000000000000,Tronsmart,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,
030000005f140000c501000000000000,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:Windows,
03000000b80500000210000000000000,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:Windows,
030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,
03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
-03000000d90400000200000000000000,TwinShock PS2,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,
+03000000d90400000200000000000000,TwinShock PS2 Controller,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,
03000000101c0000171c000000000000,uRage Gamepad,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,
-030000000b0400003065000000000000,USB Game 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,
-03000000242f00006e00000000000000,USB Game Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows,
-03000000300f00000701000000000000,USB Game 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 Game 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 Game 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 Game 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 Game 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 Game 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 Game 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,
-03000000b50700001503000000000000,USB Game Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
-03000000bd12000012d0000000000000,USB Game Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
-03000000f0250000c183000000000000,USB Game 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,
-03000000ff1100004133000000000000,USB Game Controller,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:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+030000000b0400003065000000000000,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,
+03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows,
+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,
+03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+03000000ff1100004133000000000000,USB Controller,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:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002305000000000000,USB Vibration 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:Windows,
03000000790000001a18000000000000,Venom,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,
03000000790000001b18000000000000,Venom Arcade Joystick,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,
-030000006f0e00000302000000000000,Victrix Pro Fight Stick for 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,
-030000006f0e00000702000000000000,Victrix Pro Fight Stick for 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,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,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,
+030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,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,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,
03000000120c0000ab57000000000000,Warrior Joypad JS083,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,
030000007e0500003003000000000000,WiiU Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
0300000032150000030a000000000000,Wildcat,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,
-030000005e040000ff02000000000000,Wired Xbox One Controller,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:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-030000005e040000ea02000000000000,Wireless Xbox One Controller,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:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
0300000032150000140a000000000000,Wolverine,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,
030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
03000000380700001647000000000000,Xbox 360 Controller,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,
@@ -683,53 +703,61 @@
030000005e040000dd02000000000000,Xbox One Controller,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,
030000005e040000e002000000000000,Xbox One Controller,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,
030000005e040000e302000000000000,Xbox One Controller,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,
+030000005e040000ea02000000000000,Xbox One Controller,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:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000fd02000000000000,Xbox One Controller,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,
+030000005e040000ff02000000000000,Xbox One Controller,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:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e0000a802000000000000,Xbox One Controller,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,
030000006f0e0000c802000000000000,Xbox One 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:Windows,
03000000c62400003a54000000000000,Xbox One Controller,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,
030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,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,
03000000341a00000608000000000000,Xeox,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,
-03000000450c00002043000000000000,Xeox Gamepad SL6556BK,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:Windows,
+03000000450c00002043000000000000,Xeox SL6556BK,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:Windows,
030000006f0e00000300000000000000,XGear,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:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
-03000000ac0500005b05000000000000,Xiaoji Gamesir G3w,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,
-03000000172700004431000000000000,XiaoMi Game 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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000172700004431000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,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,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,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,
03000000790000004f18000000000000,ZDT Android 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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
-03000000120c0000101e000000000000,Zeroplus P4 Wired Gamepad,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,
+03000000120c0000101e000000000000,Zeroplus P4 Gamepad,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,
# Mac OS X
-030000008f0e00000300000009010000,2In1 USB 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,
+030000008f0e00000300000009010000,2In1 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,
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,
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 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,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,
03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
-030000003512000012ab000001000000,8BitDo NES30 Gamepad,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,
-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,
-03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
-03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
-03000000c82d00004028000000010000,8Bitdo SN30 GamePad,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,
+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,
+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,
+03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,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,
03000000c82d00000161000000010000,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:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000260000001000000,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:Mac OS X,
03000000c82d00000261000000010000,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:Mac OS X,
-03000000c82d00000031000001000000,8BitDo Wireless 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,
+03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00003032000000010000,8BitDo Zero 2,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:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
-03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
-03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
03000000a30c00002700000003030000,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,
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,
-03000000ef0500000300000000020000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,
+03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,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,
@@ -738,7 +766,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008305000031b0000000000000,Cideko AK08b,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:Mac OS X,
03000000d8140000cecf000000000000,Cthulhu,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,
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 V.3 Rumble Pad,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,
+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,
030000000d0f00008400000000010000,Fighting Commander,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,Fighting Commander,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,
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,
@@ -747,17 +776,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,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,
0500000047532047616d657061640000,GameStop Gamepad,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:Mac OS X,
03000000c01100000140000000010000,GameStop PS4 Fun 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,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,
-030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006f0e00000102000000000000,GameStop Xbox 360 Controller,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,
+030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000280400000140000000020000,Gravis Gamepad Pro,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:Mac OS X,
-030000008f0e00000300000007010000,GreenAsia USB Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,
+030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,
030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005f00000000000000,Hori Fighting Commander 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005e00000000000000,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,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,
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,
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,
-030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro Pad,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,
+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,
030000000d0f00006e00000000010000,Horipad 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006600000000010000,Horipad 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006600000000000000,Horipad FPS Plus 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -766,59 +795,65 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000830500006020000000000000,iBuffalo Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,
030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X,
030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,
-03000000242f00002d00000007010000,JYS Wireless Adapter,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,
+03000000242f00002d00000007010000,JYS Adapter,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,
+030000006d04000019c2000000000000,Logitech 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:Mac OS X,
030000006d04000016c2000000020000,Logitech Dual Action,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:Mac OS X,
030000006d04000016c2000000030000,Logitech Dual Action,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:Mac OS X,
030000006d04000016c2000014040000,Logitech Dual Action,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:Mac OS X,
-030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),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:Mac OS X,
-030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),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:Mac OS X,
-030000006d04000019c2000005030000,Logitech F710 Gamepad,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:Mac OS X,
-030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),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,
-030000006d04000018c2000000010000,Logitech RumblePad 2 USB,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:Mac OS X,
-030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),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:Mac OS X,
-03000000380700005032000000010000,Mad Catz FightPad PRO (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,
-03000000380700005082000000010000,Mad Catz FightPad PRO (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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000380700008433000000010000,Mad Catz FightStick TE S+ (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,
-03000000380700008483000000010000,Mad Catz FightStick TE S+ (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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d04000016c2000000000000,Logitech F310,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:Mac OS X,
+030000006d04000018c2000000000000,Logitech F510,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:Mac OS X,
+030000006d04000019c2000005030000,Logitech F710,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:Mac OS X,
+030000006d0400001fc2000000000000,Logitech F710,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,
+030000006d04000018c2000000010000,Logitech RumblePad 2,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:Mac OS X,
+03000000380700005032000000010000,Mad Catz PS3 Fightpad 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: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,
+03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S+,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,
+03000000380700005082000000010000,Mad Catz PS4 Fightpad 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:Mac OS X,
+03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S+,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,
03000000790000000600000007010000,Marvo GT-004,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,
03000000790000004418000000010000,Mayflash GameCube Controller,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:Mac OS X,
+03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,x:b8,y:b12,start:b36,rightshoulder:b28,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a20,righty:a8,lefttrigger:a12,righttrigger:a16,platform:Mac OS X,
03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,
0300000079000000d218000026010000,Mayflash Magic NS,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,
03000000d620000010a7000003010000,Mayflash Magic NS,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,
0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,
03000000790000000018000000010000,Mayflash Wii U Pro Controller Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
-03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
+03000000790000000018000000000000,Mayflash WiiU Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
+030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X,
030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,
-03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Mac OS X,
+03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Mac OS X,
03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,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,
03000000c62400002b89000000010000,MOGA XP5A 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,
-03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X,
030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
-03000000d620000011a7000000020000,Nintendo Switch Core Plus Wired 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:Mac OS X,
-03000000d620000011a7000010050000,Nintendo Switch PowerA Wired 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:Mac OS X,
+03000000d620000011a7000000020000,Nintendo Switch 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:Mac OS X,
+03000000d620000011a7000010050000,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:Mac OS X,
030000007e0500000920000000000000,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:Mac OS X,
030000007e0500000920000001000000,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:Mac OS X,
-03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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:Mac OS X,
-030000006f0e00000901000002010000,PDP Versus Fighting Pad,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:Mac OS X,
+030000007e0500001920000001000000,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:Mac OS X,
+030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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:Mac OS X,
+030000006f0e00000901000002010000,PDP Versus Fighting,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:Mac OS X,
030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,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:Mac OS X,
-030000004c050000da0c000000010000,Playstation Classic 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:Mac OS X,
+030000004c050000da0c000000010000,PlayStation Classic 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:Mac OS X,
030000004c0500003713000000010000,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:Mac OS X,
03000000d62000006dca000000010000,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:Mac OS X,
03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
+030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,x:b15,y:b12,back:b0,guide:b16,start:b3,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpdown:b6,dpleft:b7,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Mac OS X,
030000004c050000a00b000000010000,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: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,
030000004c050000c405000000000000,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: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,
030000004c050000c405000000010000,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: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,
030000004c050000cc09000000010000,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: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,
-050000004c050000e60c000000010000,PS5 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+050000004c050000e60c000000010000,PS5 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:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+03000000222c00000020000000010000,Qanba Drone Arcade Stick,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,
030000008916000000fd000000000000,Razer Onza TE,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,
-03000000321500000204000000010000,Razer Panthera 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,
+03000000321500000204000000010000,Razer Panthera 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:Mac OS X,
03000000321500000104000000010000,Razer Panthera 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000321500000010000000010000,Razer Raiju,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,
03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,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,
-03000000321500000011000000010000,Razer Raion Fightpad for 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000321500000011000000010000,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:Mac OS X,
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,
@@ -828,15 +863,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
030000006b140000010d000000010000,Revolution Pro 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006b140000130d000000010000,Revolution Pro Controller 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: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,
-03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,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,
+03000000c6240000fefa000000000000,Rock Candy PS3,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,
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X,
03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
-03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
+03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
-030000004c050000e60c000000010000,Sony DualSense,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,
+030000004c050000e60c000000010000,PS5 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,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,
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,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,
-030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,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,
03000000d11800000094000000010000,Stadia 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: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,
030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,
@@ -844,63 +879,73 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
+050000004e696d6275732b008b000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
05000000556e6b6e6f776e2048494400,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000457500002211000000010000,SZMY Power PC Gamepad,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,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
-030000004f0400000ed0000000020000,ThrustMaster eSwap PRO 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004f0400000ed0000000020000,ThrustMaster eSwap Pro 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
-03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,
-030000006f0e00000302000025040000,Victrix Pro Fight Stick for 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:Mac OS X,
-030000006f0e00000702000003060000,Victrix Pro Fight Stick for 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,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000791d00000103000009010000,Wii Classic Controller,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,
+030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,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:Mac OS X,
+030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,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,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,
050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,
030000005e0400008e02000000000000,Xbox 360 Controller,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,
-030000006f0e00000104000000000000,Xbox 360 Wired Controller,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,
-03000000c6240000045d000000000000,Xbox 360 Wired Controller,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,
+030000006f0e00000104000000000000,Xbox 360 Controller,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,
+03000000c6240000045d000000000000,Xbox 360 Controller,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,
030000005e0400000a0b000000000000,Xbox Adaptive Controller,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,
-030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,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:Mac OS X,
-03000000c62400003a54000000000000,Xbox One PowerA Wired Controller,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,
-030000005e040000d102000000000000,Xbox One Wired Controller,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,
-030000005e040000dd02000000000000,Xbox One Wired Controller,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,
-030000005e040000e302000000000000,Xbox One Wired Controller,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,
+030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,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:Mac OS X,
+030000005e040000130b000011050000,Xbox One 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:Mac OS X,
+030000005e040000200b000011050000,Xbox One 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:Mac OS X,
+030000005e040000d102000000000000,Xbox One Controller,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,
+030000005e040000dd02000000000000,Xbox One Controller,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,
+030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,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:Mac OS X,
+030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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,
+030000005e040000e302000000000000,Xbox One Controller,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,
+030000005e040000ea02000000000000,Xbox One Controller,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,
+030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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,
+03000000c62400003a54000000000000,Xbox One PowerA Controller,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,
030000005e040000130b000001050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000005050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000009050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
-030000005e040000200b000011050000,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:Mac OS X,
-030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,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:Mac OS X,
-030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,x:b3,y:b4,back:b16,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X,
-030000005e040000ea02000000000000,Xbox Wireless Controller,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,
-030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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,
-03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
-03000000120c0000100e000000010000,Zeroplus P4 Gamepad,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,
-03000000120c0000101e000000010000,Zeroplus P4 Wired Gamepad,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,
+03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000120c0000100e000000010000,Zeroplus P4,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,
+03000000120c0000101e000000010000,Zeroplus P4,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,
# 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,
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,
+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,
+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,
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,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
-03000000022000000090000011010000,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,
-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,
+03000000022000000090000011010000,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,
+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,
+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,
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,
+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,
030000003512000021ab000010010000,8BitDo SFC30,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,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-030000003512000012ab000010010000,8Bitdo SFC30 GamePad,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,
-05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,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,
@@ -909,22 +954,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c82d00006228000000010000,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,
03000000c82d00000260000011010000,8BitDo SN30 Pro+,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,
05000000c82d00000261000000010000,8BitDo SN30 Pro+,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,
-05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),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,
-030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),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,
+05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
+05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
05000000c82d00003032000000010000,8BitDo Zero 2,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,
-050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
-05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
-05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c01100000355000011010000,Acrux Gamepad,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,
-030000006f0e00001302000000010000,Afterglow,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,
-030000006f0e00003901000020060000,Afterglow Controller for 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,
030000006f0e00003901000000430000,Afterglow Prismatic 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,
-030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,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,
-03000000100000008200000011010000,Akishop Customs PS360 v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
-030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
-05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,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,
+030000006f0e00001302000000010000,Afterglow Xbox 360 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,
+030000006f0e00003901000020060000,Afterglow 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,
+03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000007c1800000006000010010000,Alienware Dual Compatible Game 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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
+05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
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,
@@ -933,17 +976,25 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
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,
-03000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,
-05000000503200000210000000000000,Atari Game 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:b3,y:b2,platform:Linux,
-03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
-03000000ef0500000300000000010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
+05000000503200000110000044010000,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,
+05000000503200000110000046010000,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,
+03000000503200000210000000000000,Atari Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,
+03000000503200000210000011010000,Atari 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:b3,y:b2,platform:Linux,
+05000000503200000210000000000000,Atari 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:b3,y:b2,platform:Linux,
+05000000503200000210000045010000,Atari 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:b3,y:b2,platform:Linux,
+05000000503200000210000046010000,Atari 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:b3,y:b2,platform:Linux,
+05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,
+03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
+03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
03000000c62400001b89000011010000,BDA MOGA XP5X 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:Linux,
03000000d62000002a79000011010000,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:Linux,
03000000c21100000791000011010000,Be1 GC101 Controller 1.03,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,
-03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03,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,
+03000000c31100000791000011010000,Be1 GC101 Controller 1.03,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,
030000005e0400008e02000003030000,Be1 GC101 Xbox 360,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,
05000000bc2000000055000001000000,BETOP AX1 BFM,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:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,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,
030000006b1400000209000011010000,Bigben,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,
03000000666600006706000000010000,Boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
03000000120c0000200e000011010000,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -952,43 +1003,51 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000e82000006058000001010000,Cideko AK08b,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,
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
03000000260900008888000000010000,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:Linux,
-03000000a306000022f6000011010000,Cyborg V3 Rumble Pad,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:Linux,
+03000000a306000022f6000011010000,Cyborg V3 Rumble,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:Linux,
+03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Linux,
030000004f04000004b3000010010000,Dual Power 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000006f0e00003001000001010000,EA Sports 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,
03000000c11100000191000011010000,EasySMX,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,
+03000000242f00009100000000010000,EasySMX ESM-9101,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,
030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,
+030000006e0500000720000010010000,Elecom 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:Linux,
03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,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:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000b40400001124000011010000,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:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000151900004000000001000000,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:Linux,
+03000000ac0500005b05000010010000,GameSir G3w,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,
03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,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:b3,y:b4,platform:Linux,
-05000000ac0500002d0200001b010000,Gamesir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,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,
-03000000bc2000005656000011010000,Gamesir T4w,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,
+03000000558500001b06000010010000,GameSir G4 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:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,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,
+03000000bc2000005656000011010000,GameSir T4w,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,
0500000047532047616d657061640000,GameStop Gamepad,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,
030000006f0e00000104000000010000,Gamestop Logic3 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,
030000008f0e00000800000010010000,Gasia PlayStation Gamepad,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,
03000000451300000010000010010000,Genius Maxfire Grandias 12,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,
03000000f0250000c183000010010000,Goodbetterbest 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,
0300000079000000d418000000010000,GPD Win 2 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,
-030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
-03000000280400000140000000010000,Gravis GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000280400000140000000010000,Gravis Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,
-030000008f0e00001200000010010000,GreenAsia USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,
03000000f0250000c383000010010000,GT VX2,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,
-06000000adde0000efbe000002010000,Hidromancer Game 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,
+06000000adde0000efbe000002010000,Hidromancer 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,
03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,
-03000000c9110000f055000011010000,HJC Game Gamepqd,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,
+03000000c9110000f055000011010000,HJC Gamepad,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,
03000000632500002605000010010000,HJDX,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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000000d0f00000d00000000010000,Hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,
+030000000d0f00006d00000020010000,Hori EDGE 301,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,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,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,
030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005e00000011010000,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:Linux,
-030000000d0f00005001000009040000,Hori Fighting Commander OCTA,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,
-030000000d0f00001000000011010000,Hori Fighting Stick 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,
+030000000d0f00005001000009040000,Hori Fighting Commander OCTA 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,
+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,
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 Pad,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,
+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,
030000000d0f0000aa00000011010000,Hori Real Arcade Pro,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,
030000000d0f00002200000011010000,Hori Real Arcade Pro 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,
030000000d0f00006a00000011010000,Hori Real Arcade Pro 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -999,107 +1058,121 @@ 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,
-03000000341a000005f7000010010000,HuiJia GameCube Controller Adpater,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,
+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,
050000006964726f69643a636f6e0000,idroidcon 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,
03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
-03000000d80400008200000003000000,IMS PCU0 Gamepad,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
+03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
03000000fd0500000030000000010000,InterAct GoPad I73000,a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,
-0500000049190000020400001b010000,Ipega PG 9069 Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,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,
-03000000632500007505000011010000,Ipega PG 9099 Bluetooth Gamepad,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,
+03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,
+0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,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,
+03000000632500007505000011010000,Ipega PG 9099,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,
0500000049190000030400001b010000,Ipega PG9099,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:Linux,
05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,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:b3,y:b4,platform:Linux,
-03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
-03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,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:Linux,
-03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,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:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
+03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
+03000000300f00000b01000010010000,Jess Tech GGE909 PC 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:Linux,
+03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,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:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,
050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,
030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,
03000000bd12000003c0000010010000,Joypad Alpha Shock,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,
-03000000242f00002d00000011010000,JYS Wireless Adapter,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,
-03000000242f00008a00000011010000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
+03000000242f00002d00000011010000,JYS Adapter,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,
+03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
030000006f0e00000103000000020000,Logic3 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,
030000006d040000d1ca000000000000,Logitech Chillstream,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,
030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,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,
030000006d04000016c2000010010000,Logitech Dual Action,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,
030000006d04000016c2000011010000,Logitech Dual Action,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,
-030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),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,
-030000006d0400001ec2000019200000,Logitech F510 Gamepad (XInput),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,
-030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),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,
-030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),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,
-030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),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,
+030000006d0400001dc2000014400000,Logitech F310,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,
+030000006d0400001ec2000019200000,Logitech F510,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,
+030000006d0400001ec2000020200000,Logitech F510,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,
+030000006d04000019c2000011010000,Logitech F710,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,
+030000006d0400001fc2000005030000,Logitech F710,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,
030000006d04000018c2000010010000,Logitech RumblePad 2,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,
030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
05000000380700006652000025010000,Mad Catz CTRLR,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,
-03000000380700005032000011010000,Mad Catz FightPad PRO 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,
-03000000380700005082000011010000,Mad Catz FightPad PRO 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700005032000011010000,Mad Catz Fightpad Pro 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,
+03000000380700005082000011010000,Mad Catz Fightpad Pro 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
-03000000380700008034000011010000,Mad Catz fightstick PS3,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000380700008084000011010000,Mad Catz fightstick 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:Linux,
-03000000380700008433000011010000,Mad Catz FightStick TE S 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,
-03000000380700008483000011010000,Mad Catz FightStick TE S 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000380700001647000010040000,Mad Catz Wired Xbox 360 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,
-03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+03000000380700008034000011010000,Mad Catz Fightstick PS3,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008084000011010000,Mad Catz Fightstick 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:Linux,
+03000000380700008433000011010000,Mad Catz Fightstick TE S 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,
+03000000380700008483000011010000,Mad Catz Fightstick TE S 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700001888000010010000,Mad Catz Joystick,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700001647000010040000,Mad Catz Xbox 360 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,
+03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000ad1b000016f0000090040000,Mad Catz Xbox 360 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,
-03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,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,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000120c00000500000000010000,Manta Dualshock 2,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:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,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:b2,y:b3,platform:Linux,
-03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
+03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
0300000079000000d218000011010000,Mayflash Magic NS,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,
03000000d620000010a7000011010000,Mayflash Magic NS,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,
03000000242f0000f700000001010000,Mayflash Magic S Pro,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,
0300000025090000e803000001010000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
-03000000780000000600000010010000,Microntek USB Joystick,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,
+03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Linux,
+03000000780000000600000010010000,Microntek Joystick,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,
+030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,
-030000005e0400000700000000010000,Microsoft SideWinder Game Pad USB,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
+030000005e0400000700000000010000,Microsoft SideWinder Gamepad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux,
-030000005e0400008e02000056210000,Microsoft X-Box 360 pad,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,
-030000005e0400008e02000004010000,Microsoft Xbox 360 pad,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,
-030000005e0400008e02000062230000,Microsoft Xbox 360 pad,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,
-030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad,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,
-050000005e040000050b000003090000,Microsoft Xbox One Elite 2 pad,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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,
-030000005e040000e302000003020000,Microsoft Xbox One Elite pad,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,
-030000005e040000d102000001010000,Microsoft Xbox One pad,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,
-030000005e040000dd02000003020000,Microsoft Xbox One pad 2015,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,
-030000005e040000d102000003020000,Microsoft Xbox One pad v2,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,
-030000005e040000ea02000008040000,Microsoft Xbox One S pad,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,
-030000005e0400008502000000010000,Microsoft Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,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,
+030000005e0400008e02000004010000,Microsoft Xbox 360,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,
+030000005e0400008e02000056210000,Microsoft Xbox 360,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,
+030000005e0400008e02000062230000,Microsoft Xbox 360,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,
+030000005e040000d102000001010000,Microsoft 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,
+030000005e040000d102000003020000,Microsoft 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,
+060000005e040000120b000009050000,Microsoft 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,
+030000005e040000120b00000b050000,Microsoft 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,
+030000005e040000dd02000003020000,Microsoft Xbox One 2015,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,
+030000005e040000e302000003020000,Microsoft Xbox One Elite,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,
+030000005e040000000b000008040000,Microsoft Xbox One Elite 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,
+050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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,
+030000005e040000ea02000008040000,Microsoft Xbox One S,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,
030000005e0400008902000021010000,Microsoft Xbox pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
050000004d4f435554452d3035335800,Mocute 053X,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,
050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,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:b3,y:b4,platform:Linux,
-05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,
+05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,
05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,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:b6,x:b2,y:b3,platform:Linux,
-05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,
+05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,
03000000c62400002b89000011010000,MOGA XP5A 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:Linux,
05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,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,
05000000c62400001a89000000010000,MOGA XP5X 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:Linux,
03000000250900006688000000010000,MP8866 Super Dual Box,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:Linux,
+030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,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,
030000006b140000010c000010010000,Nacon GC 400ES,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,
030000000d0f00000900000010010000,Natec Genesis P44,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,
-030000004f1f00000800000011010000,Neogeo PS3,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,
+030000004f1f00000800000011010000,NeoGeo PS3,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,
+0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,
+050000004e696d6275732b0000000000,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,
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,
-060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),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,
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,
-050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b9,b:b8,back:b5,leftshoulder:b2,leftstick:b6,leftx:a1,lefty:a0~,rightshoulder:b4,start:b0,x:b7,y:b10,platform:Linux,
-03000000d620000013a7000011010000,Nintendo Switch PowerA Wired 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,
+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,
-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,
-050000007e0500001720000001000000,Nintendo Switch SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,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,
-05000000010000000100000003000000,Nintendo Wiimote,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,
-030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,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,
+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,
03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
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,
@@ -1107,33 +1180,35 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
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 Game 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 Game 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,
-03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
-03000000790000001c18000011010000,PC Game 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:Linux,
-03000000ff1100003133000010010000,PC Game 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:Linux,
-030000006f0e0000b802000001010000,PDP Afterglow Wired 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,
-030000006f0e0000b802000013020000,PDP Afterglow Wired 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,
+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,
+05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux,
+03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
+03000000790000001c18000011010000,PC 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:Linux,
+03000000ff1100003133000010010000,PC 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:Linux,
+030000006f0e0000b802000001010000,PDP Afterglow 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,
+030000006f0e0000b802000013020000,PDP Afterglow 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,
030000006f0e00006401000001010000,PDP Battlefield 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,
030000006f0e00003101000000010000,PDP EA Sports 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,
-030000006f0e00008001000011010000,PDP Faceoff 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:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00008001000011010000,PDP Faceoff Nintendo Switch Pro 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,
030000006f0e0000c802000012010000,PDP Kingdom Hearts 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,
-030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,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:b3,y:b0,platform:Linux,
-030000006f0e00000901000011010000,PDP Versus Fighting Pad,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,
-030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,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,
-030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,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,
+030000006f0e00008501000011010000,PDP Nintendo Switch Fightpad Pro,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,
+030000006f0e00002801000011010000,PDP PS3 Rock Candy 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,
+030000006f0e00008701000011010000,PDP Rock Nintendo Switch Candy Controller,a:b2,b:b1,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:b3,y:b0,platform:Linux,
+030000006f0e00000901000011010000,PDP Versus Fighting,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,
+030000006f0e0000a802000023020000,PDP Xbox One Controller,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,
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,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,
-030000004c050000da0c000011010000,Playstation 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,
-03000000d9040000160f000000010000,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:Linux,
+030000004c050000da0c000011010000,PlayStation 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,
+03000000d9040000160f000000010000,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:Linux,
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,
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,
-03000000d62000000228000001010000,PowerA Wired Controller for 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 Wired Controller for Xbox One and Xbox Series S and X,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,
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,
-03000000c62400001a54000001010000,PowerA Xbox One Mini Wired 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,
+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,
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,
@@ -1141,6 +1216,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000005f1400003102000010010000,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:Linux,
030000006f0e00001402000011010000,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,
030000008f0e00000300000010010000,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:Linux,
050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
@@ -1163,25 +1239,23 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c050000cc09000000010000,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
050000004c050000cc09000000810000,PS4 Controller,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000cc09000001800000,PS4 Controller,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-030000004c050000e60c000011010000,PS5 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-050000004c050000e60c000000010000,PS5 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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000ff000000cb01000010010000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
+030000004c050000e60c000011010000,PS5 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:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+050000004c050000e60c000000010000,PS5 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:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
-030000009b2800004200000001010000,Raphnet Technologies Dual NES to USB v2.0,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,
-030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
-030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
-030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
+030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
+030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,
+030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
+030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
030000008916000000fd000024010000,Razer Onza Tournament Edition,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,
-03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000204000011010000,Razer Panthera 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,
03000000321500000104000011010000,Razer Panthera 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000010000011010000,Razer Raiju,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:Linux,
03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,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,
-05000000321500000a10000001000000,Razer Raiju Tournament Edition,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:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000321500000710000000010000,Razer Raiju Tournament Edition Wired,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:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000321500000010000011010000,Razer Rainu,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:Linux,
-03000000321500000011000011010000,Razer Raion Fightpad for 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+05000000321500000a10000001000000,Razer Raiju Tournament Edition,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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000011000011010000,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:Linux,
030000008916000000fe000024010000,Razer Sabertooth,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,
03000000c6240000045d000024010000,Razer Sabertooth,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,
03000000c6240000045d000025010000,Razer Sabertooth,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,
@@ -1191,42 +1265,48 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,
0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
+00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux,
030000006b140000010d000011010000,Revolution Pro 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006b140000130d000011010000,Revolution Pro Controller 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00001f01000000010000,Rock Candy,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,
030000006f0e00001e01000011010000,Rock Candy 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,
03000000c6240000fefa000000010000,Rock Candy Xbox 360 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,
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,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,
-03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,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:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000a306000023f6000011010000,Saitek Cyborg V1 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:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,
03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,
-03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,
-03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,
-03000000a306000018f5000010010000,Saitek P3200 Rumble Pad,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:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,
+03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,
+03000000a306000018f5000010010000,Saitek P3200 Rumble,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:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,
-03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,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:b8,x:b0,y:b3,platform:Linux,
-03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,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:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,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:b8,x:b0,y:b3,platform:Linux,
+03000000a306000020f6000011010000,Saitek PS2700 Rumble,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:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,
-03000000a30c00002500000011010000,Sega Genesis Mini 3B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
+03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
+03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
+03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
+03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
-03000000f025000021c1000010010000,Shanwan Gioteck PS3 Wired 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:Linux,
-03000000632500007505000010010000,Shanwan PS3 PC 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,
-03000000bc2000000055000010010000,Shanwan PS3 PC Wired GamePad,a:b0,b:b1,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:b3,y:b4,platform:Linux,
-030000005f140000c501000010010000,Shanwan 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,
-03000000632500002305000010010000,ShanWan USB Gamepad,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,
+03000000632500002305000010010000,ShanWan Gamepad,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,
+03000000f025000021c1000010010000,Shanwan 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:Linux,
+03000000632500007505000010010000,Shanwan PS3 PC,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,
+03000000bc2000000055000010010000,Shanwan PS3 PC ,a:b0,b:b1,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:b3,y:b4,platform:Linux,
+030000005f140000c501000010010000,Shanwan Trust,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,
03000000341a00000908000010010000,SL6566,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,
-030000004c050000e60c000011810000,Sony DualSense,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-050000004c050000e60c000000810000,Sony DualSense,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,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:Linux,
-030000005e0400008e02000073050000,Speedlink Torid Wireless 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,
-030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog Gamepad pad,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,
+030000004c050000e60c000011810000,PS5 Controller,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000e60c000000810000,PS5 Controller,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000cc09000001000000,Sony DualShock 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
+03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,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:Linux,
+030000005e0400008e02000073050000,Speedlink 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,
+030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,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,
03000000d11800000094000011010000,Stadia 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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000112000001000000,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,
03000000de2800000211000001000000,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,
-03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de2800004211000001000000,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,
-03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,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,
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,
@@ -1236,118 +1316,137 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000381000003114000075010000,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,
0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,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,
05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,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:b3,y:b4,platform:Linux,
-03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
+03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
03000000666600000488000000010000,Super Joy Box 5 Pro,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:Linux,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
030000008f0e00000d31000010010000,SZMY Power 3 Turbo,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,
03000000457500002211000010010000,SZMY Power 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,
-030000008f0e00001431000010010000,SZMY Power PS3 gamepad,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,
+030000008f0e00001431000010010000,SZMY Power 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,
03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,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:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux,
-030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
-030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3 in 1,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:Linux,
-030000004f0400000ed0000011010000,Thrustmaster eSwap PRO 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+030000004f04000023b3000000010000,Thrustmaster Dual Trigger 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:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004f0400000ed0000011010000,Thrustmaster eSwap Pro 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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,
030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux,
030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,
-030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,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,
-03000000c6240000025b000002020000,Thrustmaster GPX 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,
-030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,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:Linux,
-030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless 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,
-030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,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,
-030000004f04000012b3000010010000,Thrustmaster vibrating gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
-03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
+030000004f04000026b3000002040000,Thrustmaster GP XID,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,
+03000000c6240000025b000002020000,Thrustmaster GPX,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,
+030000004f04000008d0000000010000,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:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004f04000009d0000000010000,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: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,
+030000004f04000007d0000000010000,Thrustmaster T Mini,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,
+030000004f04000012b3000010010000,Thrustmaster vibrating,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
+03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
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,
-03000000100800000100000010010000,Twin USB 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,
+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,
03000000790000000600000007010000,USB gamepad,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:a4,start:b9,x:b3,y:b0,platform:Linux,
-03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
-03000000790000001100000011010000,USB Saturn Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
-03000000790000002201000011010000,USB Saturn Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
-03000000b40400000a01000000010000,USB Saturn Pad,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
-030000006f0e00000302000011010000,Victrix Pro Fight Stick for 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:Linux,
-030000006f0e00000702000011010000,Victrix Pro Fight Stick for 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,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
+030000006f0e00000302000011010000,Victrix Pro Fightstick 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:Linux,
+030000006f0e00000702000011010000,Victrix Pro Fightstick 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,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
05000000ac0500003232000001000000,VR Box Controller,a:b0,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:b2,y:b3,platform:Linux,
-03000000791d00000103000010010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Linux,
-050000000d0f0000f600000001000000,Wireless 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,
+0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
+030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
030000005e0400008e02000010010000,Xbox 360 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,
030000005e0400008e02000014010000,Xbox 360 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,
-0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
-030000005e0400001907000000010000,Xbox 360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
-030000005e0400009102000007010000,Xbox 360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
-030000005e040000a102000000010000,Xbox 360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
-030000005e040000a102000007010000,Xbox 360 Wireless 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,
-030000005e0400008e02000000010000,Xbox 360 Wireless EasySMX,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,
-030000005e040000a102000014010000,Xbox 360 Wireless Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
+030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
+030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
+030000005e040000a102000007010000,Xbox 360 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,
+030000005e0400008e02000000010000,Xbox 360 EasySMX,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,
+030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,
+030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
030000006f0e00001304000000010000,Xbox 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,
03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
0000000058626f782047616d65706100,Xbox 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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
+030000005e040000120b000009050000,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,
030000005e040000d102000002010000,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,
+030000005e040000ea02000000000000,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,
+030000005e040000ea02000001030000,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,
+050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,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:Linux,
+050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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,
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,
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,
-030000005e040000ea02000000000000,Xbox One Wireless 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,
-050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,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:Linux,
-050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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,
-030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),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 Wireless Controller (Model 1914),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,
-030000005e0400000202000000010000,Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,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,
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,
030000005e040000130b000005050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000001050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000005050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
-03000000450c00002043000010010000,XEOX Gamepad 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,
-03000000ac0500005b05000010010000,Xiaoji Gamesir G3w,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,
-05000000172700004431000029010000,XiaoMi Game 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,
+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,
+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,
+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,
xinput,XInput 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,
-03000000120c0000100e000011010000,Zeroplus P4 Gamepad,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:Linux,
-03000000120c0000101e000011010000,Zeroplus P4 Wired Gamepad,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:Linux,
+03000000120c0000100e000011010000,Zeroplus P4,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:Linux,
+03000000120c0000101e000011010000,Zeroplus P4,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:Linux,
# Android
38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,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:b2,y:b3,platform:Android,
+36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,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:b2,y:b3,platform:Android,
+38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+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,
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,
+05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,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,
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,
-05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
-05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,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,
+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,
+62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,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,x:b3,y:b2,platform:Android,
+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,
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,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android,
-05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
-05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,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,
38303232393133383836366330346462,8BitDo SN30 Pro Plus,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,righty:a4,start:b10,x:b19,y:b2,platform:Android,
38346630346135363335366265656666,8BitDo SN30 Pro Plus,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,
+38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,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,
+536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,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,
66306331643531333230306437353936,8BitDo SN30 Pro Plus,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,
05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,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,
-050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,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,
-050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
+050000002028000009000000ffff3f00,8BitDo SNES30,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,
+050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
63396666386564393334393236386630,8BitDo Zero 2,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,start:b6,x:b3,y:b2,platform:Android,
63633435623263373466343461646430,8BitDo Zero 2,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,start:b6,x:b2,y:b3,platform:Android,
-32333634613735616163326165323731,Amazon Luna Game Controller,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,x:b2,y:b3,platform:Android,
+32333634613735616163326165323731,Amazon Luna Controller,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,x:b2,y:b3,platform:Android,
+417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,leftx:a0,lefty:a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,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,
-33323763323132376537376266393366,Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,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,
@@ -1357,74 +1456,102 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,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:b2,y:b3,platform:Android,
66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b18,platform:Android,
31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,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,
0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android,
64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android,
+532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android,
65346535636333663931613264643164,Joy Con,a:b21,b:b22,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:b23,y:b24,platform:Android,
33346566643039343630376565326335,Joy Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
35313531613435623366313835326238,Joy Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
38383665633039363066383334653465,Joy Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
39363561613936303237333537383931,Joy Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
+4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
39656136363638323036303865326464,JYS Aapter,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,
63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,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:b0,y:b2,platform:Android,
64623163333561643339623235373232,Logitech F310,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,
35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,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:b2,y:b3,platform:Android,
+4c6f6769746563682047616d65706164,Logitech F710,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,
64396331333230326333313330336533,Logitech F710,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,
+416d617a6f6e2047616d6520436f6e74,Luna 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:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+4c756e612047616d6570616400000000,Luna Controller,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,
30363066623539323534363639323363,Magic NS,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,
31353762393935386662336365626334,Magic NS,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,
39623565346366623931666633323530,Magic NS,a:b1,b:b3,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:b0,y:b2,platform:Android,
-32303165626138343962363666346165,Mars,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,
+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,
+6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,x:b23,y:b24,start:b30,rightshoulder:b28,lefttrigger:b25,righttrigger:b26,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Android,
+65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,leftshoulder:b3,rightshoulder:b20,lefttrigger:b9,start:b18,guide:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,platform:Android,
+436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,leftshoulder:b3,rightshoulder:b20,lefttrigger:b9,start:b18,guide:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,platform:Android,
31323564663862633234646330373138,Mega Drive,a:b23,b:b22,leftx:a0,lefty: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,
+33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android,
30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,leftshoulder:b20,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android,
-64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,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,x:b2,y:b3,platform:Android,
32386235353630393033393135613831,Microsoft Xbox Series Controller,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:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d4f435554452d303533582d4d35312d,Mocute 053X,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,
33343361376163623438613466616531,Mocute M053,a:b0,b:b1,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:b2,y:b3,platform:Android,
39306635663061636563316166303966,Mocute M053,a:b0,b:b1,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:b2,y:b3,platform:Android,
7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android,
050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android,
34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android,
+36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
+4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
+534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,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:b2,y:b3,platform:Android,
+050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,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:b2,y:b3,platform:Android,
+050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,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,
4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,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,
61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,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,
-050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,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:b2,y:b3,platform:Android,
-050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,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:b2,y:b3,platform:Android,
-050000005509000014720000df7f3f00,NVIDIA Controller v01.04,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
+4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
+506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
+62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,leftshoulder:b9,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android,
61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android,
32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android,
-61363034663839376638653463633865,PS3,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-66366539656564653432353139356536,PS3,a:b0,b:b1,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:b2,y:b3,platform:Android,
-66383132326164626636313737373037,PS3,a:b0,b:b1,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:b2,y:b3,platform:Android,
050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,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:b2,y:b3,platform:Android,
-30303839663330346632363232623138,PS4,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
-31326235383662333266633463653332,PS4,a:b1,b:b16,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android,
-31663838336334393132303338353963,PS4,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-34613139376634626133336530386430,PS4,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,
-37626233336235343937333961353732,PS4,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,
-38393161636261653636653532386639,PS4,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,
-63313733393535663339656564343962,PS4,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,
-63393662363836383439353064663939,PS4,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,
-65366465656364636137653363376531,PS4,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,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,
+536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
+61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,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:b2,y:b3,platform:Android,
+66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,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:b2,y:b3,platform:Android,
050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
050000004c050000c4050000fffe3f00,PS4 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,
050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
050000004c050000cc090000fffe3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
+30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
+31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android,
31373231336561636235613666323035,PS4 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,
+31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+34613139376634626133336530386430,PS4 Controller,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,
35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
+37626233336235343937333961353732,PS4 Controller,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,
+38393161636261653636653532386639,PS4 Controller,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,
+536f6e7920496e746572616374697665,PS4 Controller,a:b0,b:b0,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,
+576972656c65737320436f6e74726f6c,PS4 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,
+63313733393535663339656564343962,PS4 Controller,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,
+63393662363836383439353064663939,PS4 Controller,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,
+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,
-62653335326261303663356263626339,PSX,a:b19,b:b1,back:b17,leftshoulder:b9,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,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,
050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,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:b2,y:b3,platform:Android,
050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,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:b2,y:b3,platform:Android,
050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android,
+32417865732031314b6579732047616d,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+36313938306539326233393732613361,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android,
61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android,
-38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38653130373365613538333235303036,Retroid Pocket 2,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,
64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b6,platform:Android,
33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,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:b24,platform:Android,
66386565396238363534313863353065,Sanwa Mobile,a:b21,b:b22,leftshoulder:b23,leftx:a0,lefty:a1,rightshoulder:b24,platform:Android,
@@ -1437,40 +1564,49 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
66633132393363353531373465633064,SG H510,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,righty:a4,start:b10,x:b19,y:b2,platform:Android,
62653761636366393366613135366338,SN30 PP,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,
38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
-32633532643734376632656664383733,Sony DualSense,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,Sony DualSense,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,
+5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
+5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,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,
+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,
63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android,
63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android,
+476f6f676c65204c4c43205374616469,Stadia 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,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
0500000011010000201400000f7e0f00,SteelSeries Nimbus,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,rightx:a2,righty:a3,x:b19,y:b2,platform:Android,
-050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
-30623739343039643830333266346439,Valve Steam 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,leftx:a0,lefty:a1,paddle1:b23,paddle2:b24,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-31643365666432386133346639383937,Valve Steam 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,leftx:a0,lefty:a1,paddle1:b23,paddle2:b24,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-30386438313564306161393537333663,Wii Classic,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
-33333034646336346339646538643633,Wii Classic,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
-30306539356238653637313730656134,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,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,
-30396232393162346330326334636566,Xbox 360,a:b0,b:b1,back:b4,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,
-38313038323730383864666463383533,Xbox 360,a:b0,b:b1,back:b4,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,
-65353331386662343338643939643636,Xbox 360,a:b0,b:b1,back:b4,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,
-65613532386633373963616462363038,Xbox 360,a:b0,b:b1,back:b4,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,
+35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android,
+050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
+30623739343039643830333266346439,Valve Steam 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,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+31643365666432386133346639383937,Valve Steam 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,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+30386438313564306161393537333663,Wii Classic Controller,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+33333034646336346339646538643633,Wii Classic Controller,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
+30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,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,
+38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,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,
+58626f782033363020576972656c6573,Xbox 360 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,
+65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,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,
+65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,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,
+47656e6572696320582d426f78207061,Xbox 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:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d6963726f736f667420582d426f7820,Xbox 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:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,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,
+050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
+050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
+050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,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:b2,y:b3,platform:Android,
33356661323266333733373865656366,Xbox One Controller,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,
+34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,
35623965373264386238353433656138,Xbox One Controller,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,
+36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,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,
+58626f7820576972656c65737320436f,Xbox One 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,
050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
-050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
-050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,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:b2,y:b3,platform:Android,
050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
-050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,
+050000005e040000130b0000ffff3f00,Xbox Series Controller,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,
65633038363832353634653836396239,Xbox Series 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,
-050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
-34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,
-36616131643361333337396261666433,Xbox Wireless Controller,a:b0,b:b1,back:b15,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,
-050000001727000044310000ffff3f00,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
# iOS
05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
@@ -1493,9 +1629,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
-050000005e040000050b0000df070001,Xbox Elite Wireless 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,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
-050000005e040000050b0000ff070001,Xbox Elite Wireless 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,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000005e040000050b0000df070001,Xbox Elite 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,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000005e040000050b0000ff070001,Xbox Elite 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,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000005e040000e0020000df070000,Xbox One 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,
+050000005e040000e0020000ff070000,Xbox One 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,
050000005e040000130b0000df870001,Xbox Series X 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,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000005e040000130b0000ff870001,Xbox Series X 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,
-050000005e040000e0020000df070000,Xbox Wireless 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,
-050000005e040000e0020000ff070000,Xbox Wireless 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 5985b121c9..7f3570729a 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -1,4 +1,4 @@
-# Game Controller DB for Godot in SDL 2.0.10 format
+# Game Controller DB for Godot in SDL 2.0.16 format
# Source: https://github.com/godotengine/godot
# Windows
@@ -31,6 +31,7 @@ MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoul
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
# 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 656bb92203..40cea2cd80 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -72,9 +72,9 @@ Input *Input::singleton = nullptr;
void (*Input::set_mouse_mode_func)(Input::MouseMode) = nullptr;
Input::MouseMode (*Input::get_mouse_mode_func)() = nullptr;
-void (*Input::warp_mouse_func)(const Vector2 &p_to_pos) = nullptr;
+void (*Input::warp_mouse_func)(const Vector2 &p_position) = nullptr;
Input::CursorShape (*Input::get_current_cursor_shape_func)() = nullptr;
-void (*Input::set_custom_mouse_cursor_func)(const RES &, Input::CursorShape, const Vector2 &) = nullptr;
+void (*Input::set_custom_mouse_cursor_func)(const Ref<Resource> &, Input::CursorShape, const Vector2 &) = nullptr;
Input *Input::get_singleton() {
return singleton;
@@ -126,7 +126,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask);
ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
- ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
+ ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Input::warp_mouse);
ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
@@ -733,8 +733,8 @@ MouseButton Input::get_mouse_button_mask() const {
return mouse_button_mask; // do not trust OS implementation, should remove it - OS::get_singleton()->get_mouse_button_state();
}
-void Input::warp_mouse_position(const Vector2 &p_to) {
- warp_mouse_func(p_to);
+void Input::warp_mouse(const Vector2 &p_position) {
+ warp_mouse_func(p_position);
}
Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) {
@@ -756,7 +756,7 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con
const Point2i pos_local = p_motion->get_global_position() - p_rect.position;
const Point2i pos_warped(Math::fposmod(pos_local.x, p_rect.size.x), Math::fposmod(pos_local.y, p_rect.size.y));
if (pos_warped != pos_local) {
- warp_mouse_position(pos_warped + p_rect.position);
+ warp_mouse(pos_warped + p_rect.position);
}
return rel_warped;
@@ -772,6 +772,8 @@ void Input::action_press(const StringName &p_action, float p_strength) {
action.process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = true;
action.strength = p_strength;
+ action.raw_strength = p_strength;
+ action.exact = true;
action_state[p_action] = action;
}
@@ -783,6 +785,8 @@ void Input::action_release(const StringName &p_action) {
action.process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = false;
action.strength = 0.f;
+ action.raw_strength = 0.f;
+ action.exact = true;
action_state[p_action] = action;
}
@@ -846,11 +850,13 @@ Input::CursorShape Input::get_current_cursor_shape() const {
return get_current_cursor_shape_func();
}
-void Input::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+void Input::set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
+ ERR_FAIL_INDEX(p_shape, CursorShape::CURSOR_MAX);
+
set_custom_mouse_cursor_func(p_cursor, p_shape, p_hotspot);
}
@@ -1070,7 +1076,6 @@ void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) {
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
JoyEvent event;
- event.type = TYPE_MAX;
for (int i = 0; i < mapping.bindings.size(); i++) {
const JoyBinding binding = mapping.bindings[i];
@@ -1106,7 +1111,6 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping,
Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value) {
JoyEvent event;
- event.type = TYPE_MAX;
for (int i = 0; i < mapping.bindings.size(); i++) {
const JoyBinding binding = mapping.bindings[i];
@@ -1442,4 +1446,8 @@ Input::Input() {
}
}
+Input::~Input() {
+ singleton = nullptr;
+}
+
//////////////////////////////////////////////////////////
diff --git a/core/input/input.h b/core/input/input.h
index ab2cd377f4..5a7cb84ece 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -113,10 +113,10 @@ private:
int mouse_from_touch_index = -1;
struct VelocityTrack {
- uint64_t last_tick;
+ uint64_t last_tick = 0;
Vector2 velocity;
Vector2 accum;
- float accum_t;
+ float accum_t = 0.0f;
float min_ref_frame;
float max_ref_frame;
@@ -157,9 +157,9 @@ private:
};
struct JoyEvent {
- int type;
- int index; // Can be either JoyAxis or JoyButton.
- float value;
+ int type = TYPE_MAX;
+ int index = -1; // Can be either JoyAxis or JoyButton.
+ float value = 0.f;
};
struct JoyBinding {
@@ -216,10 +216,10 @@ private:
static void (*set_mouse_mode_func)(MouseMode);
static MouseMode (*get_mouse_mode_func)();
- static void (*warp_mouse_func)(const Vector2 &p_to_pos);
+ static void (*warp_mouse_func)(const Vector2 &p_position);
static CursorShape (*get_current_cursor_shape_func)();
- static void (*set_custom_mouse_cursor_func)(const RES &, CursorShape, const Vector2 &);
+ static void (*set_custom_mouse_cursor_func)(const Ref<Resource> &, CursorShape, const Vector2 &);
EventDispatchFunc event_dispatch_function = nullptr;
@@ -273,7 +273,7 @@ public:
Vector2 get_last_mouse_velocity();
MouseButton get_mouse_button_mask() const;
- void warp_mouse_position(const Vector2 &p_to);
+ void warp_mouse(const Vector2 &p_position);
Point2i warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
void parse_input_event(const Ref<InputEvent> &p_event);
@@ -305,7 +305,7 @@ public:
CursorShape get_default_cursor_shape() const;
void set_default_cursor_shape(CursorShape p_shape);
CursorShape get_current_cursor_shape() const;
- void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
+ void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
void parse_mapping(String p_mapping);
void joy_button(int p_device, JoyButton p_button, bool p_pressed);
@@ -331,6 +331,7 @@ public:
void set_event_dispatch_function(EventDispatchFunc p_function);
Input();
+ ~Input();
};
VARIANT_ENUM_CAST(Input::MouseMode);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index ab0f36132f..2d4c203748 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -47,30 +47,30 @@ int InputEvent::get_device() const {
}
bool InputEvent::is_action(const StringName &p_action, bool p_exact_match) const {
- return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match);
+ return InputMap::get_singleton()->event_is_action(Ref<InputEvent>(const_cast<InputEvent *>(this)), p_action, p_exact_match);
}
bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo, bool p_exact_match) const {
bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>(const_cast<InputEvent *>(this)), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && pressed && (p_allow_echo || !is_echo());
}
bool InputEvent::is_action_released(const StringName &p_action, bool p_exact_match) const {
bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>(const_cast<InputEvent *>(this)), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && !pressed;
}
float InputEvent::get_action_strength(const StringName &p_action, bool p_exact_match) const {
float strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, &strength, nullptr);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>(const_cast<InputEvent *>(this)), p_action, p_exact_match, nullptr, &strength, nullptr);
return valid ? strength : 0.0f;
}
float InputEvent::get_action_raw_strength(const StringName &p_action, bool p_exact_match) const {
float raw_strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, nullptr, &raw_strength);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>(const_cast<InputEvent *>(this)), p_action, p_exact_match, nullptr, nullptr, &raw_strength);
return valid ? raw_strength : 0.0f;
}
@@ -83,7 +83,7 @@ bool InputEvent::is_echo() const {
}
Ref<InputEvent> InputEvent::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
- return Ref<InputEvent>((InputEvent *)this);
+ return Ref<InputEvent>(const_cast<InputEvent *>(this));
}
bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const {
@@ -382,7 +382,7 @@ String InputEventKey::to_string() {
}
String mods = InputEventWithModifiers::as_text();
- mods = mods.is_empty() ? TTR("none") : mods;
+ mods = mods.is_empty() ? "none" : mods;
return vformat("InputEventKey: keycode=%s, mods=%s, physical=%s, pressed=%s, echo=%s", kc, mods, physical, p, e);
}
@@ -424,8 +424,13 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool p_exact_ma
} else {
match = get_physical_keycode() == key->get_physical_keycode();
}
+ Key action_mask = get_modifiers_mask();
+ Key key_mask = key->get_modifiers_mask();
+ if (key->is_pressed()) {
+ match &= (action_mask & key_mask) == action_mask;
+ }
if (p_exact_match) {
- match &= get_modifiers_mask() == key->get_modifiers_mask();
+ match &= action_mask == key_mask;
}
if (match) {
bool pressed = key->is_pressed();
@@ -589,8 +594,13 @@ bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool p_
}
bool match = button_index == mb->button_index;
+ Key action_mask = get_modifiers_mask();
+ Key button_mask = mb->get_modifiers_mask();
+ if (mb->is_pressed()) {
+ match &= (action_mask & button_mask) == action_mask;
+ }
if (p_exact_match) {
- match &= get_modifiers_mask() == mb->get_modifiers_mask();
+ match &= action_mask == button_mask;
}
if (match) {
bool pressed = mb->is_pressed();
@@ -680,14 +690,14 @@ String InputEventMouseButton::to_string() {
case MouseButton::WHEEL_RIGHT:
case MouseButton::MB_XBUTTON1:
case MouseButton::MB_XBUTTON2:
- button_string += " (" + RTR(_mouse_button_descriptions[(size_t)idx - 1]) + ")"; // button index starts from 1, array index starts from 0, so subtract 1
+ button_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)idx - 1])); // button index starts from 1, array index starts from 0, so subtract 1
break;
default:
break;
}
String mods = InputEventWithModifiers::as_text();
- mods = mods.is_empty() ? TTR("none") : mods;
+ mods = mods.is_empty() ? "none" : mods;
// Work around the fact vformat can only take 5 substitutions but 6 need to be passed.
String index_and_mods = vformat("button_index=%s, mods=%s", button_index, mods);
@@ -777,19 +787,19 @@ String InputEventMouseMotion::to_string() {
String button_mask_string = itos((int64_t)button_mask);
switch (button_mask) {
case MouseButton::MASK_LEFT:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[(size_t)MouseButton::LEFT - 1]) + ")";
+ button_mask_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)MouseButton::LEFT - 1]));
break;
case MouseButton::MASK_MIDDLE:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[(size_t)MouseButton::MIDDLE - 1]) + ")";
+ button_mask_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)MouseButton::MIDDLE - 1]));
break;
case MouseButton::MASK_RIGHT:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[(size_t)MouseButton::RIGHT - 1]) + ")";
+ button_mask_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)MouseButton::RIGHT - 1]));
break;
case MouseButton::MASK_XBUTTON1:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[(size_t)MouseButton::MB_XBUTTON1 - 1]) + ")";
+ button_mask_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)MouseButton::MB_XBUTTON1 - 1]));
break;
case MouseButton::MASK_XBUTTON2:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[(size_t)MouseButton::MB_XBUTTON2 - 1]) + ")";
+ button_mask_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)MouseButton::MB_XBUTTON2 - 1]));
break;
default:
break;
@@ -951,9 +961,9 @@ static const char *_joy_axis_descriptions[(size_t)JoyAxis::MAX] = {
};
String InputEventJoypadMotion::as_text() const {
- String desc = axis < JoyAxis::MAX ? RTR(_joy_axis_descriptions[(size_t)axis]) : TTR("Unknown Joypad Axis");
+ String desc = axis < JoyAxis::MAX ? TTRGET(_joy_axis_descriptions[(size_t)axis]) : RTR("Unknown Joypad Axis");
- return vformat(TTR("Joypad Motion on Axis %d (%s) with Value %.2f"), axis, desc, axis_value);
+ return vformat(RTR("Joypad Motion on Axis %d (%s) with Value %.2f"), axis, desc, axis_value);
}
String InputEventJoypadMotion::to_string() {
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 41083b4c47..ab94c00999 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -344,7 +344,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_filedialog_refresh", TTRC("Refresh") },
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
- { "", TTRC("")}
+ { "", ""}
/* clang-format on */
};
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index c942b417e4..bc24cac955 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -129,12 +129,9 @@ void ConfigFile::erase_section_key(const String &p_section, const String &p_key)
Error ConfigFile::save(const String &p_path) {
Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
if (err) {
- if (file) {
- memdelete(file);
- }
return err;
}
@@ -143,17 +140,16 @@ Error ConfigFile::save(const String &p_path) {
Error ConfigFile::save_encrypted(const String &p_path, const Vector<uint8_t> &p_key) {
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
if (err) {
return err;
}
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
err = fae->open_and_parse(f, p_key, FileAccessEncrypted::MODE_WRITE_AES256);
if (err) {
- memdelete(fae);
- memdelete(f);
return err;
}
return _internal_save(fae);
@@ -161,24 +157,23 @@ Error ConfigFile::save_encrypted(const String &p_path, const Vector<uint8_t> &p_
Error ConfigFile::save_encrypted_pass(const String &p_path, const String &p_pass) {
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
if (err) {
return err;
}
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
err = fae->open_and_parse_password(f, p_pass, FileAccessEncrypted::MODE_WRITE_AES256);
if (err) {
- memdelete(fae);
- memdelete(f);
return err;
}
return _internal_save(fae);
}
-Error ConfigFile::_internal_save(FileAccess *file) {
+Error ConfigFile::_internal_save(Ref<FileAccess> file) {
for (OrderedHashMap<String, OrderedHashMap<String, Variant>>::Element E = values.front(); E; E = E.next()) {
if (E != values.front()) {
file->store_string("\n");
@@ -194,16 +189,14 @@ Error ConfigFile::_internal_save(FileAccess *file) {
}
}
- memdelete(file);
-
return OK;
}
Error ConfigFile::load(const String &p_path) {
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
+ if (f.is_null()) {
return err;
}
@@ -212,17 +205,16 @@ Error ConfigFile::load(const String &p_path) {
Error ConfigFile::load_encrypted(const String &p_path, const Vector<uint8_t> &p_key) {
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
return err;
}
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
err = fae->open_and_parse(f, p_key, FileAccessEncrypted::MODE_READ);
if (err) {
- memdelete(fae);
- memdelete(f);
return err;
}
return _internal_load(p_path, fae);
@@ -230,31 +222,28 @@ Error ConfigFile::load_encrypted(const String &p_path, const Vector<uint8_t> &p_
Error ConfigFile::load_encrypted_pass(const String &p_path, const String &p_pass) {
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
return err;
}
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
err = fae->open_and_parse_password(f, p_pass, FileAccessEncrypted::MODE_READ);
if (err) {
- memdelete(fae);
- memdelete(f);
return err;
}
return _internal_load(p_path, fae);
}
-Error ConfigFile::_internal_load(const String &p_path, FileAccess *f) {
+Error ConfigFile::_internal_load(const String &p_path, Ref<FileAccess> f) {
VariantParser::StreamFile stream;
stream.f = f;
Error err = _parse(p_path, &stream);
- memdelete(f);
-
return err;
}
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 71e9080fb7..7a52b0e16a 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -43,8 +43,8 @@ class ConfigFile : public RefCounted {
PackedStringArray _get_sections() const;
PackedStringArray _get_section_keys(const String &p_section) const;
- Error _internal_load(const String &p_path, FileAccess *f);
- Error _internal_save(FileAccess *file);
+ Error _internal_load(const String &p_path, Ref<FileAccess> f);
+ Error _internal_save(Ref<FileAccess> file);
Error _parse(const String &p_path, VariantParser::Stream *p_stream);
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index 86d8dea3d9..433a7efb21 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -217,8 +217,8 @@ String DirAccess::fix_path(String p_path) const {
DirAccess::CreateFunc DirAccess::create_func[ACCESS_MAX] = { nullptr, nullptr, nullptr };
-DirAccess *DirAccess::create_for_path(const String &p_path) {
- DirAccess *da = nullptr;
+Ref<DirAccess> DirAccess::create_for_path(const String &p_path) {
+ Ref<DirAccess> da;
if (p_path.begins_with("res://")) {
da = create(ACCESS_RESOURCES);
} else if (p_path.begins_with("user://")) {
@@ -230,80 +230,77 @@ DirAccess *DirAccess::create_for_path(const String &p_path) {
return da;
}
-DirAccess *DirAccess::open(const String &p_path, Error *r_error) {
- DirAccess *da = create_for_path(p_path);
-
- ERR_FAIL_COND_V_MSG(!da, nullptr, "Cannot create DirAccess for path '" + p_path + "'.");
+Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
+ Ref<DirAccess> da = create_for_path(p_path);
+ ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, "Cannot create DirAccess for path '" + p_path + "'.");
Error err = da->change_dir(p_path);
if (r_error) {
*r_error = err;
}
if (err != OK) {
- memdelete(da);
return nullptr;
}
return da;
}
-DirAccess *DirAccess::create(AccessType p_access) {
- DirAccess *da = create_func[p_access] ? create_func[p_access]() : nullptr;
- if (da) {
+Ref<DirAccess> DirAccess::create(AccessType p_access) {
+ Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr;
+ if (da.is_valid()) {
da->_access_type = p_access;
+
+ // for ACCESS_RESOURCES and ACCESS_FILESYSTEM, current_dir already defaults to where game was started
+ // in case current directory is force changed elsewhere for ACCESS_RESOURCES
+ if (p_access == ACCESS_RESOURCES) {
+ da->change_dir("res://");
+ } else if (p_access == ACCESS_USERDATA) {
+ da->change_dir("user://");
+ }
}
return da;
}
String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
- DirAccess *d = DirAccess::create(p_access);
- if (!d) {
+ Ref<DirAccess> d = DirAccess::create(p_access);
+ if (d.is_null()) {
return p_path;
}
d->change_dir(p_path);
String full = d->get_current_dir();
- memdelete(d);
return full;
}
Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
//printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data());
Error err;
- FileAccess *fsrc = FileAccess::open(p_from, FileAccess::READ, &err);
-
- if (err) {
- ERR_PRINT("Failed to open " + p_from);
- return err;
- }
-
- FileAccess *fdst = FileAccess::open(p_to, FileAccess::WRITE, &err);
- if (err) {
- fsrc->close();
- memdelete(fsrc);
- ERR_PRINT("Failed to open " + p_to);
- return err;
- }
+ {
+ Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from);
+
+ Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to);
+
+ fsrc->seek_end(0);
+ int size = fsrc->get_position();
+ fsrc->seek(0);
+ err = OK;
+ while (size--) {
+ if (fsrc->get_error() != OK) {
+ err = fsrc->get_error();
+ break;
+ }
+ if (fdst->get_error() != OK) {
+ err = fdst->get_error();
+ break;
+ }
- fsrc->seek_end(0);
- int size = fsrc->get_position();
- fsrc->seek(0);
- err = OK;
- while (size--) {
- if (fsrc->get_error() != OK) {
- err = fsrc->get_error();
- break;
+ fdst->store_8(fsrc->get_8());
}
- if (fdst->get_error() != OK) {
- err = fdst->get_error();
- break;
- }
-
- fdst->store_8(fsrc->get_8());
}
if (err == OK && p_chmod_flags != -1) {
- fdst->close();
err = FileAccess::set_unix_permissions(p_to, p_chmod_flags);
// If running on a platform with no chmod support (i.e., Windows), don't fail
if (err == ERR_UNAVAILABLE) {
@@ -311,9 +308,6 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
}
}
- memdelete(fsrc);
- memdelete(fdst);
-
return err;
}
@@ -335,7 +329,7 @@ public:
}
};
-Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) {
+Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) {
List<String> dirs;
String curdir = get_current_dir();
@@ -391,14 +385,11 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) {
ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist.");
- DirAccess *target_da = DirAccess::create_for_path(p_to);
- ERR_FAIL_COND_V_MSG(!target_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'.");
+ Ref<DirAccess> target_da = DirAccess::create_for_path(p_to);
+ ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'.");
if (!target_da->dir_exists(p_to)) {
Error err = target_da->make_dir_recursive(p_to);
- if (err) {
- memdelete(target_da);
- }
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + p_to + "'.");
}
@@ -408,14 +399,11 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_
DirChanger dir_changer(this, p_from);
Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links);
- memdelete(target_da);
return err;
}
bool DirAccess::exists(String p_dir) {
- DirAccess *da = DirAccess::create_for_path(p_dir);
- bool valid = da->change_dir(p_dir) == OK;
- memdelete(da);
- return valid;
+ Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
+ return da->change_dir(p_dir) == OK;
}
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index 8154f5366c..0125f011b5 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -31,11 +31,12 @@
#ifndef DIR_ACCESS_H
#define DIR_ACCESS_H
+#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
-class DirAccess {
+class DirAccess : public RefCounted {
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -44,13 +45,13 @@ public:
ACCESS_MAX
};
- typedef DirAccess *(*CreateFunc)();
+ typedef Ref<DirAccess> (*CreateFunc)();
private:
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object
- Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
+ Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
protected:
String _get_root_path() const;
@@ -59,7 +60,7 @@ protected:
String fix_path(String p_path) const;
template <class T>
- static DirAccess *_create_builtin() {
+ static Ref<DirAccess> _create_builtin() {
return memnew(T);
}
@@ -77,7 +78,7 @@ public:
virtual bool drives_are_shortcuts();
virtual Error change_dir(String p_dir) = 0; ///< can be relative or absolute, return false on success
- virtual String get_current_dir(bool p_include_drive = true) = 0; ///< return current dir location
+ virtual String get_current_dir(bool p_include_drive = true) const = 0; ///< return current dir location
virtual Error make_dir(String p_dir) = 0;
virtual Error make_dir_recursive(String p_dir);
virtual Error erase_contents_recursive(); //super dangerous, use with care!
@@ -101,47 +102,29 @@ public:
// Meant for editor code when we want to quickly remove a file without custom
// handling (e.g. removing a cache file).
static void remove_file_or_error(String p_path) {
- DirAccess *da = create(ACCESS_FILESYSTEM);
+ Ref<DirAccess> da = create(ACCESS_FILESYSTEM);
if (da->file_exists(p_path)) {
if (da->remove(p_path) != OK) {
ERR_FAIL_MSG("Cannot remove file or directory: " + p_path);
}
}
- memdelete(da);
}
virtual String get_filesystem_type() const = 0;
static String get_full_path(const String &p_path, AccessType p_access);
- static DirAccess *create_for_path(const String &p_path);
+ static Ref<DirAccess> create_for_path(const String &p_path);
- static DirAccess *create(AccessType p_access);
+ static Ref<DirAccess> create(AccessType p_access);
template <class T>
static void make_default(AccessType p_access) {
create_func[p_access] = _create_builtin<T>;
}
- static DirAccess *open(const String &p_path, Error *r_error = nullptr);
+ static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
DirAccess() {}
virtual ~DirAccess() {}
};
-struct DirAccessRef {
- _FORCE_INLINE_ DirAccess *operator->() {
- return f;
- }
-
- operator bool() const { return f != nullptr; }
-
- DirAccess *f;
-
- DirAccessRef(DirAccess *fa) { f = fa; }
- ~DirAccessRef() {
- if (f) {
- memdelete(f);
- }
- }
-};
-
#endif // DIR_ACCESS_H
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 86836454c5..7d8da1b11c 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -42,10 +42,10 @@ FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr;
bool FileAccess::backup_save = false;
-FileAccess *FileAccess::create(AccessType p_access) {
+Ref<FileAccess> FileAccess::create(AccessType p_access) {
ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
- FileAccess *ret = create_func[p_access]();
+ Ref<FileAccess> ret = create_func[p_access]();
ret->_set_access_type(p_access);
return ret;
}
@@ -55,11 +55,10 @@ bool FileAccess::exists(const String &p_name) {
return true;
}
- FileAccess *f = open(p_name, READ);
- if (!f) {
+ Ref<FileAccess> f = open(p_name, READ);
+ if (f.is_null()) {
return false;
}
- memdelete(f);
return true;
}
@@ -67,8 +66,8 @@ void FileAccess::_set_access_type(AccessType p_access) {
_access_type = p_access;
}
-FileAccess *FileAccess::create_for_path(const String &p_path) {
- FileAccess *ret = nullptr;
+Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
+ Ref<FileAccess> ret;
if (p_path.begins_with("res://")) {
ret = create(ACCESS_RESOURCES);
} else if (p_path.begins_with("user://")) {
@@ -85,13 +84,13 @@ Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
return _open(p_path, p_mode_flags);
}
-FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) {
+Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) {
//try packed data first
- FileAccess *ret = nullptr;
+ Ref<FileAccess> ret;
if (!(p_mode_flags & WRITE) && PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled()) {
ret = PackedData::get_singleton()->try_open_path(p_path);
- if (ret) {
+ if (ret.is_valid()) {
if (r_error) {
*r_error = OK;
}
@@ -106,8 +105,7 @@ FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_er
*r_error = err;
}
if (err != OK) {
- memdelete(ret);
- ret = nullptr;
+ ret.unref();
}
return ret;
@@ -463,11 +461,10 @@ uint64_t FileAccess::get_modified_time(const String &p_file) {
return 0;
}
- FileAccess *fa = create_for_path(p_file);
- ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'.");
+ Ref<FileAccess> fa = create_for_path(p_file);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'.");
uint64_t mt = fa->_get_modified_time(p_file);
- memdelete(fa);
return mt;
}
@@ -476,11 +473,10 @@ uint32_t FileAccess::get_unix_permissions(const String &p_file) {
return 0;
}
- FileAccess *fa = create_for_path(p_file);
- ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'.");
+ Ref<FileAccess> fa = create_for_path(p_file);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'.");
uint32_t mt = fa->_get_unix_permissions(p_file);
- memdelete(fa);
return mt;
}
@@ -489,11 +485,10 @@ Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissi
return ERR_UNAVAILABLE;
}
- FileAccess *fa = create_for_path(p_file);
- ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
+ Ref<FileAccess> fa = create_for_path(p_file);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
Error err = fa->_set_unix_permissions(p_file, p_permissions);
- memdelete(fa);
return err;
}
@@ -559,8 +554,8 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) {
- FileAccess *f = FileAccess::open(p_path, READ, r_error);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error);
+ if (f.is_null()) {
if (r_error) { // if error requested, do not throw error
return Vector<uint8_t>();
}
@@ -569,7 +564,6 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err
Vector<uint8_t> data;
data.resize(f->get_length());
f->get_buffer(data.ptrw(), data.size());
- memdelete(f);
return data;
}
@@ -592,8 +586,8 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) {
}
String FileAccess::get_md5(const String &p_file) {
- FileAccess *f = FileAccess::open(p_file, READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_file, READ);
+ if (f.is_null()) {
return String();
}
@@ -615,8 +609,6 @@ String FileAccess::get_md5(const String &p_file) {
unsigned char hash[16];
ctx.finish(hash);
- memdelete(f);
-
return String::md5(hash);
}
@@ -625,8 +617,8 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) {
ctx.start();
for (int i = 0; i < p_file.size(); i++) {
- FileAccess *f = FileAccess::open(p_file[i], READ);
- ERR_CONTINUE(!f);
+ Ref<FileAccess> f = FileAccess::open(p_file[i], READ);
+ ERR_CONTINUE(f.is_null());
unsigned char step[32768];
@@ -639,7 +631,6 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) {
break;
}
}
- memdelete(f);
}
unsigned char hash[16];
@@ -649,8 +640,8 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) {
}
String FileAccess::get_sha256(const String &p_file) {
- FileAccess *f = FileAccess::open(p_file, READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_file, READ);
+ if (f.is_null()) {
return String();
}
@@ -672,6 +663,5 @@ String FileAccess::get_sha256(const String &p_file) {
unsigned char hash[32];
ctx.finish(hash);
- memdelete(f);
return String::hex_encode_buffer(hash, 32);
}
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 5413665440..e2c11142d7 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -32,6 +32,7 @@
#define FILE_ACCESS_H
#include "core/math/math_defs.h"
+#include "core/object/ref_counted.h"
#include "core/os/memory.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
@@ -40,7 +41,7 @@
* Multi-Platform abstraction for accessing to files.
*/
-class FileAccess {
+class FileAccess : public RefCounted {
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -51,7 +52,7 @@ public:
typedef void (*FileCloseFailNotify)(const String &);
- typedef FileAccess *(*CreateFunc)();
+ typedef Ref<FileAccess> (*CreateFunc)();
bool big_endian = false;
bool real_is_double = false;
@@ -71,7 +72,7 @@ private:
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */
template <class T>
- static FileAccess *_create_builtin() {
+ static Ref<FileAccess> _create_builtin() {
return memnew(T);
}
@@ -87,7 +88,6 @@ public:
WRITE_READ = 7,
};
- virtual void close() = 0; ///< close a file
virtual bool is_open() const = 0; ///< true when file is open
virtual String get_path() const { return ""; } /// returns the path for the current open file
@@ -148,9 +148,9 @@ public:
virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType
- static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
- static FileAccess *create_for_path(const String &p_path);
- static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
+ static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
+ static Ref<FileAccess> create_for_path(const String &p_path);
+ static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file);
@@ -176,23 +176,4 @@ public:
virtual ~FileAccess() {}
};
-struct FileAccessRef {
- _FORCE_INLINE_ FileAccess *operator->() {
- return f;
- }
-
- operator bool() const { return f != nullptr; }
-
- FileAccess *f;
-
- operator FileAccess *() { return f; }
-
- FileAccessRef(FileAccess *fa) { f = fa; }
- ~FileAccessRef() {
- if (f) {
- memdelete(f);
- }
- }
-};
-
#endif // FILE_ACCESS_H
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 526952b14f..1d0a718166 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -58,12 +58,12 @@ void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_
} \
}
-Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
+Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
f = p_base;
cmode = (Compression::Mode)f->get_32();
block_size = f->get_32();
if (block_size == 0) {
- f = nullptr; // Let the caller to handle the FileAccess object if failed to open as compressed file.
+ f.unref();
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted.");
}
read_total = f->get_32();
@@ -88,26 +88,22 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
read_block_count = bc;
read_block_size = read_blocks.size() == 1 ? read_total : block_size;
- Compression::decompress(buffer.ptrw(), read_block_size, comp_buffer.ptr(), read_blocks[0].csize, cmode);
+ int ret = Compression::decompress(buffer.ptrw(), read_block_size, comp_buffer.ptr(), read_blocks[0].csize, cmode);
read_block = 0;
read_pos = 0;
- return OK;
+ return ret == -1 ? ERR_FILE_CORRUPT : OK;
}
Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE);
-
- if (f) {
- close();
- }
+ _close();
Error err;
f = FileAccess::open(p_path, p_mode_flags, &err);
if (err != OK) {
//not openable
-
- f = nullptr;
+ f.unref();
return err;
}
@@ -125,18 +121,18 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
char rmagic[5];
f->get_buffer((uint8_t *)rmagic, 4);
rmagic[4] = 0;
- if (magic != rmagic || open_after_magic(f) != OK) {
- memdelete(f);
- f = nullptr;
- return ERR_FILE_UNRECOGNIZED;
+ err = ERR_FILE_UNRECOGNIZED;
+ if (magic != rmagic || (err = open_after_magic(f)) != OK) {
+ f.unref();
+ return err;
}
}
return OK;
}
-void FileAccessCompressed::close() {
- if (!f) {
+void FileAccessCompressed::_close() {
+ if (f.is_null()) {
return;
}
@@ -181,17 +177,15 @@ void FileAccessCompressed::close() {
buffer.clear();
read_blocks.clear();
}
-
- memdelete(f);
- f = nullptr;
+ f.unref();
}
bool FileAccessCompressed::is_open() const {
- return f != nullptr;
+ return f.is_valid();
}
void FileAccessCompressed::seek(uint64_t p_position) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
if (writing) {
ERR_FAIL_COND(p_position > write_max);
@@ -210,7 +204,8 @@ void FileAccessCompressed::seek(uint64_t p_position) {
read_block = block_idx;
f->seek(read_blocks[read_block].offset);
f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize);
- Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
+ int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
+ ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");
read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size;
}
@@ -220,7 +215,7 @@ void FileAccessCompressed::seek(uint64_t p_position) {
}
void FileAccessCompressed::seek_end(int64_t p_position) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
if (writing) {
seek(write_max + p_position);
} else {
@@ -229,7 +224,7 @@ void FileAccessCompressed::seek_end(int64_t p_position) {
}
uint64_t FileAccessCompressed::get_position() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use.");
if (writing) {
return write_pos;
} else {
@@ -238,7 +233,7 @@ uint64_t FileAccessCompressed::get_position() const {
}
uint64_t FileAccessCompressed::get_length() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use.");
if (writing) {
return write_max;
} else {
@@ -247,7 +242,7 @@ uint64_t FileAccessCompressed::get_length() const {
}
bool FileAccessCompressed::eof_reached() const {
- ERR_FAIL_COND_V_MSG(!f, false, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use.");
if (writing) {
return false;
} else {
@@ -256,7 +251,7 @@ bool FileAccessCompressed::eof_reached() const {
}
uint8_t FileAccessCompressed::get_8() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use.");
ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
if (at_end) {
@@ -273,7 +268,8 @@ uint8_t FileAccessCompressed::get_8() const {
if (read_block < read_block_count) {
//read another block of compressed data
f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize);
- Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
+ int total = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
+ ERR_FAIL_COND_V_MSG(total == -1, 0, "Compressed file is corrupt.");
read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size;
read_pos = 0;
@@ -288,7 +284,7 @@ uint8_t FileAccessCompressed::get_8() const {
uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
if (at_end) {
@@ -305,7 +301,8 @@ uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) con
if (read_block < read_block_count) {
//read another block of compressed data
f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize);
- Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
+ int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode);
+ ERR_FAIL_COND_V_MSG(ret == -1, -1, "Compressed file is corrupt.");
read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size;
read_pos = 0;
@@ -328,14 +325,14 @@ Error FileAccessCompressed::get_error() const {
}
void FileAccessCompressed::flush() {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
// compressed files keep data in memory till close()
}
void FileAccessCompressed::store_8(uint8_t p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
WRITE_FIT(1);
@@ -343,16 +340,15 @@ void FileAccessCompressed::store_8(uint8_t p_dest) {
}
bool FileAccessCompressed::file_exists(const String &p_name) {
- FileAccess *fa = FileAccess::open(p_name, FileAccess::READ);
- if (!fa) {
+ Ref<FileAccess> fa = FileAccess::open(p_name, FileAccess::READ);
+ if (fa.is_null()) {
return false;
}
- memdelete(fa);
return true;
}
uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) {
- if (f) {
+ if (f.is_valid()) {
return f->get_modified_time(p_file);
} else {
return 0;
@@ -360,21 +356,19 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) {
}
uint32_t FileAccessCompressed::_get_unix_permissions(const String &p_file) {
- if (f) {
+ if (f.is_valid()) {
return f->_get_unix_permissions(p_file);
}
return 0;
}
Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
- if (f) {
+ if (f.is_valid()) {
return f->_set_unix_permissions(p_file, p_permissions);
}
return FAILED;
}
FileAccessCompressed::~FileAccessCompressed() {
- if (f) {
- close();
- }
+ _close();
}
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index 97ef3fbdeb..b8382e61d9 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -61,15 +61,16 @@ class FileAccessCompressed : public FileAccess {
String magic = "GCMP";
mutable Vector<uint8_t> buffer;
- FileAccess *f = nullptr;
+ Ref<FileAccess> f;
+
+ void _close();
public:
void configure(const String &p_magic, Compression::Mode p_mode = Compression::MODE_ZSTD, uint32_t p_block_size = 4096);
- Error open_after_magic(FileAccess *p_base);
+ Error open_after_magic(Ref<FileAccess> p_base);
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 8ee19d3d06..d1b014a0be 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -36,7 +36,7 @@
#include <stdio.h>
-Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) {
+Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) {
ERR_FAIL_COND_V_MSG(file != nullptr, ERR_ALREADY_IN_USE, "Can't open file while another file from path '" + file->get_path_absolute() + "' is open.");
ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
@@ -99,7 +99,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8
return OK;
}
-Error FileAccessEncrypted::open_and_parse_password(FileAccess *p_base, const String &p_key, Mode p_mode) {
+Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode) {
String cs = p_key.md5_text();
ERR_FAIL_COND_V(cs.length() != 32, ERR_INVALID_PARAMETER);
Vector<uint8_t> key;
@@ -115,30 +115,11 @@ Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessEncrypted::close() {
- if (!file) {
+void FileAccessEncrypted::_close() {
+ if (file.is_null()) {
return;
}
- _release();
-
- file->close();
- memdelete(file);
-
- file = nullptr;
-}
-
-void FileAccessEncrypted::release() {
- if (!file) {
- return;
- }
-
- _release();
-
- file = nullptr;
-}
-
-void FileAccessEncrypted::_release() {
if (writing) {
Vector<uint8_t> compressed;
uint64_t len = data.size();
@@ -176,6 +157,8 @@ void FileAccessEncrypted::_release() {
file->store_buffer(compressed.ptr(), compressed.size());
data.clear();
}
+
+ file.unref();
}
bool FileAccessEncrypted::is_open() const {
@@ -183,7 +166,7 @@ bool FileAccessEncrypted::is_open() const {
}
String FileAccessEncrypted::get_path() const {
- if (file) {
+ if (file.is_valid()) {
return file->get_path();
} else {
return "";
@@ -191,7 +174,7 @@ String FileAccessEncrypted::get_path() const {
}
String FileAccessEncrypted::get_path_absolute() const {
- if (file) {
+ if (file.is_valid()) {
return file->get_path_absolute();
} else {
return "";
@@ -291,11 +274,10 @@ void FileAccessEncrypted::store_8(uint8_t p_dest) {
}
bool FileAccessEncrypted::file_exists(const String &p_name) {
- FileAccess *fa = FileAccess::open(p_name, FileAccess::READ);
- if (!fa) {
+ Ref<FileAccess> fa = FileAccess::open(p_name, FileAccess::READ);
+ if (fa.is_null()) {
return false;
}
- memdelete(fa);
return true;
}
@@ -313,7 +295,5 @@ Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t
}
FileAccessEncrypted::~FileAccessEncrypted() {
- if (file) {
- close();
- }
+ _close();
}
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index be5904c894..0d1ee6a4d8 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -46,7 +46,7 @@ public:
private:
Vector<uint8_t> key;
bool writing = false;
- FileAccess *file = nullptr;
+ Ref<FileAccess> file;
uint64_t base = 0;
uint64_t length = 0;
Vector<uint8_t> data;
@@ -54,15 +54,13 @@ private:
mutable bool eofed = false;
bool use_magic = true;
- void _release();
+ void _close();
public:
- Error open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
- Error open_and_parse_password(FileAccess *p_base, const String &p_key, Mode p_mode);
+ Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
+ Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
- virtual void release(); ///< finish and keep base file open
virtual bool is_open() const; ///< true when file is open
virtual String get_path() const; /// returns the path for the current open file
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 4aca26b007..943dc72307 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -60,7 +60,7 @@ void FileAccessMemory::cleanup() {
memdelete(files);
}
-FileAccess *FileAccessMemory::create() {
+Ref<FileAccess> FileAccessMemory::create() {
return memnew(FileAccessMemory);
}
@@ -94,10 +94,6 @@ Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessMemory::close() {
- data = nullptr;
-}
-
bool FileAccessMemory::is_open() const {
return data != nullptr;
}
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 50b23e1f32..868b8ed481 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -38,7 +38,7 @@ class FileAccessMemory : public FileAccess {
uint64_t length = 0;
mutable uint64_t pos = 0;
- static FileAccess *create();
+ static Ref<FileAccess> create();
public:
static void register_file(String p_name, Vector<uint8_t> p_data);
@@ -46,7 +46,6 @@ public:
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index cb38ac0928..1365b4b593 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -165,7 +165,7 @@ void FileAccessNetworkClient::_thread_func() {
}
void FileAccessNetworkClient::_thread_func(void *s) {
- FileAccessNetworkClient *self = (FileAccessNetworkClient *)s;
+ FileAccessNetworkClient *self = static_cast<FileAccessNetworkClient *>(s);
self->_thread_func();
}
@@ -254,9 +254,8 @@ void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) {
Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE);
- if (opened) {
- close();
- }
+ _close();
+
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
DEBUG_PRINT("open: " + p_path);
@@ -287,7 +286,7 @@ Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
return response;
}
-void FileAccessNetwork::close() {
+void FileAccessNetwork::_close() {
if (!opened) {
return;
}
@@ -483,7 +482,7 @@ FileAccessNetwork::FileAccessNetwork() {
}
FileAccessNetwork::~FileAccessNetwork() {
- close();
+ _close();
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
nc->lock_mutex();
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index 6cae49b540..214d391c95 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -86,15 +86,15 @@ class FileAccessNetwork : public FileAccess {
Semaphore page_sem;
Mutex buffer_mutex;
bool opened = false;
- uint64_t total_size;
+ uint64_t total_size = 0;
mutable uint64_t pos = 0;
- int32_t id;
+ int32_t id = -1;
mutable bool eof_flag = false;
mutable int32_t last_page = -1;
mutable uint8_t *last_page_buff = nullptr;
- int32_t page_size;
- int32_t read_ahead;
+ int32_t page_size = 0;
+ int32_t read_ahead = 0;
mutable int waiting_on_page = -1;
@@ -108,11 +108,13 @@ class FileAccessNetwork : public FileAccess {
mutable Error response;
- uint64_t exists_modtime;
+ uint64_t exists_modtime = 0;
+
friend class FileAccessNetworkClient;
void _queue_page(int32_t p_page) const;
void _respond(uint64_t p_len, Error p_status);
void _set_block(uint64_t p_offset, const Vector<uint8_t> &p_block);
+ void _close();
public:
enum Command {
@@ -131,7 +133,6 @@ public:
};
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 7dbea96c3d..ba120de68b 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -32,6 +32,7 @@
#include "core/io/file_access_encrypted.h"
#include "core/object/script_language.h"
+#include "core/os/os.h"
#include "core/version.h"
#include <stdio.h>
@@ -126,60 +127,81 @@ PackedData::~PackedData() {
//////////////////////////////////////////////////////////////////
bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
return false;
}
- f->seek(p_offset);
+ bool pck_header_found = false;
+ // Search for the header at the start offset - standalone PCK file.
+ f->seek(p_offset);
uint32_t magic = f->get_32();
+ if (magic == PACK_HEADER_MAGIC) {
+ pck_header_found = true;
+ }
- if (magic != PACK_HEADER_MAGIC) {
- // loading with offset feature not supported for self contained exe files
+ // Search for the header in the executable "pck" section - self contained executable.
+ if (!pck_header_found) {
+ // Loading with offset feature not supported for self contained exe files.
if (p_offset != 0) {
- f->close();
- memdelete(f);
ERR_FAIL_V_MSG(false, "Loading self-contained executable with offset not supported.");
}
- //maybe at the end.... self contained exe
- f->seek_end();
- f->seek(f->get_position() - 4);
- magic = f->get_32();
- if (magic != PACK_HEADER_MAGIC) {
- f->close();
- memdelete(f);
- return false;
+ int64_t pck_off = OS::get_singleton()->get_embedded_pck_offset();
+ if (pck_off != 0) {
+ // Search for the header, in case PCK start and section have different alignment.
+ for (int i = 0; i < 8; i++) {
+ f->seek(pck_off);
+ magic = f->get_32();
+ if (magic == PACK_HEADER_MAGIC) {
+#ifdef DEBUG_ENABLED
+ print_verbose("PCK header found in executable pck section, loading from offset 0x" + String::num_int64(pck_off - 4, 16));
+#endif
+ pck_header_found = true;
+ break;
+ }
+ pck_off++;
+ }
}
- f->seek(f->get_position() - 12);
+ }
- uint64_t ds = f->get_64();
- f->seek(f->get_position() - ds - 8);
+ // Search for the header at the end of file - self contained executable.
+ if (!pck_header_found) {
+ // Loading with offset feature not supported for self contained exe files.
+ if (p_offset != 0) {
+ ERR_FAIL_V_MSG(false, "Loading self-contained executable with offset not supported.");
+ }
+ f->seek_end();
+ f->seek(f->get_position() - 4);
magic = f->get_32();
- if (magic != PACK_HEADER_MAGIC) {
- f->close();
- memdelete(f);
- return false;
+
+ if (magic == PACK_HEADER_MAGIC) {
+ f->seek(f->get_position() - 12);
+ uint64_t ds = f->get_64();
+ f->seek(f->get_position() - ds - 8);
+ magic = f->get_32();
+ if (magic == PACK_HEADER_MAGIC) {
+#ifdef DEBUG_ENABLED
+ print_verbose("PCK header found at the end of executable, loading from offset 0x" + String::num_int64(f->get_position() - 4, 16));
+#endif
+ pck_header_found = true;
+ }
}
}
+ if (!pck_header_found) {
+ return false;
+ }
+
uint32_t version = f->get_32();
uint32_t ver_major = f->get_32();
uint32_t ver_minor = f->get_32();
f->get_32(); // patch number, not used for validation.
- if (version != PACK_FORMAT_VERSION) {
- f->close();
- memdelete(f);
- ERR_FAIL_V_MSG(false, "Pack version unsupported: " + itos(version) + ".");
- }
- if (ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR)) {
- f->close();
- memdelete(f);
- ERR_FAIL_V_MSG(false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + ".");
- }
+ ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, "Pack version unsupported: " + itos(version) + ".");
+ ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + ".");
uint32_t pack_flags = f->get_32();
uint64_t file_base = f->get_64();
@@ -194,12 +216,9 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
int file_count = f->get_32();
if (enc_directory) {
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
- if (!fae) {
- f->close();
- memdelete(f);
- ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory.");
- }
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ ERR_FAIL_COND_V_MSG(fae.is_null(), false, "Can't open encrypted pack directory.");
Vector<uint8_t> key;
key.resize(32);
@@ -208,12 +227,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
}
Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
- if (err) {
- f->close();
- memdelete(f);
- memdelete(fae);
- ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory.");
- }
+ ERR_FAIL_COND_V_MSG(err, false, "Can't open encrypted pack directory.");
f = fae;
}
@@ -236,12 +250,10 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
PackedData::get_singleton()->add_path(p_path, path, ofs + p_offset, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED));
}
- f->close();
- memdelete(f);
return true;
}
-FileAccess *PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) {
+Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) {
return memnew(FileAccessPack(p_path, *p_file));
}
@@ -252,15 +264,17 @@ Error FileAccessPack::_open(const String &p_path, int p_mode_flags) {
return ERR_UNAVAILABLE;
}
-void FileAccessPack::close() {
- f->close();
-}
-
bool FileAccessPack::is_open() const {
- return f->is_open();
+ if (f.is_valid()) {
+ return f->is_open();
+ } else {
+ return false;
+ }
}
void FileAccessPack::seek(uint64_t p_position) {
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
+
if (p_position > pf.size) {
eof = true;
} else {
@@ -288,6 +302,7 @@ bool FileAccessPack::eof_reached() const {
}
uint8_t FileAccessPack::get_8() const {
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use.");
if (pos >= pf.size) {
eof = true;
return 0;
@@ -298,6 +313,7 @@ uint8_t FileAccessPack::get_8() const {
}
uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
+ ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
if (eof) {
@@ -321,6 +337,8 @@ uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
}
void FileAccessPack::set_big_endian(bool p_big_endian) {
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
+
FileAccess::set_big_endian(p_big_endian);
f->set_big_endian(p_big_endian);
}
@@ -351,16 +369,15 @@ bool FileAccessPack::file_exists(const String &p_name) {
FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) :
pf(p_file),
f(FileAccess::open(pf.pack, FileAccess::READ)) {
- ERR_FAIL_COND_MSG(!f, "Can't open pack-referenced file '" + String(pf.pack) + "'.");
+ ERR_FAIL_COND_MSG(f.is_null(), "Can't open pack-referenced file '" + String(pf.pack) + "'.");
f->seek(pf.offset);
off = pf.offset;
if (pf.encrypted) {
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
- if (!fae) {
- ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
- }
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ ERR_FAIL_COND_MSG(fae.is_null(), "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
Vector<uint8_t> key;
key.resize(32);
@@ -369,10 +386,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
}
Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
- if (err) {
- memdelete(fae);
- ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
- }
+ ERR_FAIL_COND_MSG(err, "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
f = fae;
off = 0;
}
@@ -380,13 +394,6 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
eof = false;
}
-FileAccessPack::~FileAccessPack() {
- if (f) {
- f->close();
- memdelete(f);
- }
-}
-
//////////////////////////////////////////////////////////////////////////////////
// DIR ACCESS
//////////////////////////////////////////////////////////////////////////////////
@@ -507,7 +514,7 @@ Error DirAccessPack::change_dir(String p_dir) {
}
}
-String DirAccessPack::get_current_dir(bool p_include_drive) {
+String DirAccessPack::get_current_dir(bool p_include_drive) const {
PackedData::PackedDir *pd = current;
String p = current->name;
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 6eee2f593d..17e87c835a 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -64,7 +64,7 @@ public:
uint64_t offset; //if offset is ZERO, the file was ERASED
uint64_t size;
uint8_t md5[16];
- PackSource *src;
+ PackSource *src = nullptr;
bool encrypted;
};
@@ -93,7 +93,7 @@ private:
PathMD5() {}
- PathMD5(const Vector<uint8_t> &p_buf) {
+ explicit PathMD5(const Vector<uint8_t> &p_buf) {
a = *((uint64_t *)&p_buf[0]);
b = *((uint64_t *)&p_buf[8]);
}
@@ -103,7 +103,7 @@ private:
Vector<PackSource *> sources;
- PackedDir *root;
+ PackedDir *root = nullptr;
static PackedData *singleton;
bool disabled = false;
@@ -120,10 +120,10 @@ public:
static PackedData *get_singleton() { return singleton; }
Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
- _FORCE_INLINE_ FileAccess *try_open_path(const String &p_path);
+ _FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
_FORCE_INLINE_ bool has_path(const String &p_path);
- _FORCE_INLINE_ DirAccess *try_open_directory(const String &p_path);
+ _FORCE_INLINE_ Ref<DirAccess> try_open_directory(const String &p_path);
_FORCE_INLINE_ bool has_directory(const String &p_path);
PackedData();
@@ -133,14 +133,14 @@ public:
class PackSource {
public:
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) = 0;
- virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) = 0;
+ virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) = 0;
virtual ~PackSource() {}
};
class PackedSourcePCK : public PackSource {
public:
- virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
- virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
+ virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
};
class FileAccessPack : public FileAccess {
@@ -150,14 +150,13 @@ class FileAccessPack : public FileAccess {
mutable bool eof;
uint64_t off;
- FileAccess *f;
+ Ref<FileAccess> f;
virtual Error _open(const String &p_path, int p_mode_flags);
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
public:
- virtual void close();
virtual bool is_open() const;
virtual void seek(uint64_t p_position);
@@ -183,10 +182,9 @@ public:
virtual bool file_exists(const String &p_name);
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file);
- ~FileAccessPack();
};
-FileAccess *PackedData::try_open_path(const String &p_path) {
+Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
PathMD5 pmd5(p_path.md5_buffer());
Map<PathMD5, PackedFile>::Element *E = files.find(pmd5);
if (!E) {
@@ -204,9 +202,8 @@ bool PackedData::has_path(const String &p_path) {
}
bool PackedData::has_directory(const String &p_path) {
- DirAccess *da = try_open_directory(p_path);
- if (da) {
- memdelete(da);
+ Ref<DirAccess> da = try_open_directory(p_path);
+ if (da.is_valid()) {
return true;
} else {
return false;
@@ -233,7 +230,7 @@ public:
virtual String get_drive(int p_drive);
virtual Error change_dir(String p_dir);
- virtual String get_current_dir(bool p_include_drive = true);
+ virtual String get_current_dir(bool p_include_drive = true) const;
virtual bool file_exists(String p_file);
virtual bool dir_exists(String p_dir);
@@ -252,14 +249,12 @@ public:
virtual String get_filesystem_type() const;
DirAccessPack();
- ~DirAccessPack() {}
};
-DirAccess *PackedData::try_open_directory(const String &p_path) {
- DirAccess *da = memnew(DirAccessPack());
+Ref<DirAccess> PackedData::try_open_directory(const String &p_path) {
+ Ref<DirAccess> da = memnew(DirAccessPack());
if (da->change_dir(p_path) != OK) {
- memdelete(da);
- da = nullptr;
+ da = Ref<DirAccess>();
}
return da;
}
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 6347862775..17f2335a8e 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -38,20 +38,26 @@ ZipArchive *ZipArchive::instance = nullptr;
extern "C" {
-static void *godot_open(void *data, const char *p_fname, int mode) {
+struct ZipData {
+ Ref<FileAccess> f;
+};
+
+static void *godot_open(voidpf opaque, const char *p_fname, int mode) {
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
return nullptr;
}
- FileAccess *f = FileAccess::open(p_fname, FileAccess::READ);
- ERR_FAIL_COND_V(!f, nullptr);
+ Ref<FileAccess> f = FileAccess::open(p_fname, FileAccess::READ);
+ ERR_FAIL_COND_V(f.is_null(), nullptr);
- return f;
+ ZipData *zd = memnew(ZipData);
+ zd->f = f;
+ return zd;
}
-static uLong godot_read(void *data, void *fdata, void *buf, uLong size) {
- FileAccess *f = (FileAccess *)fdata;
- f->get_buffer((uint8_t *)buf, size);
+static uLong godot_read(voidpf opaque, voidpf stream, void *buf, uLong size) {
+ ZipData *zd = (ZipData *)stream;
+ zd->f->get_buffer((uint8_t *)buf, size);
return size;
}
@@ -60,42 +66,38 @@ static uLong godot_write(voidpf opaque, voidpf stream, const void *buf, uLong si
}
static long godot_tell(voidpf opaque, voidpf stream) {
- FileAccess *f = (FileAccess *)stream;
- return f->get_position();
+ ZipData *zd = (ZipData *)stream;
+ return zd->f->get_position();
}
static long godot_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
- FileAccess *f = (FileAccess *)stream;
+ ZipData *zd = (ZipData *)stream;
uint64_t pos = offset;
switch (origin) {
case ZLIB_FILEFUNC_SEEK_CUR:
- pos = f->get_position() + offset;
+ pos = zd->f->get_position() + offset;
break;
case ZLIB_FILEFUNC_SEEK_END:
- pos = f->get_length() + offset;
+ pos = zd->f->get_length() + offset;
break;
default:
break;
}
- f->seek(pos);
+ zd->f->seek(pos);
return 0;
}
static int godot_close(voidpf opaque, voidpf stream) {
- FileAccess *f = (FileAccess *)stream;
- if (f) {
- f->close();
- memdelete(f);
- f = nullptr;
- }
+ ZipData *zd = (ZipData *)stream;
+ memdelete(zd);
return 0;
}
static int godot_testerror(voidpf opaque, voidpf stream) {
- FileAccess *f = (FileAccess *)stream;
- return f->get_error() != OK ? 1 : 0;
+ ZipData *zd = (ZipData *)stream;
+ return zd->f->get_error() != OK ? 1 : 0;
}
static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) {
@@ -208,7 +210,7 @@ bool ZipArchive::file_exists(String p_name) const {
return files.has(p_name);
}
-FileAccess *ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file) {
+Ref<FileAccess> ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file) {
return memnew(FileAccessZip(p_path, *p_file));
}
@@ -233,7 +235,7 @@ ZipArchive::~ZipArchive() {
}
Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
- close();
+ _close();
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
ZipArchive *arch = ZipArchive::get_singleton();
@@ -247,7 +249,7 @@ Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessZip::close() {
+void FileAccessZip::_close() {
if (!zfile) {
return;
}
@@ -339,7 +341,7 @@ FileAccessZip::FileAccessZip(const String &p_path, const PackedData::PackedFile
}
FileAccessZip::~FileAccessZip() {
- close();
+ _close();
}
#endif // MINIZIP_ENABLED
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 7cd5893101..ae58d99a66 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -67,8 +67,8 @@ public:
bool file_exists(String p_name) const;
- virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
- FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
+ Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
static ZipArchive *get_singleton();
@@ -80,11 +80,12 @@ class FileAccessZip : public FileAccess {
unzFile zfile = nullptr;
unz_file_info64 file_info;
- mutable bool at_eof;
+ mutable bool at_eof = false;
+
+ void _close();
public:
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index f920799677..d983d86b99 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -264,6 +264,9 @@ void HTTPClientTCP::close() {
}
Error HTTPClientTCP::poll() {
+ if (tcp_connection.is_valid()) {
+ tcp_connection->poll();
+ }
switch (status) {
case STATUS_RESOLVING: {
ERR_FAIL_COND_V(resolving == IP::RESOLVER_INVALID_ID, ERR_BUG);
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 577fc59807..661a9f7177 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -378,25 +378,25 @@ Image::Image3DValidateError Image::validate_3d_image(Image::Format p_format, int
String Image::get_3d_image_validation_error_text(Image3DValidateError p_error) {
switch (p_error) {
case VALIDATE_3D_OK: {
- return TTR("Ok");
+ return "Ok";
} break;
case VALIDATE_3D_ERR_IMAGE_EMPTY: {
- return TTR("Empty Image found");
+ return "Empty Image found";
} break;
case VALIDATE_3D_ERR_MISSING_IMAGES: {
- return TTR("Missing Images");
+ return "Missing Images";
} break;
case VALIDATE_3D_ERR_EXTRA_IMAGES: {
- return TTR("Too many Images");
+ return "Too many Images";
} break;
case VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH: {
- return TTR("Image size mismatch");
+ return "Image size mismatch";
} break;
case VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH: {
- return TTR("Image format mismatch");
+ return "Image format mismatch";
} break;
case VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS: {
- return TTR("Image has included mipmaps");
+ return "Image has included mipmaps";
} break;
}
return String();
@@ -1465,8 +1465,8 @@ template <class Component, int CC, bool renormalize,
void (*renormalize_func)(Component *)>
static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint32_t p_width, uint32_t p_height) {
//fast power of 2 mipmap generation
- uint32_t dst_w = MAX(p_width >> 1, 1);
- uint32_t dst_h = MAX(p_height >> 1, 1);
+ uint32_t dst_w = MAX(p_width >> 1, 1u);
+ uint32_t dst_h = MAX(p_height >> 1, 1u);
int right_step = (p_width == 1) ? 0 : CC;
int down_step = (p_height == 1) ? 0 : (p_width * CC);
@@ -2442,6 +2442,39 @@ Ref<Image> Image::get_rect(const Rect2 &p_area) const {
return img;
}
+void Image::_get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest, Rect2i &r_clipped_src_rect, Rect2i &r_clipped_dest_rect) const {
+ r_clipped_dest_rect.position = p_dest;
+ r_clipped_src_rect = p_src_rect;
+
+ if (r_clipped_src_rect.position.x < 0) {
+ r_clipped_dest_rect.position.x -= r_clipped_src_rect.position.x;
+ r_clipped_src_rect.size.x += r_clipped_src_rect.position.x;
+ r_clipped_src_rect.position.x = 0;
+ }
+ if (r_clipped_src_rect.position.y < 0) {
+ r_clipped_dest_rect.position.y -= r_clipped_src_rect.position.y;
+ r_clipped_src_rect.size.y += r_clipped_src_rect.position.y;
+ r_clipped_src_rect.position.y = 0;
+ }
+
+ if (r_clipped_dest_rect.position.x < 0) {
+ r_clipped_src_rect.position.x -= r_clipped_dest_rect.position.x;
+ r_clipped_src_rect.size.x += r_clipped_dest_rect.position.x;
+ r_clipped_dest_rect.position.x = 0;
+ }
+ if (r_clipped_dest_rect.position.y < 0) {
+ r_clipped_src_rect.position.y -= r_clipped_dest_rect.position.y;
+ r_clipped_src_rect.size.y += r_clipped_dest_rect.position.y;
+ r_clipped_dest_rect.position.y = 0;
+ }
+
+ r_clipped_src_rect.size.x = MAX(0, MIN(r_clipped_src_rect.size.x, MIN(p_src->width - r_clipped_src_rect.position.x, width - r_clipped_dest_rect.position.x)));
+ r_clipped_src_rect.size.y = MAX(0, MIN(r_clipped_src_rect.size.y, MIN(p_src->height - r_clipped_src_rect.position.y, height - r_clipped_dest_rect.position.y)));
+
+ r_clipped_dest_rect.size.x = r_clipped_src_rect.size.x;
+ r_clipped_dest_rect.size.y = r_clipped_src_rect.size.y;
+}
+
void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) {
ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object.");
int dsize = data.size();
@@ -2451,22 +2484,13 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po
ERR_FAIL_COND(format != p_src->format);
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot blit_rect in compressed or custom image formats.");
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
-
- if (p_dest.x < 0) {
- clipped_src_rect.position.x = ABS(p_dest.x);
- }
- if (p_dest.y < 0) {
- clipped_src_rect.position.y = ABS(p_dest.y);
- }
-
- if (clipped_src_rect.has_no_area()) {
+ 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()) {
return;
}
- Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
-
uint8_t *wp = data.ptrw();
uint8_t *dst_data_ptr = wp;
@@ -2477,8 +2501,8 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po
for (int i = 0; i < dest_rect.size.y; i++) {
for (int j = 0; j < dest_rect.size.x; j++) {
- int src_x = clipped_src_rect.position.x + j;
- int src_y = clipped_src_rect.position.y + i;
+ int src_x = src_rect.position.x + j;
+ int src_y = src_rect.position.y + i;
int dst_x = dest_rect.position.x + j;
int dst_y = dest_rect.position.y + i;
@@ -2506,22 +2530,13 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
-
- if (p_dest.x < 0) {
- clipped_src_rect.position.x = ABS(p_dest.x);
- }
- if (p_dest.y < 0) {
- clipped_src_rect.position.y = ABS(p_dest.y);
- }
-
- if (clipped_src_rect.has_no_area()) {
+ 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()) {
return;
}
- Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
-
uint8_t *wp = data.ptrw();
uint8_t *dst_data_ptr = wp;
@@ -2534,8 +2549,8 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
for (int i = 0; i < dest_rect.size.y; i++) {
for (int j = 0; j < dest_rect.size.x; j++) {
- int src_x = clipped_src_rect.position.x + j;
- int src_y = clipped_src_rect.position.y + i;
+ int src_x = src_rect.position.x + j;
+ int src_y = src_rect.position.y + i;
if (msk->get_pixel(src_x, src_y).a != 0) {
int dst_x = dest_rect.position.x + j;
@@ -2560,28 +2575,19 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P
ERR_FAIL_COND(srcdsize == 0);
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
-
- if (p_dest.x < 0) {
- clipped_src_rect.position.x = ABS(p_dest.x);
- }
- if (p_dest.y < 0) {
- clipped_src_rect.position.y = ABS(p_dest.y);
- }
-
- if (clipped_src_rect.has_no_area()) {
+ 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()) {
return;
}
- Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
-
Ref<Image> img = p_src;
for (int i = 0; i < dest_rect.size.y; i++) {
for (int j = 0; j < dest_rect.size.x; j++) {
- int src_x = clipped_src_rect.position.x + j;
- int src_y = clipped_src_rect.position.y + i;
+ int src_x = src_rect.position.x + j;
+ int src_y = src_rect.position.y + i;
int dst_x = dest_rect.position.x + j;
int dst_y = dest_rect.position.y + i;
@@ -2609,29 +2615,20 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
-
- if (p_dest.x < 0) {
- clipped_src_rect.position.x = ABS(p_dest.x);
- }
- if (p_dest.y < 0) {
- clipped_src_rect.position.y = ABS(p_dest.y);
- }
-
- if (clipped_src_rect.has_no_area()) {
+ 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()) {
return;
}
- Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
-
Ref<Image> img = p_src;
Ref<Image> msk = p_mask;
for (int i = 0; i < dest_rect.size.y; i++) {
for (int j = 0; j < dest_rect.size.x; j++) {
- int src_x = clipped_src_rect.position.x + j;
- int src_y = clipped_src_rect.position.y + i;
+ int src_x = src_rect.position.x + j;
+ int src_y = src_rect.position.y + i;
// If the mask's pixel is transparent then we skip it
//Color c = msk->get_pixel(src_x, src_y);
@@ -2726,6 +2723,7 @@ Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr;
Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr;
Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr;
Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr;
+Ref<Image> (*Image::basis_universal_unpacker_ptr)(const uint8_t *, int) = nullptr;
void Image::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("width"));
@@ -3008,7 +3006,7 @@ void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation)
}
}
-Image::UsedChannels Image::detect_used_channels(CompressSource p_source) {
+Image::UsedChannels Image::detect_used_channels(CompressSource p_source) const {
ERR_FAIL_COND_V(data.size() == 0, USED_CHANNELS_RGBA);
ERR_FAIL_COND_V(is_compressed(), USED_CHANNELS_RGBA);
bool r = false, g = false, b = false, a = false, c = false;
@@ -3112,8 +3110,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
- ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::_create_empty);
- ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::_create_from_data);
+ ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
+ ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty);
@@ -3275,7 +3273,7 @@ Ref<Image> Image::rgbe_to_srgb() {
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
- new_image->set_pixel(col, row, get_pixel(col, row).to_srgb());
+ new_image->set_pixel(col, row, get_pixel(col, row).linear_to_srgb());
}
}
@@ -3613,6 +3611,10 @@ Image::Image(const uint8_t *p_mem_png_jpg, int p_len) {
if (is_empty() && _jpg_mem_loader_func) {
copy_internals_from(_jpg_mem_loader_func(p_mem_png_jpg, p_len));
}
+
+ if (is_empty() && _webp_mem_loader_func) {
+ copy_internals_from(_webp_mem_loader_func(p_mem_png_jpg, p_len));
+ }
}
Ref<Resource> Image::duplicate(bool p_subresources) const {
diff --git a/core/io/image.h b/core/io/image.h
index 53bfa0881f..1025554d51 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -147,6 +147,7 @@ public:
static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer);
static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels);
static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer);
+ static Ref<Image> (*basis_universal_unpacker_ptr)(const uint8_t *p_data, int p_size);
_FORCE_INLINE_ Color _get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const;
_FORCE_INLINE_ void _set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color);
@@ -155,14 +156,6 @@ protected:
static void _bind_methods();
private:
- void _create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
- create(p_width, p_height, p_use_mipmaps, p_format);
- }
-
- void _create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
- create(p_width, p_height, p_use_mipmaps, p_format, p_data);
- }
-
Format format = FORMAT_L8;
Vector<uint8_t> data;
int width = 0;
@@ -182,6 +175,8 @@ private:
static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr);
bool _can_modify(Format p_format) const;
+ _FORCE_INLINE_ void _get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest, Rect2i &r_clipped_src_rect, Rect2i &r_clipped_dest_rect) const;
+
_FORCE_INLINE_ void _put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel);
_FORCE_INLINE_ void _get_pixelb(int p_x, int p_y, uint32_t p_pixel_size, const uint8_t *p_data, uint8_t *p_pixel);
@@ -289,6 +284,14 @@ public:
Vector<uint8_t> save_png_to_buffer() const;
Error save_exr(const String &p_path, bool p_grayscale) const;
+ void create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+ create(p_width, p_height, p_use_mipmaps, p_format);
+ }
+
+ void create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ create(p_width, p_height, p_use_mipmaps, p_format, p_data);
+ }
+
/**
* create an empty image
*/
@@ -379,7 +382,7 @@ public:
virtual Ref<Resource> duplicate(bool p_subresources = false) const override;
- UsedChannels detect_used_channels(CompressSource p_source = COMPRESS_SOURCE_GENERIC);
+ UsedChannels detect_used_channels(CompressSource p_source = COMPRESS_SOURCE_GENERIC) const;
void optimize_channels();
Color get_pixelv(const Point2i &p_point) const;
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 5518ec8ceb..9cf7c9caba 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -44,17 +44,14 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
return false;
}
-Error ImageLoader::load_image(String p_file, Ref<Image> p_image, 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, bool p_force_linear, 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.");
- FileAccess *f = p_custom;
- if (!f) {
+ Ref<FileAccess> f = p_custom;
+ if (f.is_null()) {
Error err;
f = FileAccess::open(p_file, FileAccess::READ, &err);
- if (!f) {
- ERR_PRINT("Error opening file '" + p_file + "'.");
- return err;
- }
+ ERR_FAIL_COND_V_MSG(f.is_null(), err, "Error opening file '" + p_file + "'.");
}
String extension = p_file.get_extension();
@@ -69,18 +66,10 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c
}
if (err != ERR_FILE_UNRECOGNIZED) {
- if (!p_custom) {
- memdelete(f);
- }
-
return err;
}
}
- if (!p_custom) {
- memdelete(f);
- }
-
return ERR_FILE_UNRECOGNIZED;
}
@@ -122,13 +111,13 @@ void ImageLoader::cleanup() {
/////////////////
-RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- if (!f) {
+Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
- return RES();
+ return Ref<Resource>();
}
uint8_t header[4] = { 0, 0, 0, 0 };
@@ -136,11 +125,10 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin
bool unrecognized = header[0] != 'G' || header[1] != 'D' || header[2] != 'I' || header[3] != 'M';
if (unrecognized) {
- memdelete(f);
if (r_error) {
*r_error = ERR_FILE_UNRECOGNIZED;
}
- ERR_FAIL_V(RES());
+ ERR_FAIL_V(Ref<Resource>());
}
String extension = f->get_pascal_string();
@@ -155,11 +143,10 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin
}
if (idx == -1) {
- memdelete(f);
if (r_error) {
*r_error = ERR_FILE_UNRECOGNIZED;
}
- ERR_FAIL_V(RES());
+ ERR_FAIL_V(Ref<Resource>());
}
Ref<Image> image;
@@ -167,13 +154,11 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin
Error err = ImageLoader::loader[idx]->load_image(image, f, false, 1.0);
- memdelete(f);
-
if (err != OK) {
if (r_error) {
*r_error = err;
}
- return RES();
+ return Ref<Resource>();
}
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index 37d7620f96..c91d382c25 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -44,7 +44,7 @@ class ImageFormatLoader {
friend class ResourceFormatLoaderImage;
protected:
- virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) = 0;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) = 0;
virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
bool recognize(const String &p_extension) const;
@@ -58,7 +58,7 @@ class ImageLoader {
protected:
public:
- static Error load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom = nullptr, 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>(), bool p_force_linear = false, float p_scale = 1.0);
static void get_recognized_extensions(List<String> *p_extensions);
static ImageFormatLoader *recognize(const String &p_extension);
@@ -72,7 +72,7 @@ public:
class ResourceFormatLoaderImage : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 8e0d47e762..5156a5cb99 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -74,8 +74,7 @@ struct _IP_ResolverPrivate {
Semaphore sem;
Thread thread;
- //Semaphore* semaphore;
- bool thread_abort;
+ bool thread_abort = false;
void resolve_queues() {
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
@@ -109,7 +108,7 @@ struct _IP_ResolverPrivate {
}
static void _thread_function(void *self) {
- _IP_ResolverPrivate *ipr = (_IP_ResolverPrivate *)self;
+ _IP_ResolverPrivate *ipr = static_cast<_IP_ResolverPrivate *>(self);
while (!ipr->thread_abort) {
ipr->sem.wait();
@@ -186,7 +185,7 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
}
IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
- ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP::RESOLVER_STATUS_NONE);
+ ERR_FAIL_INDEX_V_MSG(p_id, IP::RESOLVER_MAX_QUERIES, IP::RESOLVER_STATUS_NONE, vformat("Too many concurrent DNS resolver queries (%d, but should be %d at most). Try performing less network requests at once.", p_id, IP::RESOLVER_MAX_QUERIES));
IP::ResolverStatus res = resolver->queue[p_id].status.get();
if (res == IP::RESOLVER_STATUS_NONE) {
@@ -197,7 +196,7 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
}
IPAddress IP::get_resolve_item_address(ResolverID p_id) const {
- ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IPAddress());
+ ERR_FAIL_INDEX_V_MSG(p_id, IP::RESOLVER_MAX_QUERIES, IPAddress(), vformat("Too many concurrent DNS resolver queries (%d, but should be %d at most). Try performing less network requests at once.", p_id, IP::RESOLVER_MAX_QUERIES));
MutexLock lock(resolver->mutex);
@@ -217,7 +216,7 @@ IPAddress IP::get_resolve_item_address(ResolverID p_id) const {
}
Array IP::get_resolve_item_addresses(ResolverID p_id) const {
- ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, Array());
+ ERR_FAIL_INDEX_V_MSG(p_id, IP::RESOLVER_MAX_QUERIES, Array(), vformat("Too many concurrent DNS resolver queries (%d, but should be %d at most). Try performing less network requests at once.", p_id, IP::RESOLVER_MAX_QUERIES));
MutexLock lock(resolver->mutex);
if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
@@ -237,7 +236,7 @@ Array IP::get_resolve_item_addresses(ResolverID p_id) const {
}
void IP::erase_resolve_item(ResolverID p_id) {
- ERR_FAIL_INDEX(p_id, IP::RESOLVER_MAX_QUERIES);
+ ERR_FAIL_INDEX_MSG(p_id, IP::RESOLVER_MAX_QUERIES, vformat("Too many concurrent DNS resolver queries (%d, but should be %d at most). Try performing less network requests at once.", p_id, IP::RESOLVER_MAX_QUERIES));
resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE);
}
diff --git a/core/io/ip.h b/core/io/ip.h
index 5602710550..06ff8a4d70 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -38,7 +38,6 @@ struct _IP_ResolverPrivate;
class IP : public Object {
GDCLASS(IP, Object);
- OBJ_CATEGORY("Networking");
public:
enum ResolverStatus {
@@ -56,14 +55,14 @@ public:
};
enum {
- RESOLVER_MAX_QUERIES = 32,
+ RESOLVER_MAX_QUERIES = 256,
RESOLVER_INVALID_ID = -1
};
typedef int ResolverID;
private:
- _IP_ResolverPrivate *resolver;
+ _IP_ResolverPrivate *resolver = nullptr;
protected:
static IP *singleton;
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index cb6369ae3d..c19fc2820b 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -115,21 +115,14 @@ void Logger::logf_error(const char *p_format, ...) {
va_end(argp);
}
-void RotatedFileLogger::close_file() {
- if (file) {
- memdelete(file);
- file = nullptr;
- }
-}
-
void RotatedFileLogger::clear_old_backups() {
int max_backups = max_files - 1; // -1 for the current file
String basename = base_path.get_file().get_basename();
String extension = base_path.get_extension();
- DirAccess *da = DirAccess::open(base_path.get_base_dir());
- if (!da) {
+ Ref<DirAccess> da = DirAccess::open(base_path.get_base_dir());
+ if (da.is_null()) {
return;
}
@@ -152,12 +145,10 @@ void RotatedFileLogger::clear_old_backups() {
da->remove(E->get());
}
}
-
- memdelete(da);
}
void RotatedFileLogger::rotate_file() {
- close_file();
+ file.unref();
if (FileAccess::exists(base_path)) {
if (max_files > 1) {
@@ -167,22 +158,21 @@ void RotatedFileLogger::rotate_file() {
backup_name += "." + base_path.get_extension();
}
- DirAccess *da = DirAccess::open(base_path.get_base_dir());
- if (da) {
+ Ref<DirAccess> da = DirAccess::open(base_path.get_base_dir());
+ if (da.is_valid()) {
da->copy(base_path, backup_name);
- memdelete(da);
}
clear_old_backups();
}
} else {
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_USERDATA);
- if (da) {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_USERDATA);
+ if (da.is_valid()) {
da->make_dir_recursive(base_path.get_base_dir());
- memdelete(da);
}
}
file = FileAccess::open(base_path, FileAccess::WRITE);
+ file->detach_from_objectdb(); // Note: This FileAccess instance will exist longer than ObjectDB, therefor can't be registered in ObjectDB.
}
RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files) :
@@ -196,7 +186,7 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
return;
}
- if (file) {
+ if (file.is_valid()) {
const int static_buf_size = 512;
char static_buf[static_buf_size];
char *buf = static_buf;
@@ -222,10 +212,6 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
}
}
-RotatedFileLogger::~RotatedFileLogger() {
- close_file();
-}
-
void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {
if (!should_log(p_err)) {
return;
diff --git a/core/io/logger.h b/core/io/logger.h
index 047ee3d0f1..8ac086e376 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -67,7 +67,7 @@ public:
*/
class StdLogger : public Logger {
public:
- virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0;
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) override _PRINTF_FORMAT_ATTRIBUTE_2_0;
virtual ~StdLogger() {}
};
@@ -81,28 +81,25 @@ class RotatedFileLogger : public Logger {
String base_path;
int max_files;
- FileAccess *file = nullptr;
+ Ref<FileAccess> file;
- void close_file();
void clear_old_backups();
void rotate_file();
public:
- RotatedFileLogger(const String &p_base_path, int p_max_files = 10);
+ explicit RotatedFileLogger(const String &p_base_path, int p_max_files = 10);
- virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0;
-
- virtual ~RotatedFileLogger();
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) override _PRINTF_FORMAT_ATTRIBUTE_2_0;
};
class CompositeLogger : public Logger {
Vector<Logger *> loggers;
public:
- CompositeLogger(Vector<Logger *> p_loggers);
+ explicit CompositeLogger(Vector<Logger *> p_loggers);
- virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0;
- virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type = ERR_ERROR);
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) override _PRINTF_FORMAT_ATTRIBUTE_2_0;
+ virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type = ERR_ERROR) override;
void add_logger(Logger *p_logger);
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 12de2f582e..bb9606c94b 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -291,7 +291,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- val.elements[i][j] = decode_double(&buf[(i * 2 + j) * sizeof(double)]);
+ val.columns[i][j] = decode_double(&buf[(i * 2 + j) * sizeof(double)]);
}
}
@@ -302,7 +302,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(float) * 6, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- val.elements[i][j] = decode_float(&buf[(i * 2 + j) * sizeof(float)]);
+ val.columns[i][j] = decode_float(&buf[(i * 2 + j) * sizeof(float)]);
}
}
@@ -401,7 +401,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 9, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- val.elements[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]);
+ val.rows[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]);
}
}
@@ -412,7 +412,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(float) * 9, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- val.elements[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]);
+ val.rows[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]);
}
}
@@ -429,7 +429,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 12, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- val.basis.elements[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]);
+ val.basis.rows[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]);
}
}
val.origin[0] = decode_double(&buf[sizeof(double) * 9]);
@@ -443,7 +443,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(float) * 12, ERR_INVALID_DATA);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- val.basis.elements[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]);
+ val.basis.rows[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]);
}
}
val.origin[0] = decode_float(&buf[sizeof(float) * 9]);
@@ -601,7 +601,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
if (Object::cast_to<RefCounted>(obj)) {
- REF ref = REF(Object::cast_to<RefCounted>(obj));
+ Ref<RefCounted> ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj));
r_variant = ref;
} else {
r_variant = obj;
@@ -1068,6 +1068,21 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
flags |= ENCODE_FLAG_OBJECT_AS_ID;
}
} break;
+#ifdef REAL_T_IS_DOUBLE
+ case Variant::VECTOR2:
+ case Variant::VECTOR3:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::TRANSFORM2D:
+ case Variant::TRANSFORM3D:
+ case Variant::QUATERNION:
+ case Variant::PLANE:
+ case Variant::BASIS:
+ case Variant::RECT2:
+ case Variant::AABB: {
+ flags |= ENCODE_FLAG_64;
+ } break;
+#endif // REAL_T_IS_DOUBLE
default: {
} // nothing to do at this stage
}
@@ -1246,7 +1261,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Transform2D val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- memcpy(&buf[(i * 2 + j) * sizeof(real_t)], &val.elements[i][j], sizeof(real_t));
+ memcpy(&buf[(i * 2 + j) * sizeof(real_t)], &val.columns[i][j], sizeof(real_t));
}
}
}
@@ -1297,7 +1312,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Basis val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.elements[i][j], sizeof(real_t));
+ memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.rows[i][j], sizeof(real_t));
}
}
}
@@ -1310,7 +1325,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Transform3D val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.basis.elements[i][j], sizeof(real_t));
+ memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.basis.rows[i][j], sizeof(real_t));
}
}
diff --git a/core/io/missing_resource.cpp b/core/io/missing_resource.cpp
new file mode 100644
index 0000000000..7aae6c6f0a
--- /dev/null
+++ b/core/io/missing_resource.cpp
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* missing_resource.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 "missing_resource.h"
+
+bool MissingResource::_set(const StringName &p_name, const Variant &p_value) {
+ if (is_recording_properties()) {
+ properties.insert(p_name, p_value);
+ return true; //always valid to set (add)
+ } else {
+ if (!properties.has(p_name)) {
+ return false;
+ }
+
+ properties[p_name] = p_value;
+ return true;
+ }
+}
+
+bool MissingResource::_get(const StringName &p_name, Variant &r_ret) const {
+ if (!properties.has(p_name)) {
+ return false;
+ }
+ r_ret = properties[p_name];
+ return true;
+}
+
+void MissingResource::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (OrderedHashMap<StringName, Variant>::ConstElement E = properties.front(); E; E = E.next()) {
+ p_list->push_back(PropertyInfo(E.value().get_type(), E.key()));
+ }
+}
+
+void MissingResource::set_original_class(const String &p_class) {
+ original_class = p_class;
+}
+
+String MissingResource::get_original_class() const {
+ return original_class;
+}
+
+void MissingResource::set_recording_properties(bool p_enable) {
+ recording_properties = p_enable;
+}
+
+bool MissingResource::is_recording_properties() const {
+ return recording_properties;
+}
+
+void MissingResource::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_original_class", "name"), &MissingResource::set_original_class);
+ ClassDB::bind_method(D_METHOD("get_original_class"), &MissingResource::get_original_class);
+
+ ClassDB::bind_method(D_METHOD("set_recording_properties", "enable"), &MissingResource::set_recording_properties);
+ ClassDB::bind_method(D_METHOD("is_recording_properties"), &MissingResource::is_recording_properties);
+
+ // Expose, but not save.
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "original_class", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_original_class", "get_original_class");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "recording_properties", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_recording_properties", "is_recording_properties");
+}
+
+MissingResource::MissingResource() {
+}
diff --git a/core/io/missing_resource.h b/core/io/missing_resource.h
new file mode 100644
index 0000000000..e87efe1a98
--- /dev/null
+++ b/core/io/missing_resource.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* missing_resource.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 MISSING_RESOURCE_H
+#define MISSING_RESOURCE_H
+
+#include "core/io/resource.h"
+
+#define META_PROPERTY_MISSING_RESOURCES "metadata/_missing_resources"
+#define META_MISSING_RESOURCES "_missing_resources"
+
+class MissingResource : public Resource {
+ GDCLASS(MissingResource, Resource)
+ OrderedHashMap<StringName, Variant> properties;
+
+ String original_class;
+ bool recording_properties = false;
+
+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;
+
+ static void _bind_methods();
+
+public:
+ void set_original_class(const String &p_class);
+ String get_original_class() const;
+
+ void set_recording_properties(bool p_enable);
+ bool is_recording_properties() const;
+
+ MissingResource();
+};
+
+#endif // MISSING_RESOURCE_H
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index 14183b472b..027fdd51aa 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -105,7 +105,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
if (type == TYPE_ARRAY || type == TYPE_DICT) {
Ref<PackedDataContainerRef> pdcr = memnew(PackedDataContainerRef);
- Ref<PackedDataContainer> pdc = Ref<PackedDataContainer>((PackedDataContainer *)this);
+ Ref<PackedDataContainer> pdc = Ref<PackedDataContainer>(const_cast<PackedDataContainer *>(this));
pdcr->from = pdc;
pdcr->offset = p_ofs;
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index 503eb17cae..84d1f3ebd4 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -242,7 +242,7 @@ Error PacketPeerUDP::connect_to_host(const IPAddress &p_host, int p_port) {
return OK;
}
-bool PacketPeerUDP::is_connected_to_host() const {
+bool PacketPeerUDP::is_socket_connected() const {
return connected;
}
@@ -348,7 +348,7 @@ void PacketPeerUDP::_bind_methods() {
ClassDB::bind_method(D_METHOD("wait"), &PacketPeerUDP::wait);
ClassDB::bind_method(D_METHOD("is_bound"), &PacketPeerUDP::is_bound);
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &PacketPeerUDP::connect_to_host);
- ClassDB::bind_method(D_METHOD("is_connected_to_host"), &PacketPeerUDP::is_connected_to_host);
+ ClassDB::bind_method(D_METHOD("is_socket_connected"), &PacketPeerUDP::is_socket_connected);
ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip);
ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port);
ClassDB::bind_method(D_METHOD("get_local_port"), &PacketPeerUDP::get_local_port);
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
index 444a6dd5ba..a174cf5347 100644
--- a/core/io/packet_peer_udp.h
+++ b/core/io/packet_peer_udp.h
@@ -79,7 +79,7 @@ public:
void disconnect_shared_socket(); // Used by UDPServer
Error store_packet(IPAddress p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer
Error connect_to_host(const IPAddress &p_host, int p_port);
- bool is_connected_to_host() const;
+ bool is_socket_connected() const;
IPAddress get_packet_address() const;
int get_packet_port() const;
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index 272ace3438..aa1b323db2 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -83,13 +83,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String &
}
enc_dir = p_encrypt_directory;
- if (file != nullptr) {
- memdelete(file);
- }
-
file = FileAccess::open(p_file, FileAccess::WRITE);
-
- ERR_FAIL_COND_V_MSG(!file, ERR_CANT_CREATE, "Can't open file to write: " + String(p_file) + ".");
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_CANT_CREATE, "Can't open file to write: " + String(p_file) + ".");
alignment = p_alignment;
@@ -112,8 +107,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String &
}
Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) {
- FileAccess *f = FileAccess::open(p_src, FileAccess::READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_src, FileAccess::READ);
+ if (f.is_null()) {
return ERR_FILE_CANT_OPEN;
}
@@ -149,14 +144,11 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr
files.push_back(pf);
- f->close();
- memdelete(f);
-
return OK;
}
Error PCKPacker::flush(bool p_verbose) {
- ERR_FAIL_COND_V_MSG(!file, ERR_INVALID_PARAMETER, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_INVALID_PARAMETER, "File must be opened before use.");
int64_t file_base_ofs = file->get_position();
file->store_64(0); // files base
@@ -168,12 +160,12 @@ Error PCKPacker::flush(bool p_verbose) {
// write the index
file->store_32(files.size());
- FileAccessEncrypted *fae = nullptr;
- FileAccess *fhead = file;
+ Ref<FileAccessEncrypted> fae;
+ Ref<FileAccess> fhead = file;
if (enc_dir) {
- fae = memnew(FileAccessEncrypted);
- ERR_FAIL_COND_V(!fae, ERR_CANT_CREATE);
+ fae.instantiate();
+ ERR_FAIL_COND_V(fae.is_null(), ERR_CANT_CREATE);
Error err = fae->open_and_parse(file, key, FileAccessEncrypted::MODE_WRITE_AES256, false);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
@@ -202,9 +194,9 @@ Error PCKPacker::flush(bool p_verbose) {
fhead->store_32(flags);
}
- if (fae) {
- fae->release();
- memdelete(fae);
+ if (fae.is_valid()) {
+ fhead.unref();
+ fae.unref();
}
int header_padding = _get_pad(alignment, file->get_position());
@@ -222,14 +214,13 @@ Error PCKPacker::flush(bool p_verbose) {
int count = 0;
for (int i = 0; i < files.size(); i++) {
- FileAccess *src = FileAccess::open(files[i].src_path, FileAccess::READ);
+ Ref<FileAccess> src = FileAccess::open(files[i].src_path, FileAccess::READ);
uint64_t to_write = files[i].size;
- fae = nullptr;
- FileAccess *ftmp = file;
+ Ref<FileAccess> ftmp = file;
if (files[i].encrypted) {
- fae = memnew(FileAccessEncrypted);
- ERR_FAIL_COND_V(!fae, ERR_CANT_CREATE);
+ fae.instantiate();
+ ERR_FAIL_COND_V(fae.is_null(), ERR_CANT_CREATE);
Error err = fae->open_and_parse(file, key, FileAccessEncrypted::MODE_WRITE_AES256, false);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
@@ -242,9 +233,9 @@ Error PCKPacker::flush(bool p_verbose) {
to_write -= read;
}
- if (fae) {
- fae->release();
- memdelete(fae);
+ if (fae.is_valid()) {
+ ftmp.unref();
+ fae.unref();
}
int pad = _get_pad(alignment, file->get_position());
@@ -252,15 +243,10 @@ Error PCKPacker::flush(bool p_verbose) {
file->store_8(Math::rand() % 256);
}
- src->close();
- memdelete(src);
count += 1;
const int file_num = files.size();
if (p_verbose && (file_num > 0)) {
- if (count % 100 == 0) {
- printf("%i/%i (%.2f)\r", count, file_num, float(count) / file_num * 100);
- fflush(stdout);
- }
+ print_line(vformat("[%d/%d - %d%%] PCKPacker flush: %s -> %s", count, file_num, float(count) / file_num * 100, files[i].src_path, files[i].path));
}
}
@@ -268,15 +254,8 @@ Error PCKPacker::flush(bool p_verbose) {
printf("\n");
}
- file->close();
+ file.unref();
memdelete_arr(buf);
return OK;
}
-
-PCKPacker::~PCKPacker() {
- if (file != nullptr) {
- memdelete(file);
- }
- file = nullptr;
-}
diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h
index 583171a70b..77ec293fb2 100644
--- a/core/io/pck_packer.h
+++ b/core/io/pck_packer.h
@@ -38,7 +38,7 @@ class FileAccess;
class PCKPacker : public RefCounted {
GDCLASS(PCKPacker, RefCounted);
- FileAccess *file = nullptr;
+ Ref<FileAccess> file;
int alignment = 0;
uint64_t ofs = 0;
@@ -63,7 +63,6 @@ public:
Error flush(bool p_verbose = false);
PCKPacker() {}
- ~PCKPacker();
};
#endif // PCK_PACKER_H
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 66d5c54b53..e6535c67a4 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -208,13 +208,13 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res
}
Variant p = get(E.name);
if (p.get_type() == Variant::OBJECT) {
- RES sr = p;
+ Ref<Resource> sr = p;
if (sr.is_valid()) {
if (sr->is_local_to_scene()) {
if (remap_cache.has(sr)) {
p = remap_cache[sr];
} else {
- RES dupe = sr->duplicate_for_local_scene(p_for_scene, remap_cache);
+ Ref<Resource> dupe = sr->duplicate_for_local_scene(p_for_scene, remap_cache);
p = dupe;
remap_cache[sr] = dupe;
}
@@ -240,7 +240,7 @@ void Resource::configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, R
}
Variant p = get(E.name);
if (p.get_type() == Variant::OBJECT) {
- RES sr = p;
+ Ref<Resource> sr = p;
if (sr.is_valid()) {
if (sr->is_local_to_scene()) {
if (!remap_cache.has(sr)) {
@@ -257,7 +257,7 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const {
List<PropertyInfo> plist;
get_property_list(&plist);
- Ref<Resource> r = (Resource *)ClassDB::instantiate(get_class());
+ Ref<Resource> r = static_cast<Resource *>(ClassDB::instantiate(get_class()));
ERR_FAIL_COND_V(r.is_null(), Ref<Resource>());
for (const PropertyInfo &E : plist) {
@@ -269,7 +269,7 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const {
if ((p.get_type() == Variant::DICTIONARY || p.get_type() == Variant::ARRAY)) {
r->set(E.name, p.duplicate(p_subresources));
} else if (p.get_type() == Variant::OBJECT && (p_subresources || (E.usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE))) {
- RES sr = p;
+ Ref<Resource> sr = p;
if (sr.is_valid()) {
r->set(E.name, sr->duplicate(p_subresources));
}
@@ -290,6 +290,21 @@ void Resource::_take_over_path(const String &p_path) {
}
RID Resource::get_rid() const {
+ if (get_script_instance()) {
+ Callable::CallError ce;
+ RID ret = get_script_instance()->callp(SNAME("_get_rid"), nullptr, 0, ce);
+ if (ce.error == Callable::CallError::CALL_OK && ret.is_valid()) {
+ return ret;
+ }
+ }
+ if (_get_extension() && _get_extension()->get_rid) {
+ RID ret;
+ ret.from_uint64(_get_extension()->get_rid(_get_extension_instance()));
+ if (ret.is_valid()) {
+ return ret;
+ }
+ }
+
return RID();
}
@@ -306,7 +321,7 @@ void Resource::notify_change_to_owners() {
Object *obj = ObjectDB::get_instance(E->get());
ERR_CONTINUE_MSG(!obj, "Object was deleted, while still owning a resource."); //wtf
//TODO store string
- obj->call("resource_changed", RES(this));
+ obj->call("resource_changed", Ref<Resource>(this));
}
}
@@ -320,7 +335,7 @@ uint32_t Resource::hash_edited_version() const {
for (const PropertyInfo &E : plist) {
if (E.usage & PROPERTY_USAGE_STORAGE && E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- RES res = get(E.name);
+ Ref<Resource> res = get(E.name);
if (res.is_valid()) {
hash = hash_djb2_one_32(res->hash_edited_version(), hash);
}
@@ -428,6 +443,11 @@ void Resource::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "resource_name"), "set_name", "get_name");
+
+ MethodInfo get_rid_bind("_get_rid");
+ get_rid_bind.return_val.type = Variant::RID;
+
+ ::ClassDB::add_virtual_method(get_class_static(), get_rid_bind, true, Vector<String>(), true);
}
Resource::Resource() :
@@ -518,10 +538,10 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
Map<String, int> type_count;
- FileAccess *f = nullptr;
+ Ref<FileAccess> f;
if (p_file) {
f = FileAccess::open(String::utf8(p_file), FileAccess::WRITE);
- ERR_FAIL_COND_MSG(!f, "Cannot create file at path '" + String::utf8(p_file) + "'.");
+ ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file at path '" + String::utf8(p_file) + "'.");
}
const String *K = nullptr;
@@ -535,21 +555,17 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
type_count[r->get_class()]++;
if (!p_short) {
- if (f) {
+ if (f.is_valid()) {
f->store_line(r->get_class() + ": " + r->get_path());
}
}
}
for (const KeyValue<String, int> &E : type_count) {
- if (f) {
+ if (f.is_valid()) {
f->store_line(E.key + " count: " + itos(E.value));
}
}
- if (f) {
- f->close();
- memdelete(f);
- }
lock.read_unlock();
#else
diff --git a/core/io/resource.h b/core/io/resource.h
index b1e1c15541..43ae104da5 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -48,7 +48,6 @@ private:
class Resource : public RefCounted {
GDCLASS(Resource, RefCounted);
- OBJ_CATEGORY("Resources");
public:
static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension("res", get_class_static()); }
@@ -151,8 +150,6 @@ public:
~Resource();
};
-typedef Ref<Resource> RES;
-
class ResourceCache {
friend class Resource;
friend class ResourceLoader; //need the lock
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 611f371229..fbb4293961 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -35,6 +35,7 @@
#include "core/io/file_access_compressed.h"
#include "core/io/image.h"
#include "core/io/marshalls.h"
+#include "core/io/missing_resource.h"
#include "core/version.h"
//#define print_bl(m_what) print_line(m_what)
@@ -101,6 +102,50 @@ void ResourceLoaderBinary::_advance_padding(uint32_t p_len) {
}
}
+static Error read_reals(real_t *dst, Ref<FileAccess> &f, size_t count) {
+ if (f->real_is_double) {
+ if (sizeof(real_t) == 8) {
+ // Ideal case with double-precision
+ f->get_buffer((uint8_t *)dst, count * sizeof(double));
+#ifdef BIG_ENDIAN_ENABLED
+ {
+ uint64_t *dst = (uint64_t *)dst;
+ for (size_t i = 0; i < count; i++) {
+ dst[i] = BSWAP64(dst[i]);
+ }
+ }
+#endif
+ } else if (sizeof(real_t) == 4) {
+ // May be slower, but this is for compatibility. Eventually the data should be converted.
+ for (size_t i = 0; i < count; ++i) {
+ dst[i] = f->get_double();
+ }
+ } else {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "real_t size is neither 4 nor 8!");
+ }
+ } else {
+ if (sizeof(real_t) == 4) {
+ // Ideal case with float-precision
+ f->get_buffer((uint8_t *)dst, count * sizeof(float));
+#ifdef BIG_ENDIAN_ENABLED
+ {
+ uint32_t *dst = (uint32_t *)dst;
+ for (size_t i = 0; i < count; i++) {
+ dst[i] = BSWAP32(dst[i]);
+ }
+ }
+#endif
+ } else if (sizeof(real_t) == 8) {
+ for (size_t i = 0; i < count; ++i) {
+ dst[i] = f->get_float();
+ }
+ } else {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "real_t size is neither 4 nor 8!");
+ }
+ }
+ return OK;
+}
+
StringName ResourceLoaderBinary::_get_string() {
uint32_t id = f->get_32();
if (id & 0x80000000) {
@@ -222,40 +267,40 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
} break;
case VARIANT_TRANSFORM2D: {
Transform2D v;
- v.elements[0].x = f->get_real();
- v.elements[0].y = f->get_real();
- v.elements[1].x = f->get_real();
- v.elements[1].y = f->get_real();
- v.elements[2].x = f->get_real();
- v.elements[2].y = f->get_real();
+ v.columns[0].x = f->get_real();
+ v.columns[0].y = f->get_real();
+ v.columns[1].x = f->get_real();
+ v.columns[1].y = f->get_real();
+ v.columns[2].x = f->get_real();
+ v.columns[2].y = f->get_real();
r_v = v;
} break;
case VARIANT_BASIS: {
Basis v;
- v.elements[0].x = f->get_real();
- v.elements[0].y = f->get_real();
- v.elements[0].z = f->get_real();
- v.elements[1].x = f->get_real();
- v.elements[1].y = f->get_real();
- v.elements[1].z = f->get_real();
- v.elements[2].x = f->get_real();
- v.elements[2].y = f->get_real();
- v.elements[2].z = f->get_real();
+ v.rows[0].x = f->get_real();
+ v.rows[0].y = f->get_real();
+ v.rows[0].z = f->get_real();
+ v.rows[1].x = f->get_real();
+ v.rows[1].y = f->get_real();
+ v.rows[1].z = f->get_real();
+ v.rows[2].x = f->get_real();
+ v.rows[2].y = f->get_real();
+ v.rows[2].z = f->get_real();
r_v = v;
} break;
case VARIANT_TRANSFORM3D: {
Transform3D v;
- v.basis.elements[0].x = f->get_real();
- v.basis.elements[0].y = f->get_real();
- v.basis.elements[0].z = f->get_real();
- v.basis.elements[1].x = f->get_real();
- v.basis.elements[1].y = f->get_real();
- v.basis.elements[1].z = f->get_real();
- v.basis.elements[2].x = f->get_real();
- v.basis.elements[2].y = f->get_real();
- v.basis.elements[2].z = f->get_real();
+ v.basis.rows[0].x = f->get_real();
+ v.basis.rows[0].y = f->get_real();
+ v.basis.rows[0].z = f->get_real();
+ v.basis.rows[1].x = f->get_real();
+ v.basis.rows[1].y = f->get_real();
+ v.basis.rows[1].z = f->get_real();
+ v.basis.rows[2].x = f->get_real();
+ v.basis.rows[2].y = f->get_real();
+ v.basis.rows[2].z = f->get_real();
v.origin.x = f->get_real();
v.origin.y = f->get_real();
v.origin.z = f->get_real();
@@ -344,7 +389,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
path = remaps[path];
}
- RES res = ResourceLoader::load(path, exttype);
+ Ref<Resource> res = ResourceLoader::load(path, exttype);
if (res.is_null()) {
WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data());
@@ -528,21 +573,9 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
Vector<Vector2> array;
array.resize(len);
Vector2 *w = array.ptrw();
- if (sizeof(Vector2) == 8) {
- f->get_buffer((uint8_t *)w, len * sizeof(real_t) * 2);
-#ifdef BIG_ENDIAN_ENABLED
- {
- uint32_t *ptr = (uint32_t *)w.ptr();
- for (int i = 0; i < len * 2; i++) {
- ptr[i] = BSWAP32(ptr[i]);
- }
- }
-
-#endif
-
- } else {
- ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector2 size is NOT 8!");
- }
+ static_assert(sizeof(Vector2) == 2 * sizeof(real_t));
+ const Error err = read_reals(reinterpret_cast<real_t *>(w), f, len * 2);
+ ERR_FAIL_COND_V(err != OK, err);
r_v = array;
@@ -553,21 +586,9 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
Vector<Vector3> array;
array.resize(len);
Vector3 *w = array.ptrw();
- if (sizeof(Vector3) == 12) {
- f->get_buffer((uint8_t *)w, len * sizeof(real_t) * 3);
-#ifdef BIG_ENDIAN_ENABLED
- {
- uint32_t *ptr = (uint32_t *)w.ptr();
- for (int i = 0; i < len * 3; i++) {
- ptr[i] = BSWAP32(ptr[i]);
- }
- }
-
-#endif
-
- } else {
- ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector3 size is NOT 12!");
- }
+ static_assert(sizeof(Vector3) == 3 * sizeof(real_t));
+ const Error err = read_reals(reinterpret_cast<real_t *>(w), f, len * 3);
+ ERR_FAIL_COND_V(err != OK, err);
r_v = array;
@@ -578,22 +599,19 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
Vector<Color> array;
array.resize(len);
Color *w = array.ptrw();
- if (sizeof(Color) == 16) {
- f->get_buffer((uint8_t *)w, len * sizeof(real_t) * 4);
+ // Colors always use `float` even with double-precision support enabled
+ static_assert(sizeof(Color) == 4 * sizeof(float));
+ f->get_buffer((uint8_t *)w, len * sizeof(float) * 4);
#ifdef BIG_ENDIAN_ENABLED
- {
- uint32_t *ptr = (uint32_t *)w.ptr();
- for (int i = 0; i < len * 4; i++) {
- ptr[i] = BSWAP32(ptr[i]);
- }
+ {
+ uint32_t *ptr = (uint32_t *)w.ptr();
+ for (int i = 0; i < len * 4; i++) {
+ ptr[i] = BSWAP32(ptr[i]);
}
+ }
#endif
- } else {
- ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Color size is NOT 16!");
- }
-
r_v = array;
} break;
default: {
@@ -679,7 +697,7 @@ Error ResourceLoaderBinary::load() {
}
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE && ResourceCache::has(path)) {
- RES cached = ResourceCache::get(path);
+ Ref<Resource> cached = ResourceCache::get(path);
if (cached.is_valid()) {
//already loaded, don't do anything
stage++;
@@ -700,7 +718,7 @@ Error ResourceLoaderBinary::load() {
String t = get_unicode_string();
- RES res;
+ Ref<Resource> res;
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//use the existing one
@@ -711,13 +729,23 @@ Error ResourceLoaderBinary::load() {
}
}
+ MissingResource *missing_resource = nullptr;
+
if (res.is_null()) {
//did not replace
Object *obj = ClassDB::instantiate(t);
if (!obj) {
- error = ERR_FILE_CORRUPT;
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
+ if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
+ //create a missing resource
+ missing_resource = memnew(MissingResource);
+ missing_resource->set_original_class(t);
+ missing_resource->set_recording_properties(true);
+ obj = missing_resource;
+ } else {
+ error = ERR_FILE_CORRUPT;
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
+ }
}
Resource *r = Object::cast_to<Resource>(obj);
@@ -728,7 +756,7 @@ Error ResourceLoaderBinary::load() {
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
}
- res = RES(r);
+ res = Ref<Resource>(r);
if (!path.is_empty() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it
}
@@ -743,6 +771,8 @@ Error ResourceLoaderBinary::load() {
//set properties
+ Dictionary missing_resource_properties;
+
for (int j = 0; j < pc; j++) {
StringName name = _get_string();
@@ -758,8 +788,32 @@ Error ResourceLoaderBinary::load() {
return error;
}
- res->set(name, value);
+ bool set_valid = true;
+ if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) {
+ // If the property being set is a missing resource (and the parent is not),
+ // then setting it will most likely not work.
+ // Instead, save it as metadata.
+
+ Ref<MissingResource> mr = value;
+ if (mr.is_valid()) {
+ missing_resource_properties[name] = mr;
+ set_valid = false;
+ }
+ }
+
+ if (set_valid) {
+ res->set(name, value);
+ }
+ }
+
+ if (missing_resource) {
+ missing_resource->set_recording_properties(false);
}
+
+ if (!missing_resource_properties.is_empty()) {
+ res->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
+ }
+
#ifdef TOOLS_ENABLED
res->set_edited(false);
#endif
@@ -772,7 +826,7 @@ Error ResourceLoaderBinary::load() {
resource_cache.push_back(res);
if (main) {
- f->close();
+ f.unref();
resource = res;
resource->set_as_translation_remapped(translation_remapped);
error = OK;
@@ -787,13 +841,13 @@ void ResourceLoaderBinary::set_translation_remapped(bool p_remapped) {
translation_remapped = p_remapped;
}
-static void save_ustring(FileAccess *f, const String &p_string) {
+static void save_ustring(Ref<FileAccess> f, const String &p_string) {
CharString utf8 = p_string.utf8();
f->store_32(utf8.length() + 1);
f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
}
-static String get_ustring(FileAccess *f) {
+static String get_ustring(Ref<FileAccess> f) {
int len = f->get_32();
Vector<char> str_buf;
str_buf.resize(len);
@@ -817,7 +871,7 @@ String ResourceLoaderBinary::get_unicode_string() {
return s;
}
-void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types) {
+void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types) {
open(p_f, false, true);
if (error) {
return;
@@ -839,7 +893,7 @@ void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List<String> *p_dep
}
}
-void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_keep_uuid_paths) {
+void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p_keep_uuid_paths) {
error = OK;
f = p_f;
@@ -847,11 +901,11 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee
f->get_buffer(header, 4);
if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
// Compressed.
- FileAccessCompressed *fac = memnew(FileAccessCompressed);
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
error = fac->open_after_magic(f);
if (error != OK) {
- memdelete(fac);
- f->close();
+ f.unref();
ERR_FAIL_MSG("Failed to open binary resource file: " + local_path + ".");
}
f = fac;
@@ -859,7 +913,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
// Not normal.
error = ERR_FILE_UNRECOGNIZED;
- f->close();
+ f.unref();
ERR_FAIL_MSG("Unrecognized binary resource file: " + local_path + ".");
}
@@ -884,7 +938,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee
print_bl("format: " + itos(ver_format));
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
- f->close();
+ f.unref();
ERR_FAIL_MSG(vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).",
local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH));
}
@@ -901,6 +955,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee
if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS) {
using_uids = true;
}
+ f->real_is_double = (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_REAL_T_IS_DOUBLE) != 0;
if (using_uids) {
uid = f->get_64();
@@ -960,12 +1015,12 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee
if (f->eof_reached()) {
error = ERR_FILE_CORRUPT;
- f->close();
+ f.unref();
ERR_FAIL_MSG("Premature end of file (EOF): " + local_path + ".");
}
}
-String ResourceLoaderBinary::recognize(FileAccess *p_f) {
+String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
error = OK;
f = p_f;
@@ -973,11 +1028,11 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) {
f->get_buffer(header, 4);
if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
// Compressed.
- FileAccessCompressed *fac = memnew(FileAccessCompressed);
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
error = fac->open_after_magic(f);
if (error != OK) {
- memdelete(fac);
- f->close();
+ f.unref();
return "";
}
f = fac;
@@ -985,7 +1040,7 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) {
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
// Not normal.
error = ERR_FILE_UNRECOGNIZED;
- f->close();
+ f.unref();
return "";
}
@@ -999,7 +1054,7 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) {
uint32_t ver_format = f->get_32();
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
- f->close();
+ f.unref();
return "";
}
@@ -1008,21 +1063,15 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) {
return type;
}
-ResourceLoaderBinary::~ResourceLoaderBinary() {
- if (f) {
- memdelete(f);
- }
-}
-
-RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot open file '" + p_path + "'.");
ResourceLoaderBinary loader;
loader.cache_mode = p_cache_mode;
@@ -1031,7 +1080,6 @@ RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_origi
String path = !p_original_path.is_empty() ? p_original_path : p_path;
loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.open(f);
err = loader.load();
@@ -1041,7 +1089,7 @@ RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_origi
}
if (err) {
- return RES();
+ return Ref<Resource>();
}
return loader.resource;
}
@@ -1079,23 +1127,20 @@ bool ResourceFormatLoaderBinary::handles_type(const String &p_type) const {
}
void ResourceFormatLoaderBinary::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_path + "'.");
ResourceLoaderBinary loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.get_dependencies(f, p_dependencies, p_add_types);
}
Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {
- //Error error=OK;
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_path + "'.");
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_path + "'.");
-
- FileAccess *fw = nullptr; //=FileAccess::open(p_path+".depren");
+ Ref<FileAccess> fw;
String local_path = p_path.get_base_dir();
@@ -1103,36 +1148,26 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
f->get_buffer(header, 4);
if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
// Compressed.
- FileAccessCompressed *fac = memnew(FileAccessCompressed);
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
Error err = fac->open_after_magic(f);
- if (err != OK) {
- memdelete(fac);
- memdelete(f);
- ERR_FAIL_V_MSG(err, "Cannot open file '" + p_path + "'.");
- }
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'.");
f = fac;
- FileAccessCompressed *facw = memnew(FileAccessCompressed);
+ Ref<FileAccessCompressed> facw;
+ facw.instantiate();
facw->configure("RSCC");
err = facw->_open(p_path + ".depren", FileAccess::WRITE);
- if (err) {
- memdelete(fac);
- memdelete(facw);
- ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'.");
- }
+ ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'.");
fw = facw;
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
// Not normal.
- memdelete(f);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unrecognized binary resource file '" + local_path + "'.");
} else {
fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE);
- if (!fw) {
- memdelete(f);
- }
- ERR_FAIL_COND_V_MSG(!fw, ERR_CANT_CREATE, "Cannot create file '" + p_path + ".depren'.");
+ ERR_FAIL_COND_V_MSG(fw.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + ".depren'.");
uint8_t magic[4] = { 'R', 'S', 'R', 'C' };
fw->store_buffer(magic, 4);
@@ -1155,12 +1190,14 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
uint32_t ver_format = f->get_32();
if (ver_format < FORMAT_VERSION_CAN_RENAME_DEPS) {
- memdelete(f);
- memdelete(fw);
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- da->remove(p_path + ".depren");
- memdelete(da);
- //use the old approach
+ fw.unref();
+
+ {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ da->remove(p_path + ".depren");
+ }
+
+ // Use the old approach.
WARN_PRINT("This file is old, so it can't refactor dependencies, opening and resaving '" + p_path + "'.");
@@ -1173,21 +1210,18 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
loader.remaps = p_map;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.open(f);
err = loader.load();
ERR_FAIL_COND_V(err != ERR_FILE_EOF, ERR_FILE_CORRUPT);
- RES res = loader.get_resource();
+ Ref<Resource> res = loader.get_resource();
ERR_FAIL_COND_V(!res.is_valid(), ERR_FILE_CORRUPT);
return ResourceFormatSaverBinary::singleton->save(p_path, res);
}
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
- memdelete(f);
- memdelete(fw);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED,
vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).",
local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH));
@@ -1290,36 +1324,34 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
fw->store_8(b);
b = f->get_8();
}
+ f.unref();
bool all_ok = fw->get_error() == OK;
fw->seek(md_ofs);
fw->store_64(importmd_ofs + size_diff);
- memdelete(f);
- memdelete(fw);
-
if (!all_ok) {
return ERR_CANT_CREATE;
}
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ fw.unref();
+
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
da->remove(p_path);
da->rename(p_path + ".depren", p_path);
- memdelete(da);
return OK;
}
String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
return ""; //could not read
}
ResourceLoaderBinary loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
String r = loader.recognize(f);
return ClassDB::get_compatibility_remapped_class(r);
}
@@ -1330,15 +1362,14 @@ ResourceUID::ID ResourceFormatLoaderBinary::get_resource_uid(const String &p_pat
return ResourceUID::INVALID_ID;
}
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
return ResourceUID::INVALID_ID; //could not read
}
ResourceLoaderBinary loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
- //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
loader.open(f, true);
if (loader.error != OK) {
return ResourceUID::INVALID_ID; //could not read
@@ -1350,7 +1381,7 @@ ResourceUID::ID ResourceFormatLoaderBinary::get_resource_uid(const String &p_pat
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
-void ResourceFormatSaverBinaryInstance::_pad_buffer(FileAccess *f, int p_bytes) {
+void ResourceFormatSaverBinaryInstance::_pad_buffer(Ref<FileAccess> f, int p_bytes) {
int extra = 4 - (p_bytes % 4);
if (extra < 4) {
for (int i = 0; i < extra; i++) {
@@ -1359,7 +1390,7 @@ void ResourceFormatSaverBinaryInstance::_pad_buffer(FileAccess *f, int p_bytes)
}
}
-void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) {
+void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const Variant &p_property, Map<Ref<Resource>, int> &resource_map, Map<Ref<Resource>, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) {
switch (p_property.get_type()) {
case Variant::NIL: {
f->store_32(VARIANT_NIL);
@@ -1480,40 +1511,40 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
case Variant::TRANSFORM2D: {
f->store_32(VARIANT_TRANSFORM2D);
Transform2D val = p_property;
- f->store_real(val.elements[0].x);
- f->store_real(val.elements[0].y);
- f->store_real(val.elements[1].x);
- f->store_real(val.elements[1].y);
- f->store_real(val.elements[2].x);
- f->store_real(val.elements[2].y);
+ f->store_real(val.columns[0].x);
+ f->store_real(val.columns[0].y);
+ f->store_real(val.columns[1].x);
+ f->store_real(val.columns[1].y);
+ f->store_real(val.columns[2].x);
+ f->store_real(val.columns[2].y);
} break;
case Variant::BASIS: {
f->store_32(VARIANT_BASIS);
Basis val = p_property;
- f->store_real(val.elements[0].x);
- f->store_real(val.elements[0].y);
- f->store_real(val.elements[0].z);
- f->store_real(val.elements[1].x);
- f->store_real(val.elements[1].y);
- f->store_real(val.elements[1].z);
- f->store_real(val.elements[2].x);
- f->store_real(val.elements[2].y);
- f->store_real(val.elements[2].z);
+ f->store_real(val.rows[0].x);
+ f->store_real(val.rows[0].y);
+ f->store_real(val.rows[0].z);
+ f->store_real(val.rows[1].x);
+ f->store_real(val.rows[1].y);
+ f->store_real(val.rows[1].z);
+ f->store_real(val.rows[2].x);
+ f->store_real(val.rows[2].y);
+ f->store_real(val.rows[2].z);
} break;
case Variant::TRANSFORM3D: {
f->store_32(VARIANT_TRANSFORM3D);
Transform3D val = p_property;
- f->store_real(val.basis.elements[0].x);
- f->store_real(val.basis.elements[0].y);
- f->store_real(val.basis.elements[0].z);
- f->store_real(val.basis.elements[1].x);
- f->store_real(val.basis.elements[1].y);
- f->store_real(val.basis.elements[1].z);
- f->store_real(val.basis.elements[2].x);
- f->store_real(val.basis.elements[2].y);
- f->store_real(val.basis.elements[2].z);
+ f->store_real(val.basis.rows[0].x);
+ f->store_real(val.basis.rows[0].y);
+ f->store_real(val.basis.rows[0].z);
+ f->store_real(val.basis.rows[1].x);
+ f->store_real(val.basis.rows[1].y);
+ f->store_real(val.basis.rows[1].z);
+ f->store_real(val.basis.rows[2].x);
+ f->store_real(val.basis.rows[2].y);
+ f->store_real(val.basis.rows[2].z);
f->store_real(val.origin.x);
f->store_real(val.origin.y);
f->store_real(val.origin.z);
@@ -1568,7 +1599,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
} break;
case Variant::OBJECT: {
f->store_32(VARIANT_OBJECT);
- RES res = p_property;
+ Ref<Resource> res = p_property;
if (res.is_null()) {
f->store_32(OBJECT_EMPTY);
return; // don't save it
@@ -1734,7 +1765,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant, bool p_main) {
switch (p_variant.get_type()) {
case Variant::OBJECT: {
- RES res = p_variant;
+ Ref<Resource> res = p_variant;
if (res.is_null() || external_resources.has(res)) {
return;
@@ -1762,7 +1793,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
if (E.usage & PROPERTY_USAGE_STORAGE) {
Variant value = res->get(E.name);
if (E.usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) {
- RES sres = value;
+ Ref<Resource> sres = value;
if (sres.is_valid()) {
NonPersistentKey npk;
npk.base = res;
@@ -1818,14 +1849,14 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
}
}
-void ResourceFormatSaverBinaryInstance::save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len) {
+void ResourceFormatSaverBinaryInstance::save_unicode_string(Ref<FileAccess> p_f, const String &p_string, bool p_bit_on_len) {
CharString utf8 = p_string.utf8();
if (p_bit_on_len) {
- f->store_32((utf8.length() + 1) | 0x80000000);
+ p_f->store_32((utf8.length() + 1) | 0x80000000);
} else {
- f->store_32(utf8.length() + 1);
+ p_f->store_32(utf8.length() + 1);
}
- f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
+ p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
}
int ResourceFormatSaverBinaryInstance::get_string_index(const String &p_string) {
@@ -1839,17 +1870,24 @@ int ResourceFormatSaverBinaryInstance::get_string_index(const String &p_string)
return strings.size() - 1;
}
-Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+static String _resource_get_class(Ref<Resource> p_resource) {
+ Ref<MissingResource> missing_resource = p_resource;
+ if (missing_resource.is_valid()) {
+ return missing_resource->get_original_class();
+ } else {
+ return p_resource->get_class();
+ }
+}
+
+Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Error err;
+ Ref<FileAccess> f;
if (p_flags & ResourceSaver::FLAG_COMPRESS) {
- FileAccessCompressed *fac = memnew(FileAccessCompressed);
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
fac->configure("RSCC");
f = fac;
err = fac->_open(p_path, FileAccess::WRITE);
- if (err) {
- memdelete(f);
- }
-
} else {
f = FileAccess::open(p_path, FileAccess::WRITE, &err);
}
@@ -1890,14 +1928,18 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
f->store_32(FORMAT_VERSION);
if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) {
- f->close();
- memdelete(f);
return ERR_CANT_CREATE;
}
- save_unicode_string(f, p_resource->get_class());
+ save_unicode_string(f, _resource_get_class(p_resource));
f->store_64(0); //offset to import metadata
- f->store_32(FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS);
+ {
+ uint32_t format_flags = FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS;
+#ifdef REAL_T_IS_DOUBLE
+ format_flags |= FORMAT_FLAG_REAL_T_IS_DOUBLE;
+#endif
+ f->store_32(format_flags);
+ }
ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(p_path, true);
f->store_64(uid);
for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) {
@@ -1906,10 +1948,12 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
List<ResourceData> resources;
+ Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary());
+
{
- for (const RES &E : saved_resources) {
+ for (const Ref<Resource> &E : saved_resources) {
ResourceData &rd = resources.push_back(ResourceData())->get();
- rd.type = E->get_class();
+ rd.type = _resource_get_class(E);
List<PropertyInfo> property_list;
E->get_property_list(&property_list);
@@ -1918,6 +1962,10 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
if (skip_editor && F.name.begins_with("__editor")) {
continue;
}
+ if (F.name == META_PROPERTY_MISSING_RESOURCES) {
+ continue;
+ }
+
if ((F.usage & PROPERTY_USAGE_STORAGE)) {
Property p;
p.name_idx = get_string_index(F.name);
@@ -1933,6 +1981,14 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
p.value = E->get(F.name);
}
+ if (p.pi.type == Variant::OBJECT && missing_resource_properties.has(F.name)) {
+ // Was this missing resource overriden? If so do not save the old value.
+ Ref<Resource> res = p.value;
+ if (res.is_null()) {
+ p.value = missing_resource_properties[F.name];
+ }
+ }
+
Variant default_value = ClassDB::class_get_default_property_value(E->get_class(), F.name);
if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, p.value, default_value))) {
@@ -1954,10 +2010,10 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
// save external resource table
f->store_32(external_resources.size()); //amount of external resources
- Vector<RES> save_order;
+ Vector<Ref<Resource>> save_order;
save_order.resize(external_resources.size());
- for (const KeyValue<RES, int> &E : external_resources) {
+ for (const KeyValue<Ref<Resource>, int> &E : external_resources) {
save_order.write[E.value] = E.key;
}
@@ -1974,7 +2030,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
Vector<uint64_t> ofs_pos;
Set<String> used_unique_ids;
- for (RES &r : saved_resources) {
+ for (Ref<Resource> &r : saved_resources) {
if (r->is_built_in()) {
if (!r->get_scene_unique_id().is_empty()) {
if (used_unique_ids.has(r->get_scene_unique_id())) {
@@ -1986,15 +2042,15 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
}
}
- Map<RES, int> resource_map;
+ Map<Ref<Resource>, int> resource_map;
int res_index = 0;
- for (RES &r : saved_resources) {
+ for (Ref<Resource> &r : saved_resources) {
if (r->is_built_in()) {
if (r->get_scene_unique_id().is_empty()) {
String new_id;
while (true) {
- new_id = r->get_class() + "_" + Resource::generate_scene_unique_id();
+ new_id = _resource_get_class(r) + "_" + Resource::generate_scene_unique_id();
if (!used_unique_ids.has(new_id)) {
break;
}
@@ -2043,28 +2099,23 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
f->store_buffer((const uint8_t *)"RSRC", 4); //magic at end
if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) {
- f->close();
- memdelete(f);
return ERR_CANT_CREATE;
}
- f->close();
- memdelete(f);
-
return OK;
}
-Error ResourceFormatSaverBinary::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverBinary::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
String local_path = ProjectSettings::get_singleton()->localize_path(p_path);
ResourceFormatSaverBinaryInstance saver;
return saver.save(local_path, p_resource, p_flags);
}
-bool ResourceFormatSaverBinary::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverBinary::recognize(const Ref<Resource> &p_resource) const {
return true; //all recognized
}
-void ResourceFormatSaverBinary::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverBinary::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
String base = p_resource->get_base_extension().to_lower();
p_extensions->push_back(base);
if (base != "res") {
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index ecc3e95f6b..92d4e4eeaa 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -43,14 +43,14 @@ class ResourceLoaderBinary {
Ref<Resource> resource;
uint32_t ver_format = 0;
- FileAccess *f = nullptr;
+ Ref<FileAccess> f;
uint64_t importmd_ofs = 0;
ResourceUID::ID uid = ResourceUID::INVALID_ID;
Vector<char> str_buf;
- List<RES> resource_cache;
+ List<Ref<Resource>> resource_cache;
Vector<StringName> string_map;
@@ -60,7 +60,7 @@ class ResourceLoaderBinary {
String path;
String type;
ResourceUID::ID uid = ResourceUID::INVALID_ID;
- RES cache;
+ Ref<Resource> cache;
};
bool using_named_scene_ids = false;
@@ -75,7 +75,7 @@ class ResourceLoaderBinary {
};
Vector<IntResource> internal_resources;
- Map<String, RES> internal_index_cache;
+ Map<String, Ref<Resource>> internal_index_cache;
String get_unicode_string();
void _advance_padding(uint32_t p_len);
@@ -89,7 +89,7 @@ class ResourceLoaderBinary {
Error parse_variant(Variant &r_v);
- Map<String, RES> dependency_cache;
+ Map<String, Ref<Resource>> dependency_cache;
public:
void set_local_path(const String &p_local_path);
@@ -98,17 +98,16 @@ public:
void set_translation_remapped(bool p_remapped);
void set_remaps(const Map<String, String> &p_remaps) { remaps = p_remaps; }
- void open(FileAccess *p_f, bool p_no_resources = false, bool p_keep_uuid_paths = false);
- String recognize(FileAccess *p_f);
- void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
+ void open(Ref<FileAccess> p_f, bool p_no_resources = false, bool p_keep_uuid_paths = false);
+ String recognize(Ref<FileAccess> p_f);
+ void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types);
ResourceLoaderBinary() {}
- ~ResourceLoaderBinary();
};
class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
@@ -127,22 +126,21 @@ class ResourceFormatSaverBinaryInstance {
bool skip_editor;
bool big_endian;
bool takeover_paths;
- FileAccess *f;
String magic;
- Set<RES> resource_set;
+ Set<Ref<Resource>> resource_set;
struct NonPersistentKey { //for resource properties generated on the fly
- RES base;
+ Ref<Resource> base;
StringName property;
bool operator<(const NonPersistentKey &p_key) const { return base == p_key.base ? property < p_key.property : base < p_key.base; }
};
- Map<NonPersistentKey, RES> non_persistent_map;
+ Map<NonPersistentKey, Ref<Resource>> non_persistent_map;
Map<StringName, int> string_map;
Vector<StringName> strings;
- Map<RES, int> external_resources;
- List<RES> saved_resources;
+ Map<Ref<Resource>, int> external_resources;
+ List<Ref<Resource>> saved_resources;
struct Property {
int name_idx;
@@ -155,28 +153,30 @@ class ResourceFormatSaverBinaryInstance {
List<Property> properties;
};
- static void _pad_buffer(FileAccess *f, int p_bytes);
+ static void _pad_buffer(Ref<FileAccess> f, int p_bytes);
void _find_resources(const Variant &p_variant, bool p_main = false);
- static void save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false);
+ static void save_unicode_string(Ref<FileAccess> f, const String &p_string, bool p_bit_on_len = false);
int get_string_index(const String &p_string);
public:
enum {
FORMAT_FLAG_NAMED_SCENE_IDS = 1,
FORMAT_FLAG_UIDS = 2,
+ FORMAT_FLAG_REAL_T_IS_DOUBLE = 4,
+
// Amount of reserved 32-bit fields in resource header
RESERVED_FIELDS = 11
};
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- static void write_variant(FileAccess *f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo());
+ Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ static void write_variant(Ref<FileAccess> f, const Variant &p_property, Map<Ref<Resource>, int> &resource_map, Map<Ref<Resource>, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo());
};
class ResourceFormatSaverBinary : public ResourceFormatSaver {
public:
static ResourceFormatSaverBinary *singleton;
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual bool recognize(const RES &p_resource) const;
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
ResourceFormatSaverBinary();
};
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 9b6440e2a2..984cf06d2b 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -40,9 +40,9 @@ bool ResourceFormatImporter::SortImporterByName::operator()(const Ref<ResourceIm
Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const {
Error err;
- FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path + ".import", FileAccess::READ, &err);
- if (!f) {
+ if (f.is_null()) {
if (r_valid) {
*r_valid = false;
}
@@ -70,11 +70,9 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
- memdelete(f);
return OK;
} else if (err != OK) {
ERR_PRINT("ResourceFormatImporter::load - " + p_path + ".import:" + itos(lines) + " error: " + error_text);
- memdelete(f);
return err;
}
@@ -110,15 +108,13 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
}
}
- memdelete(f);
-
if (r_path_and_type.path.is_empty() || r_path_and_type.type.is_empty()) {
return ERR_FILE_CORRUPT;
}
return OK;
}
-RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
PathAndType pat;
Error err = _get_path_and_type(p_path, pat);
@@ -127,10 +123,10 @@ RES ResourceFormatImporter::load(const String &p_path, const String &p_original_
*r_error = err;
}
- return RES();
+ return Ref<Resource>();
}
- RES res = ResourceLoader::_load(pat.path, p_path, pat.type, p_cache_mode, r_error, p_use_sub_threads, r_progress);
+ Ref<Resource> res = ResourceLoader::_load(pat.path, p_path, pat.type, p_cache_mode, r_error, p_use_sub_threads, r_progress);
#ifdef TOOLS_ENABLED
if (res.is_valid()) {
@@ -270,9 +266,9 @@ String ResourceFormatImporter::get_internal_resource_path(const String &p_path)
void ResourceFormatImporter::get_internal_resource_path_list(const String &p_path, List<String> *r_paths) {
Error err;
- FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path + ".import", FileAccess::READ, &err);
- if (!f) {
+ if (f.is_null()) {
return;
}
@@ -292,11 +288,9 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat
err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
- memdelete(f);
return;
} else if (err != OK) {
ERR_PRINT("ResourceFormatImporter::get_internal_resource_path_list - " + p_path + ".import:" + itos(lines) + " error: " + error_text);
- memdelete(f);
return;
}
@@ -310,7 +304,6 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat
break;
}
}
- memdelete(f);
}
String ResourceFormatImporter::get_import_group_file(const String &p_path) const {
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 2fffc16ad8..b3d777847b 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -58,7 +58,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
public:
static ResourceFormatImporter *get_singleton() { return singleton; }
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 2419c76dd3..d125dd4e91 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -125,14 +125,14 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions)
}
}
-RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Variant res;
if (GDVIRTUAL_CALL(_load, p_path, p_original_path, p_use_sub_threads, p_cache_mode, res)) {
if (res.get_type() == Variant::INT) { // Error code, abort.
if (r_error) {
*r_error = (Error)res.operator int64_t();
}
- return RES();
+ return Ref<Resource>();
} else { // Success, pass on result.
if (r_error) {
*r_error = OK;
@@ -141,7 +141,7 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa
}
}
- ERR_FAIL_V_MSG(RES(), "Failed to load resource '" + p_path + "'. ResourceFormatLoader::load was not implemented for this resource type.");
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Failed to load resource '" + p_path + "'. ResourceFormatLoader::load was not implemented for this resource type.");
}
void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
@@ -185,7 +185,7 @@ void ResourceFormatLoader::_bind_methods() {
///////////////////////////////////
-RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
+Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
bool found = false;
// Try all loaders and pick the first match for the type hint
@@ -194,7 +194,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
continue;
}
found = true;
- RES res = loader[i]->load(p_path, !p_original_path.is_empty() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
+ Ref<Resource> res = loader[i]->load(p_path, !p_original_path.is_empty() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
if (res.is_null()) {
continue;
}
@@ -202,15 +202,15 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
return res;
}
- ERR_FAIL_COND_V_MSG(found, RES(),
+ ERR_FAIL_COND_V_MSG(found, Ref<Resource>(),
vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path));
#ifdef TOOLS_ENABLED
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), RES(), "Resource file not found: " + p_path + ".");
+ Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+ ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), Ref<Resource>(), "Resource file not found: " + p_path + ".");
#endif
- ERR_FAIL_V_MSG(RES(), "No loader found for resource: " + p_path + ".");
+ ERR_FAIL_V_MSG(Ref<Resource>(), "No loader found for resource: " + p_path + ".");
}
void ResourceLoader::_thread_load_function(void *p_userdata) {
@@ -342,7 +342,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
Resource **rptr = ResourceCache::resources.getptr(local_path);
if (rptr) {
- RES res(*rptr);
+ Ref<Resource> res(*rptr);
//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
if (res.is_valid()) {
//referencing is fine
@@ -427,7 +427,7 @@ ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const
return status;
}
-RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
+Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
String local_path = _validate_local_path(p_path);
thread_load_mutex->lock();
@@ -436,7 +436,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
if (r_error) {
*r_error = ERR_INVALID_PARAMETER;
}
- return RES();
+ return Ref<Resource>();
}
ThreadLoadTask &load_task = thread_load_tasks[local_path];
@@ -480,11 +480,11 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
if (r_error) {
*r_error = ERR_INVALID_PARAMETER;
}
- return RES();
+ return Ref<Resource>();
}
}
- RES resource = load_task.resource;
+ Ref<Resource> resource = load_task.resource;
if (r_error) {
*r_error = load_task.error;
}
@@ -504,7 +504,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
return resource;
}
-RES ResourceLoader::load(const String &p_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
+Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
@@ -522,7 +522,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, Resour
*r_error = err;
}
thread_load_mutex->unlock();
- return RES();
+ return Ref<Resource>();
}
thread_load_mutex->unlock();
@@ -535,7 +535,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, Resour
Resource **rptr = ResourceCache::resources.getptr(local_path);
if (rptr) {
- RES res(*rptr);
+ Ref<Resource> res(*rptr);
//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
if (res.is_valid()) {
@@ -575,16 +575,16 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, Resour
String path = _path_remap(local_path, &xl_remapped);
if (path.is_empty()) {
- ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed.");
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Remapping '" + local_path + "' failed.");
}
print_verbose("Loading resource: " + path);
float p;
- RES res = _load(path, local_path, p_type_hint, p_cache_mode, r_error, false, &p);
+ Ref<Resource> res = _load(path, local_path, p_type_hint, p_cache_mode, r_error, false, &p);
if (res.is_null()) {
print_verbose("Failed loading resource: " + path);
- return RES();
+ return Ref<Resource>();
}
if (xl_remapped) {
@@ -817,9 +817,8 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
if (new_path == p_path) { // Did not remap.
// Try file remap.
Error err;
- FileAccess *f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err);
-
- if (f) {
+ Ref<FileAccess> f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err);
+ if (f.is_valid()) {
VariantParser::StreamFile stream;
stream.f = f;
@@ -849,8 +848,6 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
break;
}
}
-
- memdelete(f);
}
}
@@ -982,6 +979,10 @@ void ResourceLoader::remove_custom_resource_format_loader(String script_path) {
}
}
+void ResourceLoader::set_create_missing_resources_if_class_unavailable(bool p_enable) {
+ create_missing_resources_if_class_unavailable = p_enable;
+}
+
void ResourceLoader::add_custom_loaders() {
// Custom loaders registration exploits global class names
@@ -1033,6 +1034,7 @@ void *ResourceLoader::err_notify_ud = nullptr;
DependencyErrorNotify ResourceLoader::dep_err_notify = nullptr;
void *ResourceLoader::dep_err_notify_ud = nullptr;
+bool ResourceLoader::create_missing_resources_if_class_unavailable = false;
bool ResourceLoader::abort_on_missing_resource = true;
bool ResourceLoader::timestamp_on_load = false;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index a3fdefa0f1..ea18ac23fd 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -61,7 +61,7 @@ protected:
GDVIRTUAL4RC(Variant, _load, String, String, bool, int)
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual bool exists(const String &p_path) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
@@ -85,7 +85,7 @@ typedef void (*ResourceLoadErrorNotify)(void *p_ud, const String &p_text);
typedef void (*DependencyErrorNotify)(void *p_ud, const String &p_loading, const String &p_which, const String &p_type);
typedef Error (*ResourceLoaderImport)(const String &p_path);
-typedef void (*ResourceLoadedCallback)(RES p_resource, const String &p_path);
+typedef void (*ResourceLoadedCallback)(Ref<Resource> p_resource, const String &p_path);
class ResourceLoader {
enum {
@@ -110,6 +110,7 @@ private:
static void *dep_err_notify_ud;
static DependencyErrorNotify dep_err_notify;
static bool abort_on_missing_resource;
+ static bool create_missing_resources_if_class_unavailable;
static HashMap<String, Vector<String>> translation_remaps;
static HashMap<String, String> path_remaps;
@@ -121,7 +122,7 @@ private:
friend class ResourceFormatImporter;
friend class ResourceInteractiveLoader;
// Internal load function.
- static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress);
+ static Ref<Resource> _load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress);
static ResourceLoadedCallback _loaded_callback;
@@ -138,7 +139,7 @@ private:
ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
Error error = OK;
- RES resource;
+ Ref<Resource> resource;
bool xl_remapped = false;
bool use_sub_threads = false;
bool start_next = true;
@@ -161,9 +162,9 @@ private:
public:
static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, const String &p_source_resource = String());
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
- static RES load_threaded_get(const String &p_path, Error *r_error = nullptr);
+ static Ref<Resource> load_threaded_get(const String &p_path, Error *r_error = nullptr);
- static RES load(const String &p_path, const String &p_type_hint = "", ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, Error *r_error = nullptr);
+ static Ref<Resource> load(const String &p_path, const String &p_type_hint = "", ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, Error *r_error = nullptr);
static bool exists(const String &p_path, const String &p_type_hint = "");
static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions);
@@ -222,6 +223,9 @@ public:
static void add_custom_loaders();
static void remove_custom_loaders();
+ static void set_create_missing_resources_if_class_unavailable(bool p_enable);
+ _FORCE_INLINE_ static bool is_creating_missing_resources_if_class_unavailable_enabled() { return create_missing_resources_if_class_unavailable; }
+
static void initialize();
static void finalize();
};
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index c883e8502f..2f5c5b54dd 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -41,7 +41,7 @@ bool ResourceSaver::timestamp_on_save = false;
ResourceSavedCallback ResourceSaver::save_callback = nullptr;
ResourceSaverGetResourceIDForPath ResourceSaver::save_get_id_for_path = nullptr;
-Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaver::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
int64_t res;
if (GDVIRTUAL_CALL(_save, p_path, p_resource, p_flags, res)) {
return (Error)res;
@@ -50,7 +50,7 @@ Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uin
return ERR_METHOD_NOT_FOUND;
}
-bool ResourceFormatSaver::recognize(const RES &p_resource) const {
+bool ResourceFormatSaver::recognize(const Ref<Resource> &p_resource) const {
bool success;
if (GDVIRTUAL_CALL(_recognize, p_resource, success)) {
return success;
@@ -59,7 +59,7 @@ bool ResourceFormatSaver::recognize(const RES &p_resource) const {
return false;
}
-void ResourceFormatSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
PackedStringArray exts;
if (GDVIRTUAL_CALL(_get_recognized_extensions, p_resource, exts)) {
const String *r = exts.ptr();
@@ -75,7 +75,7 @@ void ResourceFormatSaver::_bind_methods() {
GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
}
-Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceSaver::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
String extension = p_path.get_extension();
Error err = ERR_FILE_UNRECOGNIZED;
@@ -102,7 +102,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t
String local_path = ProjectSettings::get_singleton()->localize_path(p_path);
- RES rwcopy = p_resource;
+ Ref<Resource> rwcopy = p_resource;
if (p_flags & FLAG_CHANGE_PATH) {
rwcopy->set_path(local_path);
}
@@ -139,7 +139,7 @@ void ResourceSaver::set_save_callback(ResourceSavedCallback p_callback) {
save_callback = p_callback;
}
-void ResourceSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) {
+void ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) {
for (int i = 0; i < saver_count; i++) {
saver[i]->get_recognized_extensions(p_resource, p_extensions);
}
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 2919a4cec0..088317bfbe 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -41,14 +41,14 @@ class ResourceFormatSaver : public RefCounted {
protected:
static void _bind_methods();
- GDVIRTUAL3R(int64_t, _save, String, RES, uint32_t)
- GDVIRTUAL1RC(bool, _recognize, RES)
- GDVIRTUAL1RC(Vector<String>, _get_recognized_extensions, RES)
+ GDVIRTUAL3R(int64_t, _save, String, Ref<Resource>, uint32_t)
+ GDVIRTUAL1RC(bool, _recognize, Ref<Resource>)
+ GDVIRTUAL1RC(Vector<String>, _get_recognized_extensions, Ref<Resource>)
public:
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual bool recognize(const RES &p_resource) const;
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
virtual ~ResourceFormatSaver() {}
};
@@ -71,6 +71,7 @@ class ResourceSaver {
public:
enum SaverFlags {
+ FLAG_NONE = 0,
FLAG_RELATIVE_PATHS = 1,
FLAG_BUNDLE_RESOURCES = 2,
FLAG_CHANGE_PATH = 4,
@@ -80,8 +81,8 @@ public:
FLAG_REPLACE_SUBRESOURCE_PATHS = 64,
};
- static Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- static void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions);
+ static Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = (uint32_t)FLAG_NONE);
+ static void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions);
static void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front = false);
static void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index d0335bed3a..515b7c710e 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -135,12 +135,12 @@ void ResourceUID::remove_id(ID p_id) {
Error ResourceUID::save_to_cache() {
String cache_file = get_cache_file();
if (!FileAccess::exists(cache_file)) {
- DirAccessRef d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
d->make_dir_recursive(String(cache_file).get_base_dir()); //ensure base dir exists
}
- FileAccessRef f = FileAccess::open(cache_file, FileAccess::WRITE);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(cache_file, FileAccess::WRITE);
+ if (f.is_null()) {
return ERR_CANT_OPEN;
}
@@ -163,8 +163,8 @@ Error ResourceUID::save_to_cache() {
}
Error ResourceUID::load_from_cache() {
- FileAccessRef f = FileAccess::open(get_cache_file(), FileAccess::READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(get_cache_file(), FileAccess::READ);
+ if (f.is_null()) {
return ERR_CANT_OPEN;
}
@@ -201,12 +201,12 @@ Error ResourceUID::update_cache() {
}
MutexLock l(mutex);
- FileAccess *f = nullptr;
+ Ref<FileAccess> f;
for (OrderedHashMap<ID, Cache>::Element E = unique_ids.front(); E; E = E.next()) {
if (!E.get().saved_to_cache) {
- if (f == nullptr) {
+ if (f.is_null()) {
f = FileAccess::open(get_cache_file(), FileAccess::READ_WRITE); //append
- if (!f) {
+ if (f.is_null()) {
return ERR_CANT_OPEN;
}
f->seek_end();
@@ -220,11 +220,9 @@ Error ResourceUID::update_cache() {
}
}
- if (f != nullptr) {
+ if (f.is_valid()) {
f->seek(0);
f->store_32(cache_entries); //update amount of entries
- f->close();
- memdelete(f);
}
changed = false;
diff --git a/core/io/resource_uid.h b/core/io/resource_uid.h
index 1ea44b9d06..0b7ffdf6d0 100644
--- a/core/io/resource_uid.h
+++ b/core/io/resource_uid.h
@@ -46,7 +46,7 @@ public:
static String get_cache_file();
private:
- void *crypto; // CryptoCore::RandomGenerator (avoid including crypto_core.h)
+ void *crypto = nullptr; // CryptoCore::RandomGenerator (avoid including crypto_core.h)
Mutex mutex;
struct Cache {
CharString cs;
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index e71941b7e1..4609e52aa2 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -39,7 +39,6 @@
class StreamPeer : public RefCounted {
GDCLASS(StreamPeer, RefCounted);
- OBJ_CATEGORY("Networking");
protected:
static void _bind_methods();
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index 6d5784a8ab..ba79590c19 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -32,8 +32,28 @@
#include "core/config/project_settings.h"
-Error StreamPeerTCP::_poll_connection() {
- ERR_FAIL_COND_V(status != STATUS_CONNECTING || !_sock.is_valid() || !_sock->is_open(), FAILED);
+Error StreamPeerTCP::poll() {
+ if (status == STATUS_CONNECTED) {
+ Error err;
+ err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
+ if (err == OK) {
+ // FIN received
+ if (_sock->get_available_bytes() == 0) {
+ disconnect_from_host();
+ return OK;
+ }
+ }
+ // Also poll write
+ err = _sock->poll(NetSocket::POLL_TYPE_IN_OUT, 0);
+ if (err != OK && err != ERR_BUSY) {
+ // Got an error
+ disconnect_from_host();
+ status = STATUS_ERROR;
+ return err;
+ }
+ } else if (status != STATUS_CONNECTING) {
+ return OK;
+ }
Error err = _sock->connect_to_host(peer_host, peer_port);
@@ -61,7 +81,7 @@ void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IPAddress p_host, uint1
_sock->set_blocking_enabled(false);
timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/tcp/connect_timeout_seconds")) * 1000);
- status = STATUS_CONNECTING;
+ status = STATUS_CONNECTED;
peer_host = p_host;
peer_port = p_port;
@@ -121,22 +141,7 @@ Error StreamPeerTCP::connect_to_host(const IPAddress &p_host, int p_port) {
Error StreamPeerTCP::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
- if (status == STATUS_NONE || status == STATUS_ERROR) {
- return FAILED;
- }
-
if (status != STATUS_CONNECTED) {
- if (_poll_connection() != OK) {
- return FAILED;
- }
-
- if (status != STATUS_CONNECTED) {
- r_sent = 0;
- return OK;
- }
- }
-
- if (!_sock->is_open()) {
return FAILED;
}
@@ -179,21 +184,10 @@ Error StreamPeerTCP::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool
}
Error StreamPeerTCP::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) {
- if (!is_connected_to_host()) {
+ if (status != STATUS_CONNECTED) {
return FAILED;
}
- if (status == STATUS_CONNECTING) {
- if (_poll_connection() != OK) {
- return FAILED;
- }
-
- if (status != STATUS_CONNECTED) {
- r_received = 0;
- return OK;
- }
- }
-
Error err;
int to_read = p_bytes;
int total_read = 0;
@@ -243,36 +237,11 @@ Error StreamPeerTCP::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool
}
void StreamPeerTCP::set_no_delay(bool p_enabled) {
- ERR_FAIL_COND(!is_connected_to_host());
+ ERR_FAIL_COND(!_sock.is_valid() || !_sock->is_open());
_sock->set_tcp_no_delay_enabled(p_enabled);
}
-bool StreamPeerTCP::is_connected_to_host() const {
- return _sock.is_valid() && _sock->is_open() && (status == STATUS_CONNECTED || status == STATUS_CONNECTING);
-}
-
-StreamPeerTCP::Status StreamPeerTCP::get_status() {
- if (status == STATUS_CONNECTING) {
- _poll_connection();
- } else if (status == STATUS_CONNECTED) {
- Error err;
- err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
- if (err == OK) {
- // FIN received
- if (_sock->get_available_bytes() == 0) {
- disconnect_from_host();
- return status;
- }
- }
- // Also poll write
- err = _sock->poll(NetSocket::POLL_TYPE_IN_OUT, 0);
- if (err != OK && err != ERR_BUSY) {
- // Got an error
- disconnect_from_host();
- status = STATUS_ERROR;
- }
- }
-
+StreamPeerTCP::Status StreamPeerTCP::get_status() const {
return status;
}
@@ -287,7 +256,7 @@ void StreamPeerTCP::disconnect_from_host() {
peer_port = 0;
}
-Error StreamPeerTCP::poll(NetSocket::PollType p_type, int timeout) {
+Error StreamPeerTCP::wait(NetSocket::PollType p_type, int timeout) {
ERR_FAIL_COND_V(_sock.is_null() || !_sock->is_open(), ERR_UNAVAILABLE);
return _sock->poll(p_type, timeout);
}
@@ -346,7 +315,7 @@ Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
void StreamPeerTCP::_bind_methods() {
ClassDB::bind_method(D_METHOD("bind", "port", "host"), &StreamPeerTCP::bind, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &StreamPeerTCP::_connect);
- ClassDB::bind_method(D_METHOD("is_connected_to_host"), &StreamPeerTCP::is_connected_to_host);
+ ClassDB::bind_method(D_METHOD("poll"), &StreamPeerTCP::poll);
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerTCP::get_status);
ClassDB::bind_method(D_METHOD("get_connected_host"), &StreamPeerTCP::get_connected_host);
ClassDB::bind_method(D_METHOD("get_connected_port"), &StreamPeerTCP::get_connected_port);
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index f2c47b25cf..39c2e84346 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -38,7 +38,6 @@
class StreamPeerTCP : public StreamPeer {
GDCLASS(StreamPeerTCP, StreamPeer);
- OBJ_CATEGORY("Networking");
public:
enum Status {
@@ -56,7 +55,6 @@ protected:
uint16_t peer_port = 0;
Error _connect(const String &p_address, int p_port);
- Error _poll_connection();
Error write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block);
Error read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block);
@@ -67,19 +65,21 @@ public:
Error bind(int p_port, const IPAddress &p_host);
Error connect_to_host(const IPAddress &p_host, int p_port);
- bool is_connected_to_host() const;
IPAddress get_connected_host() const;
int get_connected_port() const;
int get_local_port() const;
void disconnect_from_host();
int get_available_bytes() const override;
- Status get_status();
+ Status get_status() const;
void set_no_delay(bool p_enabled);
- // Poll functions (wait or check for writable, readable)
- Error poll(NetSocket::PollType p_type, int timeout = 0);
+ // Poll socket updating its state.
+ Error poll();
+
+ // Wait or check for writable, readable.
+ Error wait(NetSocket::PollType p_type, int timeout = 0);
// Read/Write from StreamPeer
Error put_data(const uint8_t *p_data, int p_bytes) override;
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 8d3e58cad1..f36eb7c763 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -34,226 +34,293 @@
#include "core/string/translation.h"
#include "core/string/translation_po.h"
-RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
- enum Status {
- STATUS_NONE,
- STATUS_READING_ID,
- STATUS_READING_STRING,
- STATUS_READING_CONTEXT,
- STATUS_READING_PLURAL,
- };
-
- Status status = STATUS_NONE;
-
- String msg_id;
- String msg_str;
- String msg_context;
- Vector<String> msgs_plural;
- String config;
-
+Ref<Resource> TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_error) {
if (r_error) {
*r_error = ERR_FILE_CORRUPT;
}
- Ref<TranslationPO> translation = Ref<TranslationPO>(memnew(TranslationPO));
- int line = 1;
- int plural_forms = 0;
- int plural_index = -1;
- bool entered_context = false;
- bool skip_this = false;
- bool skip_next = false;
- bool is_eof = false;
const String path = f->get_path();
+ Ref<TranslationPO> translation = Ref<TranslationPO>(memnew(TranslationPO));
+ String config;
- while (!is_eof) {
- String l = f->get_line().strip_edges();
- is_eof = f->eof_reached();
-
- // If we reached last line and it's not a content line, break, otherwise let processing that last loop
- if (is_eof && l.is_empty()) {
- if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || (status == STATUS_READING_PLURAL && plural_index != plural_forms - 1)) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading PO file at: " + path + ":" + itos(line));
- } else {
- break;
- }
- }
-
- if (l.begins_with("msgctxt")) {
- if (status != STATUS_READING_STRING && status != STATUS_READING_PLURAL) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line));
+ uint32_t magic = f->get_32();
+ if (magic == 0x950412de) {
+ // Load binary MO file.
+
+ uint16_t version_maj = f->get_16();
+ uint16_t version_min = f->get_16();
+ ERR_FAIL_COND_V_MSG(version_maj > 1, Ref<Resource>(), vformat("Unsupported MO file %s, version %d.%d.", path, version_maj, version_min));
+
+ uint32_t num_strings = f->get_32();
+ uint32_t id_table_offset = f->get_32();
+ uint32_t trans_table_offset = f->get_32();
+
+ // Read string tables.
+ for (uint32_t i = 0; i < num_strings; i++) {
+ String msg_id;
+ String msg_id_plural;
+ String msg_context;
+
+ // Read id strings and context.
+ {
+ Vector<uint8_t> data;
+ f->seek(id_table_offset + i * 8);
+ uint32_t str_start = 0;
+ uint32_t str_len = f->get_32();
+ uint32_t str_offset = f->get_32();
+
+ data.resize(str_len + 1);
+ f->seek(str_offset);
+ f->get_buffer(data.ptrw(), str_len);
+ data.write[str_len] = 0;
+
+ bool is_plural = false;
+ for (uint32_t j = 0; j < str_len + 1; j++) {
+ if (data[j] == 0x04) {
+ msg_context.parse_utf8((const char *)data.ptr(), j);
+ str_start = j + 1;
+ }
+ if (data[j] == 0x00) {
+ if (is_plural) {
+ msg_id_plural.parse_utf8((const char *)(data.ptr() + str_start), j - str_start);
+ } else {
+ msg_id.parse_utf8((const char *)(data.ptr() + str_start), j - str_start);
+ is_plural = true;
+ }
+ str_start = j + 1;
+ }
+ }
}
- // In PO file, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read
- // and set "entered_context" to true to prevent adding twice.
- if (!skip_this && !msg_id.is_empty()) {
- if (status == STATUS_READING_STRING) {
- translation->add_message(msg_id, msg_str, msg_context);
- } else if (status == STATUS_READING_PLURAL) {
- if (plural_index != plural_forms - 1) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
+ // Read translated strings.
+ {
+ Vector<uint8_t> data;
+ f->seek(trans_table_offset + i * 8);
+ uint32_t str_len = f->get_32();
+ uint32_t str_offset = f->get_32();
+
+ data.resize(str_len + 1);
+ f->seek(str_offset);
+ f->get_buffer(data.ptrw(), str_len);
+ data.write[str_len] = 0;
+
+ if (msg_id.is_empty()) {
+ config = String::utf8((const char *)data.ptr(), str_len);
+ // Record plural rule.
+ int p_start = config.find("Plural-Forms");
+ if (p_start != -1) {
+ int p_end = config.find("\n", p_start);
+ translation->set_plural_rule(config.substr(p_start, p_end - p_start));
+ }
+ } else {
+ uint32_t str_start = 0;
+ Vector<String> plural_msg;
+ for (uint32_t j = 0; j < str_len + 1; j++) {
+ if (data[j] == 0x00) {
+ if (msg_id_plural.is_empty()) {
+ translation->add_message(msg_id, String::utf8((const char *)(data.ptr() + str_start), j - str_start), msg_context);
+ } else {
+ plural_msg.push_back(String::utf8((const char *)(data.ptr() + str_start), j - str_start));
+ }
+ str_start = j + 1;
+ }
+ }
+ if (!plural_msg.is_empty()) {
+ translation->add_plural_message(msg_id, plural_msg, msg_context);
}
- translation->add_plural_message(msg_id, msgs_plural, msg_context);
}
}
- msg_context = "";
- l = l.substr(7, l.length()).strip_edges();
- status = STATUS_READING_CONTEXT;
- entered_context = true;
}
- if (l.begins_with("msgid_plural")) {
- if (plural_forms == 0) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "PO file uses 'msgid_plural' but 'Plural-Forms' is invalid or missing in header: " + path + ":" + itos(line));
- } else if (status != STATUS_READING_ID) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line));
- }
- // We don't record the message in "msgid_plural" itself as tr_n(), TTRN(), RTRN() interfaces provide the plural string already.
- // We just have to reset variables related to plurals for "msgstr[]" later on.
- l = l.substr(12, l.length()).strip_edges();
- plural_index = -1;
- msgs_plural.clear();
- msgs_plural.resize(plural_forms);
- status = STATUS_READING_PLURAL;
- } else if (l.begins_with("msgid")) {
- if (status == STATUS_READING_ID) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line));
+ } else {
+ // Try to load as text PO file.
+ f->seek(0);
+
+ enum Status {
+ STATUS_NONE,
+ STATUS_READING_ID,
+ STATUS_READING_STRING,
+ STATUS_READING_CONTEXT,
+ STATUS_READING_PLURAL,
+ };
+
+ Status status = STATUS_NONE;
+
+ String msg_id;
+ String msg_str;
+ String msg_context;
+ Vector<String> msgs_plural;
+
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ }
+
+ int line = 1;
+ int plural_forms = 0;
+ int plural_index = -1;
+ bool entered_context = false;
+ bool skip_this = false;
+ bool skip_next = false;
+ bool is_eof = false;
+
+ while (!is_eof) {
+ String l = f->get_line().strip_edges();
+ is_eof = f->eof_reached();
+
+ // If we reached last line and it's not a content line, break, otherwise let processing that last loop
+ if (is_eof && l.is_empty()) {
+ if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || (status == STATUS_READING_PLURAL && plural_index != plural_forms - 1)) {
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Unexpected EOF while reading PO file at: " + path + ":" + itos(line));
+ } else {
+ break;
+ }
}
- if (!msg_id.is_empty()) {
- if (!skip_this && !entered_context) {
+ if (l.begins_with("msgctxt")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_STRING && status != STATUS_READING_PLURAL, Ref<Resource>(), "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line));
+
+ // In PO file, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read
+ // and set "entered_context" to true to prevent adding twice.
+ if (!skip_this && !msg_id.is_empty()) {
if (status == STATUS_READING_STRING) {
translation->add_message(msg_id, msg_str, msg_context);
} else if (status == STATUS_READING_PLURAL) {
- if (plural_index != plural_forms - 1) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
- }
+ ERR_FAIL_COND_V_MSG(plural_index != plural_forms - 1, Ref<Resource>(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
translation->add_plural_message(msg_id, msgs_plural, msg_context);
}
}
- } else if (config.is_empty()) {
- config = msg_str;
- // Record plural rule.
- int p_start = config.find("Plural-Forms");
- if (p_start != -1) {
- int p_end = config.find("\n", p_start);
- translation->set_plural_rule(config.substr(p_start, p_end - p_start));
- plural_forms = translation->get_plural_forms();
- }
- }
-
- l = l.substr(5, l.length()).strip_edges();
- status = STATUS_READING_ID;
- // If we did not encounter msgctxt, we reset context to empty to reset it.
- if (!entered_context) {
msg_context = "";
+ l = l.substr(7, l.length()).strip_edges();
+ status = STATUS_READING_CONTEXT;
+ entered_context = true;
}
- msg_id = "";
- msg_str = "";
- skip_this = skip_next;
- skip_next = false;
- entered_context = false;
- }
- if (l.begins_with("msgstr[")) {
- if (status != STATUS_READING_PLURAL) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line));
- }
- plural_index++; // Increment to add to the next slot in vector msgs_plural.
- l = l.substr(9, l.length()).strip_edges();
- } else if (l.begins_with("msgstr")) {
- if (status != STATUS_READING_ID) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line));
- }
-
- l = l.substr(6, l.length()).strip_edges();
- status = STATUS_READING_STRING;
- }
+ if (l.begins_with("msgid_plural")) {
+ if (plural_forms == 0) {
+ ERR_FAIL_V_MSG(Ref<Resource>(), "PO file uses 'msgid_plural' but 'Plural-Forms' is invalid or missing in header: " + path + ":" + itos(line));
+ } else if (status != STATUS_READING_ID) {
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line));
+ }
+ // We don't record the message in "msgid_plural" itself as tr_n(), TTRN(), RTRN() interfaces provide the plural string already.
+ // We just have to reset variables related to plurals for "msgstr[]" later on.
+ l = l.substr(12, l.length()).strip_edges();
+ plural_index = -1;
+ msgs_plural.clear();
+ msgs_plural.resize(plural_forms);
+ status = STATUS_READING_PLURAL;
+ } else if (l.begins_with("msgid")) {
+ ERR_FAIL_COND_V_MSG(status == STATUS_READING_ID, Ref<Resource>(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line));
+
+ if (!msg_id.is_empty()) {
+ if (!skip_this && !entered_context) {
+ if (status == STATUS_READING_STRING) {
+ translation->add_message(msg_id, msg_str, msg_context);
+ } else if (status == STATUS_READING_PLURAL) {
+ ERR_FAIL_COND_V_MSG(plural_index != plural_forms - 1, Ref<Resource>(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
+ translation->add_plural_message(msg_id, msgs_plural, msg_context);
+ }
+ }
+ } else if (config.is_empty()) {
+ config = msg_str;
+ // Record plural rule.
+ int p_start = config.find("Plural-Forms");
+ if (p_start != -1) {
+ int p_end = config.find("\n", p_start);
+ translation->set_plural_rule(config.substr(p_start, p_end - p_start));
+ plural_forms = translation->get_plural_forms();
+ }
+ }
- if (l.is_empty() || l.begins_with("#")) {
- if (l.contains("fuzzy")) {
- skip_next = true;
+ l = l.substr(5, l.length()).strip_edges();
+ status = STATUS_READING_ID;
+ // If we did not encounter msgctxt, we reset context to empty to reset it.
+ if (!entered_context) {
+ msg_context = "";
+ }
+ msg_id = "";
+ msg_str = "";
+ skip_this = skip_next;
+ skip_next = false;
+ entered_context = false;
}
- line++;
- continue; // Nothing to read or comment.
- }
- if (!l.begins_with("\"") || status == STATUS_NONE) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line));
- }
-
- l = l.substr(1, l.length());
- // Find final quote, ignoring escaped ones (\").
- // The escape_next logic is necessary to properly parse things like \\"
- // where the backslash is the one being escaped, not the quote.
- int end_pos = -1;
- bool escape_next = false;
- for (int i = 0; i < l.length(); i++) {
- if (l[i] == '\\' && !escape_next) {
- escape_next = true;
- continue;
+ if (l.begins_with("msgstr[")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_PLURAL, Ref<Resource>(), "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line));
+ plural_index++; // Increment to add to the next slot in vector msgs_plural.
+ l = l.substr(9, l.length()).strip_edges();
+ } else if (l.begins_with("msgstr")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_ID, Ref<Resource>(), "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line));
+ l = l.substr(6, l.length()).strip_edges();
+ status = STATUS_READING_STRING;
}
- if (l[i] == '"' && !escape_next) {
- end_pos = i;
- break;
+ if (l.is_empty() || l.begins_with("#")) {
+ if (l.contains("fuzzy")) {
+ skip_next = true;
+ }
+ line++;
+ continue; // Nothing to read or comment.
}
- escape_next = false;
- }
+ ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, Ref<Resource>(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line));
+
+ l = l.substr(1, l.length());
+ // Find final quote, ignoring escaped ones (\").
+ // The escape_next logic is necessary to properly parse things like \\"
+ // where the backslash is the one being escaped, not the quote.
+ int end_pos = -1;
+ bool escape_next = false;
+ for (int i = 0; i < l.length(); i++) {
+ if (l[i] == '\\' && !escape_next) {
+ escape_next = true;
+ continue;
+ }
- if (end_pos == -1) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line));
- }
+ if (l[i] == '"' && !escape_next) {
+ end_pos = i;
+ break;
+ }
- l = l.substr(0, end_pos);
- l = l.c_unescape();
-
- if (status == STATUS_READING_ID) {
- msg_id += l;
- } else if (status == STATUS_READING_STRING) {
- msg_str += l;
- } else if (status == STATUS_READING_CONTEXT) {
- msg_context += l;
- } else if (status == STATUS_READING_PLURAL && plural_index >= 0) {
- msgs_plural.write[plural_index] = msgs_plural[plural_index] + l;
- }
+ escape_next = false;
+ }
- line++;
- }
+ ERR_FAIL_COND_V_MSG(end_pos == -1, Ref<Resource>(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line));
- memdelete(f);
+ l = l.substr(0, end_pos);
+ l = l.c_unescape();
- // Add the last set of data from last iteration.
- if (status == STATUS_READING_STRING) {
- if (!msg_id.is_empty()) {
- if (!skip_this) {
- translation->add_message(msg_id, msg_str, msg_context);
+ if (status == STATUS_READING_ID) {
+ msg_id += l;
+ } else if (status == STATUS_READING_STRING) {
+ msg_str += l;
+ } else if (status == STATUS_READING_CONTEXT) {
+ msg_context += l;
+ } else if (status == STATUS_READING_PLURAL && plural_index >= 0) {
+ ERR_FAIL_COND_V_MSG(plural_index >= plural_forms, Ref<Resource>(), "Unexpected plural form while parsing: " + path + ":" + itos(line));
+ msgs_plural.write[plural_index] = msgs_plural[plural_index] + l;
}
- } else if (config.is_empty()) {
- config = msg_str;
+
+ line++;
}
- } else if (status == STATUS_READING_PLURAL) {
- if (!skip_this && !msg_id.is_empty()) {
- if (plural_index != plural_forms - 1) {
- memdelete(f);
- ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
+
+ // Add the last set of data from last iteration.
+ if (status == STATUS_READING_STRING) {
+ if (!msg_id.is_empty()) {
+ if (!skip_this) {
+ translation->add_message(msg_id, msg_str, msg_context);
+ }
+ } else if (config.is_empty()) {
+ config = msg_str;
+ }
+ } else if (status == STATUS_READING_PLURAL) {
+ if (!skip_this && !msg_id.is_empty()) {
+ ERR_FAIL_COND_V_MSG(plural_index != plural_forms - 1, Ref<Resource>(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
+ translation->add_plural_message(msg_id, msgs_plural, msg_context);
}
- translation->add_plural_message(msg_id, msgs_plural, msg_context);
}
}
- ERR_FAIL_COND_V_MSG(config.is_empty(), RES(), "No config found in file: " + path + ".");
+ ERR_FAIL_COND_V_MSG(config.is_empty(), Ref<Resource>(), "No config found in file: " + path + ".");
Vector<String> configs = config.split("\n");
for (int i = 0; i < configs.size(); i++) {
@@ -277,19 +344,20 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
return translation;
}
-RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, RES(), "Cannot open file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), Ref<Resource>(), "Cannot open file '" + p_path + "'.");
return load_translation(f, r_error);
}
void TranslationLoaderPO::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("po");
+ p_extensions->push_back("mo");
}
bool TranslationLoaderPO::handles_type(const String &p_type) const {
@@ -297,7 +365,7 @@ bool TranslationLoaderPO::handles_type(const String &p_type) const {
}
String TranslationLoaderPO::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "po") {
+ if (p_path.get_extension().to_lower() == "po" || p_path.get_extension().to_lower() == "mo") {
return "Translation";
}
return "";
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index 1c58896a00..4477ad7714 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -37,8 +37,8 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
- static RES load_translation(FileAccess *f, Error *r_error = nullptr);
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ static Ref<Resource> load_translation(Ref<FileAccess> f, Error *r_error = nullptr);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/udp_server.h b/core/io/udp_server.h
index 4a7546fddf..47f06b2490 100644
--- a/core/io/udp_server.h
+++ b/core/io/udp_server.h
@@ -43,7 +43,7 @@ protected:
};
struct Peer {
- PacketPeerUDP *peer;
+ PacketPeerUDP *peer = nullptr;
IPAddress ip;
uint16_t port = 0;
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 360da46f96..7b43193f47 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -472,7 +472,7 @@ Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) {
Error XMLParser::open(const String &p_path) {
Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'.");
@@ -488,8 +488,6 @@ Error XMLParser::open(const String &p_path) {
data[length] = 0;
P = data;
- memdelete(file);
-
return OK;
}
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index 2c4f8346ab..2cc844b628 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -30,73 +30,69 @@
#include "zip_io.h"
-void *zipio_open(void *data, const char *p_fname, int mode) {
- FileAccess *&f = *(FileAccess **)data;
+void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
+ ZipIOData *zd = (ZipIOData *)opaque;
String fname;
fname.parse_utf8(p_fname);
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
- f = FileAccess::open(fname, FileAccess::WRITE);
+ zd->f = FileAccess::open(fname, FileAccess::WRITE);
} else {
- f = FileAccess::open(fname, FileAccess::READ);
+ zd->f = FileAccess::open(fname, FileAccess::READ);
}
- if (!f) {
+ if (zd->f.is_null()) {
return nullptr;
}
- return data;
+ return opaque;
}
-uLong zipio_read(void *data, void *fdata, void *buf, uLong size) {
- FileAccess *f = *(FileAccess **)data;
- return f->get_buffer((uint8_t *)buf, size);
+uLong zipio_read(voidpf opaque, voidpf stream, void *buf, uLong size) {
+ ZipIOData *zd = (ZipIOData *)opaque;
+ return zd->f->get_buffer((uint8_t *)buf, size);
}
uLong zipio_write(voidpf opaque, voidpf stream, const void *buf, uLong size) {
- FileAccess *f = *(FileAccess **)opaque;
- f->store_buffer((uint8_t *)buf, size);
+ ZipIOData *zd = (ZipIOData *)opaque;
+ zd->f->store_buffer((uint8_t *)buf, size);
return size;
}
long zipio_tell(voidpf opaque, voidpf stream) {
- FileAccess *f = *(FileAccess **)opaque;
- return f->get_position();
+ ZipIOData *zd = (ZipIOData *)opaque;
+ return zd->f->get_position();
}
long zipio_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
- FileAccess *f = *(FileAccess **)opaque;
+ ZipIOData *zd = (ZipIOData *)opaque;
uint64_t pos = offset;
switch (origin) {
case ZLIB_FILEFUNC_SEEK_CUR:
- pos = f->get_position() + offset;
+ pos = zd->f->get_position() + offset;
break;
case ZLIB_FILEFUNC_SEEK_END:
- pos = f->get_length() + offset;
+ pos = zd->f->get_length() + offset;
break;
default:
break;
}
- f->seek(pos);
+ zd->f->seek(pos);
return 0;
}
int zipio_close(voidpf opaque, voidpf stream) {
- FileAccess *&f = *(FileAccess **)opaque;
- if (f) {
- f->close();
- memdelete(f);
- f = nullptr;
- }
+ ZipIOData *zd = (ZipIOData *)opaque;
+ memdelete(zd);
return 0;
}
int zipio_testerror(voidpf opaque, voidpf stream) {
- FileAccess *f = *(FileAccess **)opaque;
- return (f && f->get_error() != OK) ? 1 : 0;
+ ZipIOData *zd = (ZipIOData *)opaque;
+ return (zd->f.is_valid() && zd->f->get_error() != OK) ? 1 : 0;
}
voidpf zipio_alloc(voidpf opaque, uInt items, uInt size) {
@@ -109,9 +105,9 @@ void zipio_free(voidpf opaque, voidpf address) {
memfree(address);
}
-zlib_filefunc_def zipio_create_io_from_file(FileAccess **p_file) {
+zlib_filefunc_def zipio_create_io() {
zlib_filefunc_def io;
- io.opaque = p_file;
+ io.opaque = (void *)memnew(ZipIOData);
io.zopen_file = zipio_open;
io.zread_file = zipio_read;
io.zwrite_file = zipio_write;
diff --git a/core/io/zip_io.h b/core/io/zip_io.h
index 6a29703449..3bcd1f830d 100644
--- a/core/io/zip_io.h
+++ b/core/io/zip_io.h
@@ -39,8 +39,12 @@
#include "thirdparty/minizip/unzip.h"
#include "thirdparty/minizip/zip.h"
-void *zipio_open(void *data, const char *p_fname, int mode);
-uLong zipio_read(void *data, void *fdata, void *buf, uLong size);
+struct ZipIOData {
+ Ref<FileAccess> f;
+};
+
+void *zipio_open(voidpf opaque, const char *p_fname, int mode);
+uLong zipio_read(voidpf opaque, voidpf stream, void *buf, uLong size);
uLong zipio_write(voidpf opaque, voidpf stream, const void *buf, uLong size);
long zipio_tell(voidpf opaque, voidpf stream);
@@ -53,6 +57,6 @@ int zipio_testerror(voidpf opaque, voidpf stream);
voidpf zipio_alloc(voidpf opaque, uInt items, uInt size);
void zipio_free(voidpf opaque, voidpf address);
-zlib_filefunc_def zipio_create_io_from_file(FileAccess **p_file);
+zlib_filefunc_def zipio_create_io();
#endif // ZIP_IO_H
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 14057b96be..284b4294ea 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -33,7 +33,7 @@
#include "core/math/geometry_3d.h"
#include "core/object/script_language.h"
-int AStar::get_available_point_id() const {
+int AStar3D::get_available_point_id() const {
if (points.has(last_free_id)) {
int cur_new_id = last_free_id + 1;
while (points.has(cur_new_id)) {
@@ -45,9 +45,9 @@ int AStar::get_available_point_id() const {
return last_free_id;
}
-void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
+void AStar3D::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
ERR_FAIL_COND_MSG(p_id < 0, vformat("Can't add a point with negative id: %d.", p_id));
- ERR_FAIL_COND_MSG(p_weight_scale < 1, vformat("Can't add a point with weight scale less than one: %f.", p_weight_scale));
+ ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't add a point with weight scale less than 0.0: %f.", p_weight_scale));
Point *found_pt;
bool p_exists = points.lookup(p_id, found_pt);
@@ -68,7 +68,7 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
}
}
-Vector3 AStar::get_point_position(int p_id) const {
+Vector3 AStar3D::get_point_position(int p_id) const {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V_MSG(!p_exists, Vector3(), vformat("Can't get point's position. Point with id: %d doesn't exist.", p_id));
@@ -76,7 +76,7 @@ Vector3 AStar::get_point_position(int p_id) const {
return p->pos;
}
-void AStar::set_point_position(int p_id, const Vector3 &p_pos) {
+void AStar3D::set_point_position(int p_id, const Vector3 &p_pos) {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set point's position. Point with id: %d doesn't exist.", p_id));
@@ -84,7 +84,7 @@ void AStar::set_point_position(int p_id, const Vector3 &p_pos) {
p->pos = p_pos;
}
-real_t AStar::get_point_weight_scale(int p_id) const {
+real_t AStar3D::get_point_weight_scale(int p_id) const {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V_MSG(!p_exists, 0, vformat("Can't get point's weight scale. Point with id: %d doesn't exist.", p_id));
@@ -92,16 +92,16 @@ real_t AStar::get_point_weight_scale(int p_id) const {
return p->weight_scale;
}
-void AStar::set_point_weight_scale(int p_id, real_t p_weight_scale) {
+void AStar3D::set_point_weight_scale(int p_id, real_t p_weight_scale) {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set point's weight scale. Point with id: %d doesn't exist.", p_id));
- ERR_FAIL_COND_MSG(p_weight_scale < 1, vformat("Can't set point's weight scale less than one: %f.", p_weight_scale));
+ ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale));
p->weight_scale = p_weight_scale;
}
-void AStar::remove_point(int p_id) {
+void AStar3D::remove_point(int p_id) {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_MSG(!p_exists, vformat("Can't remove point. Point with id: %d doesn't exist.", p_id));
@@ -127,7 +127,7 @@ void AStar::remove_point(int p_id) {
last_free_id = p_id;
}
-void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) {
+void AStar3D::connect_points(int p_id, int p_with_id, bool bidirectional) {
ERR_FAIL_COND_MSG(p_id == p_with_id, vformat("Can't connect point with id: %d to itself.", p_id));
Point *a;
@@ -165,7 +165,7 @@ void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) {
segments.insert(s);
}
-void AStar::disconnect_points(int p_id, int p_with_id, bool bidirectional) {
+void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) {
Point *a;
bool a_exists = points.lookup(p_id, a);
ERR_FAIL_COND_MSG(!a_exists, vformat("Can't disconnect points. Point with id: %d doesn't exist.", p_id));
@@ -205,11 +205,11 @@ void AStar::disconnect_points(int p_id, int p_with_id, bool bidirectional) {
}
}
-bool AStar::has_point(int p_id) const {
+bool AStar3D::has_point(int p_id) const {
return points.has(p_id);
}
-Array AStar::get_point_ids() {
+Array AStar3D::get_point_ids() {
Array point_list;
for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) {
@@ -219,7 +219,7 @@ Array AStar::get_point_ids() {
return point_list;
}
-Vector<int> AStar::get_point_connections(int p_id) {
+Vector<int> AStar3D::get_point_connections(int p_id) {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V_MSG(!p_exists, Vector<int>(), vformat("Can't get point's connections. Point with id: %d doesn't exist.", p_id));
@@ -233,7 +233,7 @@ Vector<int> AStar::get_point_connections(int p_id) {
return point_list;
}
-bool AStar::are_points_connected(int p_id, int p_with_id, bool bidirectional) const {
+bool AStar3D::are_points_connected(int p_id, int p_with_id, bool bidirectional) const {
Segment s(p_id, p_with_id);
const Set<Segment>::Element *element = segments.find(s);
@@ -241,7 +241,7 @@ bool AStar::are_points_connected(int p_id, int p_with_id, bool bidirectional) co
(bidirectional || (element->get().direction & s.direction) == s.direction);
}
-void AStar::clear() {
+void AStar3D::clear() {
last_free_id = 0;
for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) {
memdelete(*(it.value));
@@ -250,21 +250,21 @@ void AStar::clear() {
points.clear();
}
-int AStar::get_point_count() const {
+int AStar3D::get_point_count() const {
return points.get_num_elements();
}
-int AStar::get_point_capacity() const {
+int AStar3D::get_point_capacity() const {
return points.get_capacity();
}
-void AStar::reserve_space(int p_num_nodes) {
+void AStar3D::reserve_space(int p_num_nodes) {
ERR_FAIL_COND_MSG(p_num_nodes <= 0, vformat("New capacity must be greater than 0, new was: %d.", p_num_nodes));
ERR_FAIL_COND_MSG((uint32_t)p_num_nodes < points.get_capacity(), vformat("New capacity must be greater than current capacity: %d, new was: %d.", points.get_capacity(), p_num_nodes));
points.reserve(p_num_nodes);
}
-int AStar::get_closest_point(const Vector3 &p_point, bool p_include_disabled) const {
+int AStar3D::get_closest_point(const Vector3 &p_point, bool p_include_disabled) const {
int closest_id = -1;
real_t closest_dist = 1e20;
@@ -289,7 +289,7 @@ int AStar::get_closest_point(const Vector3 &p_point, bool p_include_disabled) co
return closest_id;
}
-Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const {
+Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const {
real_t closest_dist = 1e20;
Vector3 closest_point;
@@ -318,7 +318,7 @@ Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const {
return closest_point;
}
-bool AStar::_solve(Point *begin_point, Point *end_point) {
+bool AStar3D::_solve(Point *begin_point, Point *end_point) {
pass++;
if (!end_point->enabled) {
@@ -380,7 +380,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
return found_route;
}
-real_t AStar::_estimate_cost(int p_from_id, int p_to_id) {
+real_t AStar3D::_estimate_cost(int p_from_id, int p_to_id) {
real_t scost;
if (GDVIRTUAL_CALL(_estimate_cost, p_from_id, p_to_id, scost)) {
return scost;
@@ -397,7 +397,7 @@ real_t AStar::_estimate_cost(int p_from_id, int p_to_id) {
return from_point->pos.distance_to(to_point->pos);
}
-real_t AStar::_compute_cost(int p_from_id, int p_to_id) {
+real_t AStar3D::_compute_cost(int p_from_id, int p_to_id) {
real_t scost;
if (GDVIRTUAL_CALL(_compute_cost, p_from_id, p_to_id, scost)) {
return scost;
@@ -414,7 +414,7 @@ real_t AStar::_compute_cost(int p_from_id, int p_to_id) {
return from_point->pos.distance_to(to_point->pos);
}
-Vector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
+Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) {
Point *a;
bool from_exists = points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id));
@@ -463,7 +463,7 @@ Vector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
return path;
}
-Vector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
+Vector<int> AStar3D::get_id_path(int p_from_id, int p_to_id) {
Point *a;
bool from_exists = points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id));
@@ -512,7 +512,7 @@ Vector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
return path;
}
-void AStar::set_point_disabled(int p_id, bool p_disabled) {
+void AStar3D::set_point_disabled(int p_id, bool p_disabled) {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set if point is disabled. Point with id: %d doesn't exist.", p_id));
@@ -520,7 +520,7 @@ void AStar::set_point_disabled(int p_id, bool p_disabled) {
p->enabled = !p_disabled;
}
-bool AStar::is_point_disabled(int p_id) const {
+bool AStar3D::is_point_disabled(int p_id) const {
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V_MSG(!p_exists, false, vformat("Can't get if point is disabled. Point with id: %d doesn't exist.", p_id));
@@ -528,41 +528,41 @@ bool AStar::is_point_disabled(int p_id) const {
return !p->enabled;
}
-void AStar::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_available_point_id"), &AStar::get_available_point_id);
- ClassDB::bind_method(D_METHOD("add_point", "id", "position", "weight_scale"), &AStar::add_point, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStar::get_point_position);
- ClassDB::bind_method(D_METHOD("set_point_position", "id", "position"), &AStar::set_point_position);
- ClassDB::bind_method(D_METHOD("get_point_weight_scale", "id"), &AStar::get_point_weight_scale);
- ClassDB::bind_method(D_METHOD("set_point_weight_scale", "id", "weight_scale"), &AStar::set_point_weight_scale);
- ClassDB::bind_method(D_METHOD("remove_point", "id"), &AStar::remove_point);
- ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point);
- ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar::get_point_connections);
- ClassDB::bind_method(D_METHOD("get_point_ids"), &AStar::get_point_ids);
+void AStar3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_available_point_id"), &AStar3D::get_available_point_id);
+ ClassDB::bind_method(D_METHOD("add_point", "id", "position", "weight_scale"), &AStar3D::add_point, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStar3D::get_point_position);
+ ClassDB::bind_method(D_METHOD("set_point_position", "id", "position"), &AStar3D::set_point_position);
+ ClassDB::bind_method(D_METHOD("get_point_weight_scale", "id"), &AStar3D::get_point_weight_scale);
+ ClassDB::bind_method(D_METHOD("set_point_weight_scale", "id", "weight_scale"), &AStar3D::set_point_weight_scale);
+ ClassDB::bind_method(D_METHOD("remove_point", "id"), &AStar3D::remove_point);
+ ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar3D::has_point);
+ ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar3D::get_point_connections);
+ ClassDB::bind_method(D_METHOD("get_point_ids"), &AStar3D::get_point_ids);
- ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar::set_point_disabled, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar::is_point_disabled);
+ ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar3D::set_point_disabled, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar3D::is_point_disabled);
- ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id", "bidirectional"), &AStar::disconnect_points, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id", "bidirectional"), &AStar::are_points_connected, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar3D::connect_points, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id", "bidirectional"), &AStar3D::disconnect_points, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id", "bidirectional"), &AStar3D::are_points_connected, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_point_count"), &AStar::get_point_count);
- ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar::get_point_capacity);
- ClassDB::bind_method(D_METHOD("reserve_space", "num_nodes"), &AStar::reserve_space);
- ClassDB::bind_method(D_METHOD("clear"), &AStar::clear);
+ ClassDB::bind_method(D_METHOD("get_point_count"), &AStar3D::get_point_count);
+ ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar3D::get_point_capacity);
+ ClassDB::bind_method(D_METHOD("reserve_space", "num_nodes"), &AStar3D::reserve_space);
+ ClassDB::bind_method(D_METHOD("clear"), &AStar3D::clear);
- ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar::get_closest_point, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar::get_closest_position_in_segment);
+ ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar3D::get_closest_point, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar3D::get_closest_position_in_segment);
- ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar::get_point_path);
- ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar::get_id_path);
+ ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar3D::get_point_path);
+ ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar3D::get_id_path);
GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
}
-AStar::~AStar() {
+AStar3D::~AStar3D() {
clear();
}
@@ -660,11 +660,11 @@ real_t AStar2D::_estimate_cost(int p_from_id, int p_to_id) {
return scost;
}
- AStar::Point *from_point;
+ AStar3D::Point *from_point;
bool from_exists = astar.points.lookup(p_from_id, from_point);
ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_from_id));
- AStar::Point *to_point;
+ AStar3D::Point *to_point;
bool to_exists = astar.points.lookup(p_to_id, to_point);
ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_to_id));
@@ -677,11 +677,11 @@ real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) {
return scost;
}
- AStar::Point *from_point;
+ AStar3D::Point *from_point;
bool from_exists = astar.points.lookup(p_from_id, from_point);
ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_from_id));
- AStar::Point *to_point;
+ AStar3D::Point *to_point;
bool to_exists = astar.points.lookup(p_to_id, to_point);
ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_to_id));
@@ -689,11 +689,11 @@ real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) {
}
Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) {
- AStar::Point *a;
+ AStar3D::Point *a;
bool from_exists = astar.points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id));
- AStar::Point *b;
+ AStar3D::Point *b;
bool to_exists = astar.points.lookup(p_to_id, b);
ERR_FAIL_COND_V_MSG(!to_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_to_id));
@@ -702,15 +702,15 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) {
return ret;
}
- AStar::Point *begin_point = a;
- AStar::Point *end_point = b;
+ AStar3D::Point *begin_point = a;
+ AStar3D::Point *end_point = b;
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
return Vector<Vector2>();
}
- AStar::Point *p = end_point;
+ AStar3D::Point *p = end_point;
int pc = 1; // Begin point
while (p != begin_point) {
pc++;
@@ -723,7 +723,7 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) {
{
Vector2 *w = path.ptrw();
- AStar::Point *p2 = end_point;
+ AStar3D::Point *p2 = end_point;
int idx = pc - 1;
while (p2 != begin_point) {
w[idx--] = Vector2(p2->pos.x, p2->pos.y);
@@ -737,11 +737,11 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) {
}
Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) {
- AStar::Point *a;
+ AStar3D::Point *a;
bool from_exists = astar.points.lookup(p_from_id, a);
ERR_FAIL_COND_V_MSG(!from_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id));
- AStar::Point *b;
+ AStar3D::Point *b;
bool to_exists = astar.points.lookup(p_to_id, b);
ERR_FAIL_COND_V_MSG(!to_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id));
@@ -751,15 +751,15 @@ Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) {
return ret;
}
- AStar::Point *begin_point = a;
- AStar::Point *end_point = b;
+ AStar3D::Point *begin_point = a;
+ AStar3D::Point *end_point = b;
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
return Vector<int>();
}
- AStar::Point *p = end_point;
+ AStar3D::Point *p = end_point;
int pc = 1; // Begin point
while (p != begin_point) {
pc++;
@@ -785,7 +785,7 @@ Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) {
return path;
}
-bool AStar2D::_solve(AStar::Point *begin_point, AStar::Point *end_point) {
+bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
astar.pass++;
if (!end_point->enabled) {
@@ -794,15 +794,15 @@ bool AStar2D::_solve(AStar::Point *begin_point, AStar::Point *end_point) {
bool found_route = false;
- Vector<AStar::Point *> open_list;
- SortArray<AStar::Point *, AStar::SortPoints> sorter;
+ Vector<AStar3D::Point *> open_list;
+ SortArray<AStar3D::Point *, AStar3D::SortPoints> sorter;
begin_point->g_score = 0;
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
while (!open_list.is_empty()) {
- AStar::Point *p = open_list[0]; // The currently processed point
+ AStar3D::Point *p = open_list[0]; // The currently processed point
if (p == end_point) {
found_route = true;
@@ -813,8 +813,8 @@ bool AStar2D::_solve(AStar::Point *begin_point, AStar::Point *end_point) {
open_list.remove_at(open_list.size() - 1);
p->closed_pass = astar.pass; // Mark the point as closed
- for (OAHashMap<int, AStar::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
- AStar::Point *e = *(it.value); // The neighbour point
+ for (OAHashMap<int, AStar3D::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
+ AStar3D::Point *e = *(it.value); // The neighbour point
if (!e->enabled || e->closed_pass == astar.pass) {
continue;
diff --git a/core/math/a_star.h b/core/math/a_star.h
index 130c202a61..bb7112fb09 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -40,8 +40,8 @@
A* pathfinding algorithm.
*/
-class AStar : public RefCounted {
- GDCLASS(AStar, RefCounted);
+class AStar3D : public RefCounted {
+ GDCLASS(AStar3D, RefCounted);
friend class AStar2D;
struct Point {
@@ -156,15 +156,15 @@ public:
Vector<Vector3> get_point_path(int p_from_id, int p_to_id);
Vector<int> get_id_path(int p_from_id, int p_to_id);
- AStar() {}
- ~AStar();
+ AStar3D() {}
+ ~AStar3D();
};
class AStar2D : public RefCounted {
GDCLASS(AStar2D, RefCounted);
- AStar astar;
+ AStar3D astar;
- bool _solve(AStar::Point *begin_point, AStar::Point *end_point);
+ bool _solve(AStar3D::Point *begin_point, AStar3D::Point *end_point);
protected:
static void _bind_methods();
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index e34c1c1315..65353d8118 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -34,32 +34,32 @@
#include "core/string/print_string.h"
#define cofac(row1, col1, row2, col2) \
- (elements[row1][col1] * elements[row2][col2] - elements[row1][col2] * elements[row2][col1])
+ (rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1])
void Basis::from_z(const Vector3 &p_z) {
- if (Math::abs(p_z.z) > Math_SQRT12) {
+ if (Math::abs(p_z.z) > (real_t)Math_SQRT12) {
// choose p in y-z plane
real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2];
real_t k = 1.0f / Math::sqrt(a);
- elements[0] = Vector3(0, -p_z[2] * k, p_z[1] * k);
- elements[1] = Vector3(a * k, -p_z[0] * elements[0][2], p_z[0] * elements[0][1]);
+ rows[0] = Vector3(0, -p_z[2] * k, p_z[1] * k);
+ rows[1] = Vector3(a * k, -p_z[0] * rows[0][2], p_z[0] * rows[0][1]);
} else {
// choose p in x-y plane
real_t a = p_z.x * p_z.x + p_z.y * p_z.y;
real_t k = 1.0f / Math::sqrt(a);
- elements[0] = Vector3(-p_z.y * k, p_z.x * k, 0);
- elements[1] = Vector3(-p_z.z * elements[0].y, p_z.z * elements[0].x, a * k);
+ rows[0] = Vector3(-p_z.y * k, p_z.x * k, 0);
+ rows[1] = Vector3(-p_z.z * rows[0].y, p_z.z * rows[0].x, a * k);
}
- elements[2] = p_z;
+ rows[2] = p_z;
}
void Basis::invert() {
real_t co[3] = {
cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)
};
- real_t det = elements[0][0] * co[0] +
- elements[0][1] * co[1] +
- elements[0][2] * co[2];
+ real_t det = rows[0][0] * co[0] +
+ rows[0][1] * co[1] +
+ rows[0][2] * co[2];
#ifdef MATH_CHECKS
ERR_FAIL_COND(det == 0);
#endif
@@ -73,9 +73,9 @@ void Basis::invert() {
void Basis::orthonormalize() {
// Gram-Schmidt Process
- Vector3 x = get_axis(0);
- Vector3 y = get_axis(1);
- Vector3 z = get_axis(2);
+ Vector3 x = get_column(0);
+ Vector3 y = get_column(1);
+ Vector3 z = get_column(2);
x.normalize();
y = (y - x * (x.dot(y)));
@@ -83,9 +83,9 @@ void Basis::orthonormalize() {
z = (z - x * (x.dot(z)) - y * (y.dot(z)));
z.normalize();
- set_axis(0, x);
- set_axis(1, y);
- set_axis(2, z);
+ set_column(0, x);
+ set_column(1, y);
+ set_column(2, z);
}
Basis Basis::orthonormalized() const {
@@ -115,9 +115,9 @@ bool Basis::is_orthogonal() const {
bool Basis::is_diagonal() const {
return (
- Math::is_zero_approx(elements[0][1]) && Math::is_zero_approx(elements[0][2]) &&
- Math::is_zero_approx(elements[1][0]) && Math::is_zero_approx(elements[1][2]) &&
- Math::is_zero_approx(elements[2][0]) && Math::is_zero_approx(elements[2][1]));
+ Math::is_zero_approx(rows[0][1]) && Math::is_zero_approx(rows[0][2]) &&
+ Math::is_zero_approx(rows[1][0]) && Math::is_zero_approx(rows[1][2]) &&
+ Math::is_zero_approx(rows[2][0]) && Math::is_zero_approx(rows[2][1]));
}
bool Basis::is_rotation() const {
@@ -127,13 +127,13 @@ bool Basis::is_rotation() const {
#ifdef MATH_CHECKS
// This method is only used once, in diagonalize. If it's desired elsewhere, feel free to remove the #ifdef.
bool Basis::is_symmetric() const {
- if (!Math::is_equal_approx(elements[0][1], elements[1][0])) {
+ if (!Math::is_equal_approx(rows[0][1], rows[1][0])) {
return false;
}
- if (!Math::is_equal_approx(elements[0][2], elements[2][0])) {
+ if (!Math::is_equal_approx(rows[0][2], rows[2][0])) {
return false;
}
- if (!Math::is_equal_approx(elements[1][2], elements[2][1])) {
+ if (!Math::is_equal_approx(rows[1][2], rows[2][1])) {
return false;
}
@@ -149,14 +149,14 @@ Basis Basis::diagonalize() {
#endif
const int ite_max = 1024;
- real_t off_matrix_norm_2 = elements[0][1] * elements[0][1] + elements[0][2] * elements[0][2] + elements[1][2] * elements[1][2];
+ real_t off_matrix_norm_2 = rows[0][1] * rows[0][1] + rows[0][2] * rows[0][2] + rows[1][2] * rows[1][2];
int ite = 0;
Basis acc_rot;
- while (off_matrix_norm_2 > CMP_EPSILON2 && ite++ < ite_max) {
- real_t el01_2 = elements[0][1] * elements[0][1];
- real_t el02_2 = elements[0][2] * elements[0][2];
- real_t el12_2 = elements[1][2] * elements[1][2];
+ while (off_matrix_norm_2 > (real_t)CMP_EPSILON2 && ite++ < ite_max) {
+ real_t el01_2 = rows[0][1] * rows[0][1];
+ real_t el02_2 = rows[0][2] * rows[0][2];
+ real_t el12_2 = rows[1][2] * rows[1][2];
// Find the pivot element
int i, j;
if (el01_2 > el02_2) {
@@ -179,19 +179,19 @@ Basis Basis::diagonalize() {
// Compute the rotation angle
real_t angle;
- if (Math::is_equal_approx(elements[j][j], elements[i][i])) {
+ if (Math::is_equal_approx(rows[j][j], rows[i][i])) {
angle = Math_PI / 4;
} else {
- angle = 0.5f * Math::atan(2 * elements[i][j] / (elements[j][j] - elements[i][i]));
+ angle = 0.5f * Math::atan(2 * rows[i][j] / (rows[j][j] - rows[i][i]));
}
// Compute the rotation matrix
Basis rot;
- rot.elements[i][i] = rot.elements[j][j] = Math::cos(angle);
- rot.elements[i][j] = -(rot.elements[j][i] = Math::sin(angle));
+ rot.rows[i][i] = rot.rows[j][j] = Math::cos(angle);
+ rot.rows[i][j] = -(rot.rows[j][i] = Math::sin(angle));
// Update the off matrix norm
- off_matrix_norm_2 -= elements[i][j] * elements[i][j];
+ off_matrix_norm_2 -= rows[i][j] * rows[i][j];
// Apply the rotation
*this = rot * *this * rot.transposed();
@@ -208,9 +208,9 @@ Basis Basis::inverse() const {
}
void Basis::transpose() {
- SWAP(elements[0][1], elements[1][0]);
- SWAP(elements[0][2], elements[2][0]);
- SWAP(elements[1][2], elements[2][1]);
+ SWAP(rows[0][1], rows[1][0]);
+ SWAP(rows[0][2], rows[2][0]);
+ SWAP(rows[1][2], rows[2][1]);
}
Basis Basis::transposed() const {
@@ -226,15 +226,15 @@ Basis Basis::from_scale(const Vector3 &p_scale) {
// Multiplies the matrix from left by the scaling matrix: M -> S.M
// See the comment for Basis::rotated for further explanation.
void Basis::scale(const Vector3 &p_scale) {
- elements[0][0] *= p_scale.x;
- elements[0][1] *= p_scale.x;
- elements[0][2] *= p_scale.x;
- elements[1][0] *= p_scale.y;
- elements[1][1] *= p_scale.y;
- elements[1][2] *= p_scale.y;
- elements[2][0] *= p_scale.z;
- elements[2][1] *= p_scale.z;
- elements[2][2] *= p_scale.z;
+ rows[0][0] *= p_scale.x;
+ rows[0][1] *= p_scale.x;
+ rows[0][2] *= p_scale.x;
+ rows[1][0] *= p_scale.y;
+ rows[1][1] *= p_scale.y;
+ rows[1][2] *= p_scale.y;
+ rows[2][0] *= p_scale.z;
+ rows[2][1] *= p_scale.z;
+ rows[2][2] *= p_scale.z;
}
Basis Basis::scaled(const Vector3 &p_scale) const {
@@ -260,7 +260,7 @@ Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const {
Basis b;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- dots[j] += s[i] * abs(m.get_axis(i).normalized().dot(b.get_axis(j)));
+ dots[j] += s[i] * abs(m.get_column(i).normalized().dot(b.get_column(j)));
}
}
m.scale_local(Vector3(1, 1, 1) + dots);
@@ -268,14 +268,14 @@ Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const {
}
float Basis::get_uniform_scale() const {
- return (elements[0].length() + elements[1].length() + elements[2].length()) / 3.0f;
+ return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f;
}
void Basis::make_scale_uniform() {
- float l = (elements[0].length() + elements[1].length() + elements[2].length()) / 3.0f;
+ float l = (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f;
for (int i = 0; i < 3; i++) {
- elements[i].normalize();
- elements[i] *= l;
+ rows[i].normalize();
+ rows[i] *= l;
}
}
@@ -285,14 +285,14 @@ Basis Basis::scaled_local(const Vector3 &p_scale) const {
Vector3 Basis::get_scale_abs() const {
return Vector3(
- Vector3(elements[0][0], elements[1][0], elements[2][0]).length(),
- Vector3(elements[0][1], elements[1][1], elements[2][1]).length(),
- Vector3(elements[0][2], elements[1][2], elements[2][2]).length());
+ Vector3(rows[0][0], rows[1][0], rows[2][0]).length(),
+ Vector3(rows[0][1], rows[1][1], rows[2][1]).length(),
+ Vector3(rows[0][2], rows[1][2], rows[2][2]).length());
}
Vector3 Basis::get_scale_local() const {
real_t det_sign = SIGN(determinant());
- return det_sign * Vector3(elements[0].length(), elements[1].length(), elements[2].length());
+ return det_sign * Vector3(rows[0].length(), rows[1].length(), rows[2].length());
}
// get_scale works with get_rotation, use get_scale_abs if you need to enforce positive signature.
@@ -347,22 +347,22 @@ Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const {
// The main use of Basis is as Transform.basis, which is used by the transformation matrix
// of 3D object. Rotate here refers to rotation of the object (which is R * (*this)),
// not the matrix itself (which is R * (*this) * R.transposed()).
-Basis Basis::rotated(const Vector3 &p_axis, real_t p_phi) const {
- return Basis(p_axis, p_phi) * (*this);
+Basis Basis::rotated(const Vector3 &p_axis, real_t p_angle) const {
+ return Basis(p_axis, p_angle) * (*this);
}
-void Basis::rotate(const Vector3 &p_axis, real_t p_phi) {
- *this = rotated(p_axis, p_phi);
+void Basis::rotate(const Vector3 &p_axis, real_t p_angle) {
+ *this = rotated(p_axis, p_angle);
}
-void Basis::rotate_local(const Vector3 &p_axis, real_t p_phi) {
+void Basis::rotate_local(const Vector3 &p_axis, real_t p_angle) {
// performs a rotation in object-local coordinate system:
// M -> (M.R.Minv).M = M.R.
- *this = rotated_local(p_axis, p_phi);
+ *this = rotated_local(p_axis, p_angle);
}
-Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_phi) const {
- return (*this) * Basis(p_axis, p_phi);
+Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_angle) const {
+ return (*this) * Basis(p_axis, p_angle);
}
Basis Basis::rotated(const Vector3 &p_euler) const {
@@ -462,27 +462,27 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
Vector3 euler;
- real_t sy = elements[0][2];
- if (sy < (1.0f - CMP_EPSILON)) {
- if (sy > -(1.0f - CMP_EPSILON)) {
+ real_t sy = rows[0][2];
+ if (sy < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
// is this a pure Y rotation?
- if (elements[1][0] == 0 && elements[0][1] == 0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) {
+ if (rows[1][0] == 0 && rows[0][1] == 0 && rows[1][2] == 0 && rows[2][1] == 0 && rows[1][1] == 1) {
// return the simplest form (human friendlier in editor and scripts)
euler.x = 0;
- euler.y = atan2(elements[0][2], elements[0][0]);
+ euler.y = atan2(rows[0][2], rows[0][0]);
euler.z = 0;
} else {
- euler.x = Math::atan2(-elements[1][2], elements[2][2]);
+ euler.x = Math::atan2(-rows[1][2], rows[2][2]);
euler.y = Math::asin(sy);
- euler.z = Math::atan2(-elements[0][1], elements[0][0]);
+ euler.z = Math::atan2(-rows[0][1], rows[0][0]);
}
} else {
- euler.x = Math::atan2(elements[2][1], elements[1][1]);
+ euler.x = Math::atan2(rows[2][1], rows[1][1]);
euler.y = -Math_PI / 2.0f;
euler.z = 0.0f;
}
} else {
- euler.x = Math::atan2(elements[2][1], elements[1][1]);
+ euler.x = Math::atan2(rows[2][1], rows[1][1]);
euler.y = Math_PI / 2.0f;
euler.z = 0.0f;
}
@@ -497,21 +497,21 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// cy*sx*sz cz*sx cx*cy+sx*sz*sy
Vector3 euler;
- real_t sz = elements[0][1];
- if (sz < (1.0f - CMP_EPSILON)) {
- if (sz > -(1.0f - CMP_EPSILON)) {
- euler.x = Math::atan2(elements[2][1], elements[1][1]);
- euler.y = Math::atan2(elements[0][2], elements[0][0]);
+ real_t sz = rows[0][1];
+ if (sz < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
+ euler.x = Math::atan2(rows[2][1], rows[1][1]);
+ euler.y = Math::atan2(rows[0][2], rows[0][0]);
euler.z = Math::asin(-sz);
} else {
// It's -1
- euler.x = -Math::atan2(elements[1][2], elements[2][2]);
+ euler.x = -Math::atan2(rows[1][2], rows[2][2]);
euler.y = 0.0f;
euler.z = Math_PI / 2.0f;
}
} else {
// It's 1
- euler.x = -Math::atan2(elements[1][2], elements[2][2]);
+ euler.x = -Math::atan2(rows[1][2], rows[2][2]);
euler.y = 0.0f;
euler.z = -Math_PI / 2.0f;
}
@@ -527,29 +527,29 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
- real_t m12 = elements[1][2];
+ real_t m12 = rows[1][2];
- if (m12 < (1 - CMP_EPSILON)) {
- if (m12 > -(1 - CMP_EPSILON)) {
+ if (m12 < (1 - (real_t)CMP_EPSILON)) {
+ if (m12 > -(1 - (real_t)CMP_EPSILON)) {
// is this a pure X rotation?
- if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) {
+ if (rows[1][0] == 0 && rows[0][1] == 0 && rows[0][2] == 0 && rows[2][0] == 0 && rows[0][0] == 1) {
// return the simplest form (human friendlier in editor and scripts)
- euler.x = atan2(-m12, elements[1][1]);
+ euler.x = atan2(-m12, rows[1][1]);
euler.y = 0;
euler.z = 0;
} else {
euler.x = asin(-m12);
- euler.y = atan2(elements[0][2], elements[2][2]);
- euler.z = atan2(elements[1][0], elements[1][1]);
+ euler.y = atan2(rows[0][2], rows[2][2]);
+ euler.z = atan2(rows[1][0], rows[1][1]);
}
} else { // m12 == -1
euler.x = Math_PI * 0.5f;
- euler.y = atan2(elements[0][1], elements[0][0]);
+ euler.y = atan2(rows[0][1], rows[0][0]);
euler.z = 0;
}
} else { // m12 == 1
euler.x = -Math_PI * 0.5f;
- euler.y = -atan2(elements[0][1], elements[0][0]);
+ euler.y = -atan2(rows[0][1], rows[0][0]);
euler.z = 0;
}
@@ -564,21 +564,21 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx
Vector3 euler;
- real_t sz = elements[1][0];
- if (sz < (1.0f - CMP_EPSILON)) {
- if (sz > -(1.0f - CMP_EPSILON)) {
- euler.x = Math::atan2(-elements[1][2], elements[1][1]);
- euler.y = Math::atan2(-elements[2][0], elements[0][0]);
+ real_t sz = rows[1][0];
+ if (sz < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
+ euler.x = Math::atan2(-rows[1][2], rows[1][1]);
+ euler.y = Math::atan2(-rows[2][0], rows[0][0]);
euler.z = Math::asin(sz);
} else {
// It's -1
- euler.x = Math::atan2(elements[2][1], elements[2][2]);
+ euler.x = Math::atan2(rows[2][1], rows[2][2]);
euler.y = 0.0f;
euler.z = -Math_PI / 2.0f;
}
} else {
// It's 1
- euler.x = Math::atan2(elements[2][1], elements[2][2]);
+ euler.x = Math::atan2(rows[2][1], rows[2][2]);
euler.y = 0.0f;
euler.z = Math_PI / 2.0f;
}
@@ -592,22 +592,22 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// cy*sz+cz*sx*sy cz*cx sz*sy-cz*cy*sx
// -cx*sy sx cx*cy
Vector3 euler;
- real_t sx = elements[2][1];
- if (sx < (1.0f - CMP_EPSILON)) {
- if (sx > -(1.0f - CMP_EPSILON)) {
+ real_t sx = rows[2][1];
+ if (sx < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sx > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::asin(sx);
- euler.y = Math::atan2(-elements[2][0], elements[2][2]);
- euler.z = Math::atan2(-elements[0][1], elements[1][1]);
+ euler.y = Math::atan2(-rows[2][0], rows[2][2]);
+ euler.z = Math::atan2(-rows[0][1], rows[1][1]);
} else {
// It's -1
euler.x = -Math_PI / 2.0f;
- euler.y = Math::atan2(elements[0][2], elements[0][0]);
+ euler.y = Math::atan2(rows[0][2], rows[0][0]);
euler.z = 0;
}
} else {
// It's 1
euler.x = Math_PI / 2.0f;
- euler.y = Math::atan2(elements[0][2], elements[0][0]);
+ euler.y = Math::atan2(rows[0][2], rows[0][0]);
euler.z = 0;
}
return euler;
@@ -620,23 +620,23 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx
// -sy cy*sx cy*cx
Vector3 euler;
- real_t sy = elements[2][0];
- if (sy < (1.0f - CMP_EPSILON)) {
- if (sy > -(1.0f - CMP_EPSILON)) {
- euler.x = Math::atan2(elements[2][1], elements[2][2]);
+ real_t sy = rows[2][0];
+ if (sy < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
+ euler.x = Math::atan2(rows[2][1], rows[2][2]);
euler.y = Math::asin(-sy);
- euler.z = Math::atan2(elements[1][0], elements[0][0]);
+ euler.z = Math::atan2(rows[1][0], rows[0][0]);
} else {
// It's -1
euler.x = 0;
euler.y = Math_PI / 2.0f;
- euler.z = -Math::atan2(elements[0][1], elements[1][1]);
+ euler.z = -Math::atan2(rows[0][1], rows[1][1]);
}
} else {
// It's 1
euler.x = 0;
euler.y = -Math_PI / 2.0f;
- euler.z = -Math::atan2(elements[0][1], elements[1][1]);
+ euler.z = -Math::atan2(rows[0][1], rows[1][1]);
}
return euler;
} break;
@@ -688,13 +688,13 @@ void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) {
}
bool Basis::is_equal_approx(const Basis &p_basis) const {
- return elements[0].is_equal_approx(p_basis.elements[0]) && elements[1].is_equal_approx(p_basis.elements[1]) && elements[2].is_equal_approx(p_basis.elements[2]);
+ return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]);
}
bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- if (elements[i][j] != p_matrix.elements[i][j]) {
+ if (rows[i][j] != p_matrix.rows[i][j]) {
return false;
}
}
@@ -708,9 +708,9 @@ bool Basis::operator!=(const Basis &p_matrix) const {
}
Basis::operator String() const {
- return "[X: " + get_axis(0).operator String() +
- ", Y: " + get_axis(1).operator String() +
- ", Z: " + get_axis(2).operator String() + "]";
+ return "[X: " + get_column(0).operator String() +
+ ", Y: " + get_column(1).operator String() +
+ ", Z: " + get_column(2).operator String() + "]";
}
Quaternion Basis::get_quaternion() const {
@@ -719,7 +719,7 @@ Quaternion Basis::get_quaternion() const {
#endif
/* Allow getting a quaternion from an unnormalized transform */
Basis m = *this;
- real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2];
+ real_t trace = m.rows[0][0] + m.rows[1][1] + m.rows[2][2];
real_t temp[4];
if (trace > 0.0f) {
@@ -727,23 +727,23 @@ Quaternion Basis::get_quaternion() const {
temp[3] = (s * 0.5f);
s = 0.5f / s;
- temp[0] = ((m.elements[2][1] - m.elements[1][2]) * s);
- temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s);
- temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s);
+ temp[0] = ((m.rows[2][1] - m.rows[1][2]) * s);
+ temp[1] = ((m.rows[0][2] - m.rows[2][0]) * s);
+ temp[2] = ((m.rows[1][0] - m.rows[0][1]) * s);
} else {
- int i = m.elements[0][0] < m.elements[1][1]
- ? (m.elements[1][1] < m.elements[2][2] ? 2 : 1)
- : (m.elements[0][0] < m.elements[2][2] ? 2 : 0);
+ int i = m.rows[0][0] < m.rows[1][1]
+ ? (m.rows[1][1] < m.rows[2][2] ? 2 : 1)
+ : (m.rows[0][0] < m.rows[2][2] ? 2 : 0);
int j = (i + 1) % 3;
int k = (i + 2) % 3;
- real_t s = Math::sqrt(m.elements[i][i] - m.elements[j][j] - m.elements[k][k] + 1.0f);
+ real_t s = Math::sqrt(m.rows[i][i] - m.rows[j][j] - m.rows[k][k] + 1.0f);
temp[i] = s * 0.5f;
s = 0.5f / s;
- temp[3] = (m.elements[k][j] - m.elements[j][k]) * s;
- temp[j] = (m.elements[j][i] + m.elements[i][j]) * s;
- temp[k] = (m.elements[k][i] + m.elements[i][k]) * s;
+ temp[3] = (m.rows[k][j] - m.rows[j][k]) * s;
+ temp[j] = (m.rows[j][i] + m.rows[i][j]) * s;
+ temp[k] = (m.rows[k][i] + m.rows[i][k]) * s;
}
return Quaternion(temp[0], temp[1], temp[2], temp[3]);
@@ -820,11 +820,11 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
real_t epsilon = 0.01; // margin to allow for rounding errors
real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
- if ((Math::abs(elements[1][0] - elements[0][1]) < epsilon) && (Math::abs(elements[2][0] - elements[0][2]) < epsilon) && (Math::abs(elements[2][1] - elements[1][2]) < epsilon)) {
+ if ((Math::abs(rows[1][0] - rows[0][1]) < epsilon) && (Math::abs(rows[2][0] - rows[0][2]) < epsilon) && (Math::abs(rows[2][1] - rows[1][2]) < epsilon)) {
// singularity found
// first check for identity matrix which must have +1 for all terms
// in leading diagonal and zero in other terms
- if ((Math::abs(elements[1][0] + elements[0][1]) < epsilon2) && (Math::abs(elements[2][0] + elements[0][2]) < epsilon2) && (Math::abs(elements[2][1] + elements[1][2]) < epsilon2) && (Math::abs(elements[0][0] + elements[1][1] + elements[2][2] - 3) < epsilon2)) {
+ if ((Math::abs(rows[1][0] + rows[0][1]) < epsilon2) && (Math::abs(rows[2][0] + rows[0][2]) < epsilon2) && (Math::abs(rows[2][1] + rows[1][2]) < epsilon2) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < epsilon2)) {
// this singularity is identity matrix so angle = 0
r_axis = Vector3(0, 1, 0);
r_angle = 0;
@@ -832,13 +832,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
}
// otherwise this singularity is angle = 180
angle = Math_PI;
- real_t xx = (elements[0][0] + 1) / 2;
- real_t yy = (elements[1][1] + 1) / 2;
- real_t zz = (elements[2][2] + 1) / 2;
- real_t xy = (elements[1][0] + elements[0][1]) / 4;
- real_t xz = (elements[2][0] + elements[0][2]) / 4;
- real_t yz = (elements[2][1] + elements[1][2]) / 4;
- if ((xx > yy) && (xx > zz)) { // elements[0][0] is the largest diagonal term
+ real_t xx = (rows[0][0] + 1) / 2;
+ real_t yy = (rows[1][1] + 1) / 2;
+ real_t zz = (rows[2][2] + 1) / 2;
+ real_t xy = (rows[1][0] + rows[0][1]) / 4;
+ real_t xz = (rows[2][0] + rows[0][2]) / 4;
+ real_t yz = (rows[2][1] + rows[1][2]) / 4;
+ if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term
if (xx < epsilon) {
x = 0;
y = Math_SQRT12;
@@ -848,7 +848,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
y = xy / x;
z = xz / x;
}
- } else if (yy > zz) { // elements[1][1] is the largest diagonal term
+ } else if (yy > zz) { // rows[1][1] is the largest diagonal term
if (yy < epsilon) {
x = Math_SQRT12;
y = 0;
@@ -858,7 +858,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
x = xy / y;
z = yz / y;
}
- } else { // elements[2][2] is the largest diagonal term so base result on this
+ } else { // rows[2][2] is the largest diagonal term so base result on this
if (zz < epsilon) {
x = Math_SQRT12;
y = Math_SQRT12;
@@ -874,15 +874,15 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
return;
}
// as we have reached here there are no singularities so we can handle normally
- real_t s = Math::sqrt((elements[1][2] - elements[2][1]) * (elements[1][2] - elements[2][1]) + (elements[2][0] - elements[0][2]) * (elements[2][0] - elements[0][2]) + (elements[0][1] - elements[1][0]) * (elements[0][1] - elements[1][0])); // s=|axis||sin(angle)|, used to normalise
+ real_t s = Math::sqrt((rows[1][2] - rows[2][1]) * (rows[1][2] - rows[2][1]) + (rows[2][0] - rows[0][2]) * (rows[2][0] - rows[0][2]) + (rows[0][1] - rows[1][0]) * (rows[0][1] - rows[1][0])); // s=|axis||sin(angle)|, used to normalise
- angle = Math::acos((elements[0][0] + elements[1][1] + elements[2][2] - 1) / 2);
+ angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2);
if (angle < 0) {
s = -s;
}
- x = (elements[2][1] - elements[1][2]) / s;
- y = (elements[0][2] - elements[2][0]) / s;
- z = (elements[1][0] - elements[0][1]) / s;
+ x = (rows[2][1] - rows[1][2]) / s;
+ y = (rows[0][2] - rows[2][0]) / s;
+ z = (rows[1][0] - rows[0][1]) / s;
r_axis = Vector3(x, y, z);
r_angle = angle;
@@ -900,39 +900,39 @@ void Basis::set_quaternion(const Quaternion &p_quaternion) {
xz - wy, yz + wx, 1.0f - (xx + yy));
}
-void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) {
+void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_angle) {
// Rotation matrix from axis and angle, see https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_angle
#ifdef MATH_CHECKS
ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized.");
#endif
Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z);
- real_t cosine = Math::cos(p_phi);
- elements[0][0] = axis_sq.x + cosine * (1.0f - axis_sq.x);
- elements[1][1] = axis_sq.y + cosine * (1.0f - axis_sq.y);
- elements[2][2] = axis_sq.z + cosine * (1.0f - axis_sq.z);
+ real_t cosine = Math::cos(p_angle);
+ rows[0][0] = axis_sq.x + cosine * (1.0f - axis_sq.x);
+ rows[1][1] = axis_sq.y + cosine * (1.0f - axis_sq.y);
+ rows[2][2] = axis_sq.z + cosine * (1.0f - axis_sq.z);
- real_t sine = Math::sin(p_phi);
+ real_t sine = Math::sin(p_angle);
real_t t = 1 - cosine;
real_t xyzt = p_axis.x * p_axis.y * t;
real_t zyxs = p_axis.z * sine;
- elements[0][1] = xyzt - zyxs;
- elements[1][0] = xyzt + zyxs;
+ rows[0][1] = xyzt - zyxs;
+ rows[1][0] = xyzt + zyxs;
xyzt = p_axis.x * p_axis.z * t;
zyxs = p_axis.y * sine;
- elements[0][2] = xyzt + zyxs;
- elements[2][0] = xyzt - zyxs;
+ rows[0][2] = xyzt + zyxs;
+ rows[2][0] = xyzt - zyxs;
xyzt = p_axis.y * p_axis.z * t;
zyxs = p_axis.x * sine;
- elements[1][2] = xyzt - zyxs;
- elements[2][1] = xyzt + zyxs;
+ rows[1][2] = xyzt - zyxs;
+ rows[2][1] = xyzt + zyxs;
}
-void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) {
+void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) {
_set_diagonal(p_scale);
- rotate(p_axis, p_phi);
+ rotate(p_axis, p_angle);
}
void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) {
@@ -948,24 +948,24 @@ void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &
// This also sets the non-diagonal elements to 0, which is misleading from the
// name, so we want this method to be private. Use `from_scale` externally.
void Basis::_set_diagonal(const Vector3 &p_diag) {
- elements[0][0] = p_diag.x;
- elements[0][1] = 0;
- elements[0][2] = 0;
+ rows[0][0] = p_diag.x;
+ rows[0][1] = 0;
+ rows[0][2] = 0;
- elements[1][0] = 0;
- elements[1][1] = p_diag.y;
- elements[1][2] = 0;
+ rows[1][0] = 0;
+ rows[1][1] = p_diag.y;
+ rows[1][2] = 0;
- elements[2][0] = 0;
- elements[2][1] = 0;
- elements[2][2] = p_diag.z;
+ rows[2][0] = 0;
+ rows[2][1] = 0;
+ rows[2][2] = p_diag.z;
}
Basis Basis::lerp(const Basis &p_to, const real_t &p_weight) const {
Basis b;
- b.elements[0] = elements[0].lerp(p_to.elements[0], p_weight);
- b.elements[1] = elements[1].lerp(p_to.elements[1], p_weight);
- b.elements[2] = elements[2].lerp(p_to.elements[2], p_weight);
+ b.rows[0] = rows[0].lerp(p_to.rows[0], p_weight);
+ b.rows[1] = rows[1].lerp(p_to.rows[1], p_weight);
+ b.rows[2] = rows[2].lerp(p_to.rows[2], p_weight);
return b;
}
@@ -976,9 +976,9 @@ Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const {
Quaternion to(p_to);
Basis b(from.slerp(to, p_weight));
- b.elements[0] *= Math::lerp(elements[0].length(), p_to.elements[0].length(), p_weight);
- b.elements[1] *= Math::lerp(elements[1].length(), p_to.elements[1].length(), p_weight);
- b.elements[2] *= Math::lerp(elements[2].length(), p_to.elements[2].length(), p_weight);
+ b.rows[0] *= Math::lerp(rows[0].length(), p_to.rows[0].length(), p_weight);
+ b.rows[1] *= Math::lerp(rows[1].length(), p_to.rows[1].length(), p_weight);
+ b.rows[2] *= Math::lerp(rows[2].length(), p_to.rows[2].length(), p_weight);
return b;
}
@@ -1002,17 +1002,17 @@ void Basis::rotate_sh(real_t *p_values) {
const static real_t s_scale_dst2 = s_c3 * s_c_scale_inv;
const static real_t s_scale_dst4 = s_c5 * s_c_scale_inv;
- real_t src[9] = { p_values[0], p_values[1], p_values[2], p_values[3], p_values[4], p_values[5], p_values[6], p_values[7], p_values[8] };
+ const real_t src[9] = { p_values[0], p_values[1], p_values[2], p_values[3], p_values[4], p_values[5], p_values[6], p_values[7], p_values[8] };
- real_t m00 = elements[0][0];
- real_t m01 = elements[0][1];
- real_t m02 = elements[0][2];
- real_t m10 = elements[1][0];
- real_t m11 = elements[1][1];
- real_t m12 = elements[1][2];
- real_t m20 = elements[2][0];
- real_t m21 = elements[2][1];
- real_t m22 = elements[2][2];
+ real_t m00 = rows[0][0];
+ real_t m01 = rows[0][1];
+ real_t m02 = rows[0][2];
+ real_t m10 = rows[1][0];
+ real_t m11 = rows[1][1];
+ real_t m12 = rows[1][2];
+ real_t m20 = rows[2][0];
+ real_t m21 = rows[2][1];
+ real_t m22 = rows[2][2];
p_values[0] = src[0];
p_values[1] = m11 * src[1] - m12 * src[2] + m10 * src[3];
@@ -1107,6 +1107,6 @@ Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) {
Vector3 v_y = v_z.cross(v_x);
Basis basis;
- basis.set(v_x, v_y, v_z);
+ basis.set_columns(v_x, v_y, v_z);
return basis;
}
diff --git a/core/math/basis.h b/core/math/basis.h
index 683f05150c..9cce22510b 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -35,17 +35,17 @@
#include "core/math/vector3.h"
struct _NO_DISCARD_ Basis {
- Vector3 elements[3] = {
+ Vector3 rows[3] = {
Vector3(1, 0, 0),
Vector3(0, 1, 0),
Vector3(0, 0, 1)
};
_FORCE_INLINE_ const Vector3 &operator[](int axis) const {
- return elements[axis];
+ return rows[axis];
}
_FORCE_INLINE_ Vector3 &operator[](int axis) {
- return elements[axis];
+ return rows[axis];
}
void invert();
@@ -58,22 +58,11 @@ struct _NO_DISCARD_ Basis {
void from_z(const Vector3 &p_z);
- _FORCE_INLINE_ Vector3 get_axis(int p_axis) const {
- // get actual basis axis (elements is transposed for performance)
- return Vector3(elements[0][p_axis], elements[1][p_axis], elements[2][p_axis]);
- }
- _FORCE_INLINE_ void set_axis(int p_axis, const Vector3 &p_value) {
- // get actual basis axis (elements is transposed for performance)
- elements[0][p_axis] = p_value.x;
- elements[1][p_axis] = p_value.y;
- elements[2][p_axis] = p_value.z;
- }
+ void rotate(const Vector3 &p_axis, real_t p_angle);
+ Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
- void rotate(const Vector3 &p_axis, real_t p_phi);
- Basis rotated(const Vector3 &p_axis, real_t p_phi) const;
-
- void rotate_local(const Vector3 &p_axis, real_t p_phi);
- Basis rotated_local(const Vector3 &p_axis, real_t p_phi) const;
+ void rotate_local(const Vector3 &p_axis, real_t p_angle);
+ Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
void rotate(const Vector3 &p_euler);
Basis rotated(const Vector3 &p_euler) const;
@@ -111,7 +100,7 @@ struct _NO_DISCARD_ Basis {
void set_quaternion(const Quaternion &p_quaternion);
void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const;
- void set_axis_angle(const Vector3 &p_axis, real_t p_phi);
+ void set_axis_angle(const Vector3 &p_axis, real_t p_angle);
void scale(const Vector3 &p_scale);
Basis scaled(const Vector3 &p_scale) const;
@@ -129,19 +118,19 @@ struct _NO_DISCARD_ Basis {
Vector3 get_scale_abs() const;
Vector3 get_scale_local() const;
- void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale);
+ void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale);
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
// transposed dot products
_FORCE_INLINE_ real_t tdotx(const Vector3 &v) const {
- return elements[0][0] * v[0] + elements[1][0] * v[1] + elements[2][0] * v[2];
+ return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2];
}
_FORCE_INLINE_ real_t tdoty(const Vector3 &v) const {
- return elements[0][1] * v[0] + elements[1][1] * v[1] + elements[2][1] * v[2];
+ return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2];
}
_FORCE_INLINE_ real_t tdotz(const Vector3 &v) const {
- return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2];
+ return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2];
}
bool is_equal_approx(const Basis &p_basis) const;
@@ -176,55 +165,55 @@ struct _NO_DISCARD_ Basis {
/* create / set */
_FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
- elements[0][0] = xx;
- elements[0][1] = xy;
- elements[0][2] = xz;
- elements[1][0] = yx;
- elements[1][1] = yy;
- elements[1][2] = yz;
- elements[2][0] = zx;
- elements[2][1] = zy;
- elements[2][2] = zz;
- }
- _FORCE_INLINE_ void set(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
- set_axis(0, p_x);
- set_axis(1, p_y);
- set_axis(2, p_z);
+ rows[0][0] = xx;
+ rows[0][1] = xy;
+ rows[0][2] = xz;
+ rows[1][0] = yx;
+ rows[1][1] = yy;
+ rows[1][2] = yz;
+ rows[2][0] = zx;
+ rows[2][1] = zy;
+ rows[2][2] = zz;
}
- _FORCE_INLINE_ Vector3 get_column(int i) const {
- return Vector3(elements[0][i], elements[1][i], elements[2][i]);
+ _FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
+ set_column(0, p_x);
+ set_column(1, p_y);
+ set_column(2, p_z);
}
- _FORCE_INLINE_ Vector3 get_row(int i) const {
- return Vector3(elements[i][0], elements[i][1], elements[i][2]);
+ _FORCE_INLINE_ Vector3 get_column(int p_index) const {
+ // Get actual basis axis column (we store transposed as rows for performance).
+ return Vector3(rows[0][p_index], rows[1][p_index], rows[2][p_index]);
}
- _FORCE_INLINE_ Vector3 get_main_diagonal() const {
- return Vector3(elements[0][0], elements[1][1], elements[2][2]);
+
+ _FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) {
+ // Set actual basis axis column (we store transposed as rows for performance).
+ rows[0][p_index] = p_value.x;
+ rows[1][p_index] = p_value.y;
+ rows[2][p_index] = p_value.z;
}
- _FORCE_INLINE_ void set_row(int i, const Vector3 &p_row) {
- elements[i][0] = p_row.x;
- elements[i][1] = p_row.y;
- elements[i][2] = p_row.z;
+ _FORCE_INLINE_ Vector3 get_main_diagonal() const {
+ return Vector3(rows[0][0], rows[1][1], rows[2][2]);
}
_FORCE_INLINE_ void set_zero() {
- elements[0].zero();
- elements[1].zero();
- elements[2].zero();
+ rows[0].zero();
+ rows[1].zero();
+ rows[2].zero();
}
_FORCE_INLINE_ Basis transpose_xform(const Basis &m) const {
return Basis(
- elements[0].x * m[0].x + elements[1].x * m[1].x + elements[2].x * m[2].x,
- elements[0].x * m[0].y + elements[1].x * m[1].y + elements[2].x * m[2].y,
- elements[0].x * m[0].z + elements[1].x * m[1].z + elements[2].x * m[2].z,
- elements[0].y * m[0].x + elements[1].y * m[1].x + elements[2].y * m[2].x,
- elements[0].y * m[0].y + elements[1].y * m[1].y + elements[2].y * m[2].y,
- elements[0].y * m[0].z + elements[1].y * m[1].z + elements[2].y * m[2].z,
- elements[0].z * m[0].x + elements[1].z * m[1].x + elements[2].z * m[2].x,
- elements[0].z * m[0].y + elements[1].z * m[1].y + elements[2].z * m[2].y,
- elements[0].z * m[0].z + elements[1].z * m[1].z + elements[2].z * m[2].z);
+ rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x,
+ rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y,
+ rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z,
+ rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x,
+ rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y,
+ rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z,
+ rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x,
+ rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y,
+ rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z);
}
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
@@ -248,14 +237,14 @@ struct _NO_DISCARD_ Basis {
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); };
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
- Basis(const Vector3 &p_axis, real_t p_phi) { set_axis_angle(p_axis, p_phi); }
- Basis(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_phi, p_scale); }
+ Basis(const Vector3 &p_axis, real_t p_angle) { set_axis_angle(p_axis, p_angle); }
+ 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) {
- elements[0] = row0;
- elements[1] = row1;
- elements[2] = row2;
+ rows[0] = row0;
+ rows[1] = row1;
+ rows[2] = row2;
}
_FORCE_INLINE_ Basis() {}
@@ -267,22 +256,22 @@ private:
_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) {
set(
- p_matrix.tdotx(elements[0]), p_matrix.tdoty(elements[0]), p_matrix.tdotz(elements[0]),
- p_matrix.tdotx(elements[1]), p_matrix.tdoty(elements[1]), p_matrix.tdotz(elements[1]),
- p_matrix.tdotx(elements[2]), p_matrix.tdoty(elements[2]), p_matrix.tdotz(elements[2]));
+ p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
+ p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
+ p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
}
_FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const {
return Basis(
- p_matrix.tdotx(elements[0]), p_matrix.tdoty(elements[0]), p_matrix.tdotz(elements[0]),
- p_matrix.tdotx(elements[1]), p_matrix.tdoty(elements[1]), p_matrix.tdotz(elements[1]),
- p_matrix.tdotx(elements[2]), p_matrix.tdoty(elements[2]), p_matrix.tdotz(elements[2]));
+ p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
+ p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
+ p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
}
_FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) {
- elements[0] += p_matrix.elements[0];
- elements[1] += p_matrix.elements[1];
- elements[2] += p_matrix.elements[2];
+ rows[0] += p_matrix.rows[0];
+ rows[1] += p_matrix.rows[1];
+ rows[2] += p_matrix.rows[2];
}
_FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const {
@@ -292,9 +281,9 @@ _FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const {
}
_FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) {
- elements[0] -= p_matrix.elements[0];
- elements[1] -= p_matrix.elements[1];
- elements[2] -= p_matrix.elements[2];
+ rows[0] -= p_matrix.rows[0];
+ rows[1] -= p_matrix.rows[1];
+ rows[2] -= p_matrix.rows[2];
}
_FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const {
@@ -304,9 +293,9 @@ _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const {
}
_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) {
- elements[0] *= p_val;
- elements[1] *= p_val;
- elements[2] *= p_val;
+ rows[0] *= p_val;
+ rows[1] *= p_val;
+ rows[2] *= p_val;
}
_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const {
@@ -317,22 +306,22 @@ _FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const {
Vector3 Basis::xform(const Vector3 &p_vector) const {
return Vector3(
- elements[0].dot(p_vector),
- elements[1].dot(p_vector),
- elements[2].dot(p_vector));
+ rows[0].dot(p_vector),
+ rows[1].dot(p_vector),
+ rows[2].dot(p_vector));
}
Vector3 Basis::xform_inv(const Vector3 &p_vector) const {
return Vector3(
- (elements[0][0] * p_vector.x) + (elements[1][0] * p_vector.y) + (elements[2][0] * p_vector.z),
- (elements[0][1] * p_vector.x) + (elements[1][1] * p_vector.y) + (elements[2][1] * p_vector.z),
- (elements[0][2] * p_vector.x) + (elements[1][2] * p_vector.y) + (elements[2][2] * p_vector.z));
+ (rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z),
+ (rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z),
+ (rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z));
}
real_t Basis::determinant() const {
- return elements[0][0] * (elements[1][1] * elements[2][2] - elements[2][1] * elements[1][2]) -
- elements[1][0] * (elements[0][1] * elements[2][2] - elements[2][1] * elements[0][2]) +
- elements[2][0] * (elements[0][1] * elements[1][2] - elements[1][1] * elements[0][2]);
+ return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) -
+ rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) +
+ rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]);
}
#endif // BASIS_H
diff --git a/core/math/bvh.h b/core/math/bvh.h
index a8e3cc7bbe..9f6ab9f736 100644
--- a/core/math/bvh.h
+++ b/core/math/bvh.h
@@ -46,21 +46,35 @@
// Layer masks are implemented in the renderers as a later step, and light_cull_mask appears to be
// implemented in GLES3 but not GLES2. Layer masks are not yet implemented for directional lights.
+// In the physics, the pairable_type is based on 1 << p_object->get_type() where:
+// TYPE_AREA,
+// TYPE_BODY
+// and pairable_mask is either 0 if static, or set to all if non static
+
#include "bvh_tree.h"
+#include "core/os/mutex.h"
-#define BVHTREE_CLASS BVH_Tree<T, 2, MAX_ITEMS, USE_PAIRS, Bounds, Point>
+#define BVHTREE_CLASS BVH_Tree<T, NUM_TREES, 2, MAX_ITEMS, USER_PAIR_TEST_FUNCTION, USER_CULL_TEST_FUNCTION, USE_PAIRS, BOUNDS, POINT>
+#define BVH_LOCKED_FUNCTION BVHLockedFunction(&_mutex, BVH_THREAD_SAFE &&_thread_safe);
-template <class T, bool USE_PAIRS = false, int MAX_ITEMS = 32, class Bounds = AABB, class Point = Vector3>
+template <class T, int NUM_TREES = 1, bool USE_PAIRS = false, int MAX_ITEMS = 32, class USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, class USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, class BOUNDS = AABB, class POINT = Vector3, bool BVH_THREAD_SAFE = true>
class BVH_Manager {
public:
// note we are using uint32_t instead of BVHHandle, losing type safety, but this
// is for compatibility with octree
typedef void *(*PairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int);
typedef void (*UnpairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int, void *);
+ typedef void *(*CheckPairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int, void *);
+
+ // allow locally toggling thread safety if the template has been compiled with BVH_THREAD_SAFE
+ void params_set_thread_safe(bool p_enable) {
+ _thread_safe = p_enable;
+ }
// these 2 are crucial for fine tuning, and can be applied manually
// see the variable declarations for more info.
void params_set_node_expansion(real_t p_value) {
+ BVH_LOCKED_FUNCTION
if (p_value >= 0.0) {
tree._node_expansion = p_value;
tree._auto_node_expansion = false;
@@ -70,43 +84,40 @@ public:
}
void params_set_pairing_expansion(real_t p_value) {
- if (p_value >= 0.0) {
- tree._pairing_expansion = p_value;
- tree._auto_pairing_expansion = false;
- } else {
- tree._auto_pairing_expansion = true;
- }
+ BVH_LOCKED_FUNCTION
+ tree.params_set_pairing_expansion(p_value);
}
void set_pair_callback(PairCallback p_callback, void *p_userdata) {
+ BVH_LOCKED_FUNCTION
pair_callback = p_callback;
pair_callback_userdata = p_userdata;
}
void set_unpair_callback(UnpairCallback p_callback, void *p_userdata) {
+ BVH_LOCKED_FUNCTION
unpair_callback = p_callback;
unpair_callback_userdata = p_userdata;
}
+ void set_check_pair_callback(CheckPairCallback p_callback, void *p_userdata) {
+ BVH_LOCKED_FUNCTION
+ check_pair_callback = p_callback;
+ check_pair_callback_userdata = p_userdata;
+ }
+
+ BVHHandle create(T *p_userdata, bool p_active = true, uint32_t p_tree_id = 0, uint32_t p_tree_collision_mask = 1, const BOUNDS &p_aabb = BOUNDS(), int p_subindex = 0) {
+ BVH_LOCKED_FUNCTION
- BVHHandle create(T *p_userdata, bool p_active, const Bounds &p_aabb = Bounds(), int p_subindex = 0, bool p_pairable = false, uint32_t p_pairable_type = 0, uint32_t p_pairable_mask = 1) {
// not sure if absolutely necessary to flush collisions here. It will cost performance to, instead
// of waiting for update, so only uncomment this if there are bugs.
if (USE_PAIRS) {
//_check_for_collisions();
}
-#ifdef TOOLS_ENABLED
- if (!USE_PAIRS) {
- if (p_pairable) {
- WARN_PRINT_ONCE("creating pairable item in BVH with USE_PAIRS set to false");
- }
- }
-#endif
-
- BVHHandle h = tree.item_add(p_userdata, p_active, p_aabb, p_subindex, p_pairable, p_pairable_type, p_pairable_mask);
+ BVHHandle h = tree.item_add(p_userdata, p_active, p_aabb, p_subindex, p_tree_id, p_tree_collision_mask);
if (USE_PAIRS) {
// for safety initialize the expanded AABB
- Bounds &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
+ BOUNDS &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
expanded_aabb = p_aabb;
expanded_aabb.grow_by(tree._pairing_expansion);
@@ -123,12 +134,18 @@ public:
////////////////////////////////////////////////////
// wrapper versions that use uint32_t instead of handle
// for backward compatibility. Less type safe
- void move(uint32_t p_handle, const Bounds &p_aabb) {
+ void move(uint32_t p_handle, const BOUNDS &p_aabb) {
BVHHandle h;
h.set(p_handle);
move(h, p_aabb);
}
+ void recheck_pairs(uint32_t p_handle) {
+ BVHHandle h;
+ h.set(p_handle);
+ recheck_pairs(h);
+ }
+
void erase(uint32_t p_handle) {
BVHHandle h;
h.set(p_handle);
@@ -141,7 +158,7 @@ public:
force_collision_check(h);
}
- bool activate(uint32_t p_handle, const Bounds &p_aabb, bool p_delay_collision_check = false) {
+ bool activate(uint32_t p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) {
BVHHandle h;
h.set(p_handle);
return activate(h, p_aabb, p_delay_collision_check);
@@ -153,16 +170,16 @@ public:
return deactivate(h);
}
- void set_pairable(uint32_t p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_force_collision_check = true) {
+ void set_tree(uint32_t p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) {
BVHHandle h;
h.set(p_handle);
- set_pairable(h, p_pairable, p_pairable_type, p_pairable_mask, p_force_collision_check);
+ set_tree(h, p_tree_id, p_tree_collision_mask, p_force_collision_check);
}
- bool is_pairable(uint32_t p_handle) const {
+ uint32_t get_tree_id(uint32_t p_handle) const {
BVHHandle h;
h.set(p_handle);
- return item_is_pairable(h);
+ return item_get_tree_id(h);
}
int get_subindex(uint32_t p_handle) const {
BVHHandle h;
@@ -178,7 +195,9 @@ public:
////////////////////////////////////////////////////
- void move(BVHHandle p_handle, const Bounds &p_aabb) {
+ void move(BVHHandle p_handle, const BOUNDS &p_aabb) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ BVH_LOCKED_FUNCTION
if (tree.item_move(p_handle, p_aabb)) {
if (USE_PAIRS) {
_add_changed_item(p_handle, p_aabb);
@@ -186,7 +205,14 @@ public:
}
}
+ void recheck_pairs(BVHHandle p_handle) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ force_collision_check(p_handle);
+ }
+
void erase(BVHHandle p_handle) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ BVH_LOCKED_FUNCTION
// call unpair and remove all references to the item
// before deleting from the tree
if (USE_PAIRS) {
@@ -200,11 +226,13 @@ public:
// use in conjunction with activate if you have deferred the collision check, and
// set pairable has never been called.
- // (deferred collision checks are a workaround for rendering server for historical reasons)
+ // (deferred collision checks are a workaround for visual server for historical reasons)
void force_collision_check(BVHHandle p_handle) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ BVH_LOCKED_FUNCTION
if (USE_PAIRS) {
// the aabb should already be up to date in the BVH
- Bounds aabb;
+ BOUNDS aabb;
item_get_AABB(p_handle, aabb);
// add it as changed even if aabb not different
@@ -218,7 +246,9 @@ public:
// these should be read as set_visible for render trees,
// but generically this makes items add or remove from the
// tree internally, to speed things up by ignoring inactive items
- bool activate(BVHHandle p_handle, const Bounds &p_aabb, bool p_delay_collision_check = false) {
+ bool activate(BVHHandle p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ BVH_LOCKED_FUNCTION
// sending the aabb here prevents the need for the BVH to maintain
// a redundant copy of the aabb.
// returns success
@@ -242,6 +272,8 @@ public:
}
bool deactivate(BVHHandle p_handle) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ BVH_LOCKED_FUNCTION
// returns success
if (tree.item_deactivate(p_handle)) {
// call unpair and remove all references to the item
@@ -258,12 +290,15 @@ public:
return false;
}
- bool get_active(BVHHandle p_handle) const {
+ bool get_active(BVHHandle p_handle) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ BVH_LOCKED_FUNCTION
return tree.item_get_active(p_handle);
}
// call e.g. once per frame (this does a trickle optimize)
void update() {
+ BVH_LOCKED_FUNCTION
tree.update();
_check_for_collisions();
#ifdef BVH_INTEGRITY_CHECKS
@@ -273,24 +308,27 @@ public:
// this can be called more frequently than per frame if necessary
void update_collisions() {
+ BVH_LOCKED_FUNCTION
_check_for_collisions();
}
// prefer calling this directly as type safe
- void set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_force_collision_check = true) {
+ void set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) {
+ DEV_ASSERT(!p_handle.is_invalid());
+ BVH_LOCKED_FUNCTION
// Returns true if the pairing state has changed.
- bool state_changed = tree.item_set_pairable(p_handle, p_pairable, p_pairable_type, p_pairable_mask);
+ bool state_changed = tree.item_set_tree(p_handle, p_tree_id, p_tree_collision_mask);
if (USE_PAIRS) {
// not sure if absolutely necessary to flush collisions here. It will cost performance to, instead
// of waiting for update, so only uncomment this if there are bugs.
//_check_for_collisions();
- if ((p_force_collision_check || state_changed) && get_active(p_handle)) {
+ if ((p_force_collision_check || state_changed) && tree.item_get_active(p_handle)) {
// when the pairable state changes, we need to force a collision check because newly pairable
// items may be in collision, and unpairable items might move out of collision.
// We cannot depend on waiting for the next update, because that may come much later.
- Bounds aabb;
+ BOUNDS aabb;
item_get_AABB(p_handle, aabb);
// passing false disables the optimization which prevents collision checks if
@@ -307,32 +345,33 @@ public:
}
// cull tests
- int cull_aabb(const Bounds &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_aabb(const BOUNDS &p_aabb, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) {
+ BVH_LOCKED_FUNCTION
typename BVHTREE_CLASS::CullParams params;
params.result_count_overall = 0;
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = p_subindex_array;
- params.mask = p_mask;
- params.pairable_type = 0;
- params.test_pairable_only = false;
+ params.tree_collision_mask = p_tree_collision_mask;
params.abb.from(p_aabb);
+ params.tester = p_tester;
tree.cull_aabb(params);
return params.result_count_overall;
}
- int cull_segment(const Point &p_from, const Point &p_to, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_segment(const POINT &p_from, const POINT &p_to, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) {
+ BVH_LOCKED_FUNCTION
typename BVHTREE_CLASS::CullParams params;
params.result_count_overall = 0;
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = p_subindex_array;
- params.mask = p_mask;
- params.pairable_type = 0;
+ params.tester = p_tester;
+ params.tree_collision_mask = p_tree_collision_mask;
params.segment.from = p_from;
params.segment.to = p_to;
@@ -342,15 +381,16 @@ public:
return params.result_count_overall;
}
- int cull_point(const Point &p_point, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_point(const POINT &p_point, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) {
+ BVH_LOCKED_FUNCTION
typename BVHTREE_CLASS::CullParams params;
params.result_count_overall = 0;
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = p_subindex_array;
- params.mask = p_mask;
- params.pairable_type = 0;
+ params.tester = p_tester;
+ params.tree_collision_mask = p_tree_collision_mask;
params.point = p_point;
@@ -358,7 +398,8 @@ public:
return params.result_count_overall;
}
- int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask = 0xFFFFFFFF) {
+ int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF) {
+ BVH_LOCKED_FUNCTION
if (!p_convex.size()) {
return 0;
}
@@ -373,8 +414,8 @@ public:
params.result_max = p_result_max;
params.result_array = p_result_array;
params.subindex_array = nullptr;
- params.mask = p_mask;
- params.pairable_type = 0;
+ params.tester = p_tester;
+ params.tree_collision_mask = p_tree_collision_mask;
params.hull.planes = &p_convex[0];
params.hull.num_planes = p_convex.size();
@@ -394,7 +435,7 @@ private:
return;
}
- Bounds bb;
+ BOUNDS bb;
typename BVHTREE_CLASS::CullParams params;
@@ -402,28 +443,23 @@ private:
params.result_max = INT_MAX;
params.result_array = nullptr;
params.subindex_array = nullptr;
- params.mask = 0xFFFFFFFF;
- params.pairable_type = 0;
for (unsigned int n = 0; n < changed_items.size(); n++) {
const BVHHandle &h = changed_items[n];
// use the expanded aabb for pairing
- const Bounds &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
+ const BOUNDS &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
BVHABB_CLASS abb;
abb.from(expanded_aabb);
+ tree.item_fill_cullparams(h, params);
+
// find all the existing paired aabbs that are no longer
// paired, and send callbacks
_find_leavers(h, abb, p_full_check);
uint32_t changed_item_ref_id = h.id();
- // set up the test from this item.
- // this includes whether to test the non pairable tree,
- // and the item mask.
- tree.item_fill_cullparams(h, params);
-
params.abb = abb;
params.result_count_overall = 0; // might not be needed
@@ -437,13 +473,6 @@ private:
continue;
}
-#ifdef BVH_CHECKS
- // if neither are pairable, they should ignore each other
- // THIS SHOULD NEVER HAPPEN .. now we only test the pairable tree
- // if the changed item is not pairable
- CRASH_COND(params.test_pairable_only && !tree._extra[ref_id].pairable);
-#endif
-
// checkmasks is already done in the cull routine.
BVHHandle h_collidee;
h_collidee.set_id(ref_id);
@@ -456,7 +485,8 @@ private:
}
public:
- void item_get_AABB(BVHHandle p_handle, Bounds &r_aabb) {
+ void item_get_AABB(BVHHandle p_handle, BOUNDS &r_aabb) {
+ DEV_ASSERT(!p_handle.is_invalid());
BVHABB_CLASS abb;
tree.item_get_ABB(p_handle, abb);
abb.to(r_aabb);
@@ -464,7 +494,7 @@ public:
private:
// supplemental funcs
- bool item_is_pairable(BVHHandle p_handle) const { return _get_extra(p_handle).pairable; }
+ uint32_t item_get_tree_id(BVHHandle p_handle) const { return _get_extra(p_handle).tree_id; }
T *item_get_userdata(BVHHandle p_handle) const { return _get_extra(p_handle).userdata; }
int item_get_subindex(BVHHandle p_handle) const { return _get_extra(p_handle).subindex; }
@@ -485,12 +515,35 @@ private:
void *ud_from = pairs_from.remove_pair_to(p_to);
pairs_to.remove_pair_to(p_from);
+#ifdef BVH_VERBOSE_PAIRING
+ print_line("_unpair " + itos(p_from.id()) + " from " + itos(p_to.id()));
+#endif
+
// callback
if (unpair_callback) {
unpair_callback(pair_callback_userdata, p_from, exa.userdata, exa.subindex, p_to, exb.userdata, exb.subindex, ud_from);
}
}
+ void *_recheck_pair(BVHHandle p_from, BVHHandle p_to, void *p_pair_data) {
+ tree._handle_sort(p_from, p_to);
+
+ typename BVHTREE_CLASS::ItemExtra &exa = tree._extra[p_from.id()];
+ typename BVHTREE_CLASS::ItemExtra &exb = tree._extra[p_to.id()];
+
+ // if the userdata is the same, no collisions should occur
+ if ((exa.userdata == exb.userdata) && exa.userdata) {
+ return p_pair_data;
+ }
+
+ // callback
+ if (check_pair_callback) {
+ return check_pair_callback(check_pair_callback_userdata, p_from, exa.userdata, exa.subindex, p_to, exb.userdata, exb.subindex, p_pair_data);
+ }
+
+ return p_pair_data;
+ }
+
// returns true if unpair
bool _find_leavers_process_pair(typename BVHTREE_CLASS::ItemPairs &p_pairs_from, const BVHABB_CLASS &p_abb_from, BVHHandle p_from, BVHHandle p_to, bool p_full_check) {
BVHABB_CLASS abb_to;
@@ -498,8 +551,8 @@ private:
// do they overlap?
if (p_abb_from.intersects(abb_to)) {
- // the full check for pairable / non pairable and mask changes is extra expense
- // this need not be done in most cases (for speed) except in the case where set_pairable is called
+ // the full check for pairable / non pairable (i.e. tree_id and tree_masks) and mask changes is extra expense
+ // this need not be done in most cases (for speed) except in the case where set_tree is called
// where the masks etc of the objects in question may have changed
if (!p_full_check) {
return false;
@@ -507,12 +560,13 @@ private:
const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_from);
const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_to);
- // one of the two must be pairable to still pair
- // if neither are pairable, we always unpair
- if (exa.pairable || exb.pairable) {
+ // Checking tree_ids and tree_collision_masks
+ if (exa.are_item_trees_compatible(exb)) {
+ bool pair_allowed = USER_PAIR_TEST_FUNCTION::user_pair_check(exa.userdata, exb.userdata);
+
// the masks must still be compatible to pair
- // i.e. if there is a hit between the two, then they should stay paired
- if (tree._cull_pairing_mask_test_hit(exa.pairable_mask, exa.pairable_type, exb.pairable_mask, exb.pairable_type)) {
+ // i.e. if there is a hit between the two and they intersect, then they should stay paired
+ if (pair_allowed) {
return false;
}
}
@@ -550,6 +604,11 @@ private:
const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_ha);
const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_hb);
+ // user collision callback
+ if (!USER_PAIR_TEST_FUNCTION::user_pair_check(exa.userdata, exb.userdata)) {
+ return;
+ }
+
// if the userdata is the same, no collisions should occur
if ((exa.userdata == exb.userdata) && exa.userdata) {
return;
@@ -573,6 +632,10 @@ private:
// callback
void *callback_userdata = nullptr;
+#ifdef BVH_VERBOSE_PAIRING
+ print_line("_pair " + itos(p_ha.id()) + " to " + itos(p_hb.id()));
+#endif
+
if (pair_callback) {
callback_userdata = pair_callback(pair_callback_userdata, p_ha, exa.userdata, exa.subindex, p_hb, exb.userdata, exb.subindex);
}
@@ -594,6 +657,32 @@ private:
}
}
+ // Send pair callbacks again for all existing pairs for the given handle.
+ void _recheck_pairs(BVHHandle p_handle) {
+ typename BVHTREE_CLASS::ItemPairs &from = tree._pairs[p_handle.id()];
+
+ // checking pair for every partner.
+ for (unsigned int n = 0; n < from.extended_pairs.size(); n++) {
+ typename BVHTREE_CLASS::ItemPairs::Link &pair = from.extended_pairs[n];
+ BVHHandle h_to = pair.handle;
+ void *new_pair_data = _recheck_pair(p_handle, h_to, pair.userdata);
+
+ if (new_pair_data != pair.userdata) {
+ pair.userdata = new_pair_data;
+
+ // Update pair data for the second item.
+ typename BVHTREE_CLASS::ItemPairs &to = tree._pairs[h_to.id()];
+ for (unsigned int to_index = 0; to_index < to.extended_pairs.size(); to_index++) {
+ typename BVHTREE_CLASS::ItemPairs::Link &to_pair = to.extended_pairs[to_index];
+ if (to_pair.handle == p_handle) {
+ to_pair.userdata = new_pair_data;
+ break;
+ }
+ }
+ }
+ }
+ }
+
private:
const typename BVHTREE_CLASS::ItemExtra &_get_extra(BVHHandle p_handle) const {
return tree._extra[p_handle.id()];
@@ -607,19 +696,24 @@ private:
_tick++;
}
- void _add_changed_item(BVHHandle p_handle, const Bounds &aabb, bool p_check_aabb = true) {
+ void _add_changed_item(BVHHandle p_handle, const BOUNDS &aabb, bool p_check_aabb = true) {
// Note that non pairable items can pair with pairable,
// so all types must be added to the list
+#ifdef BVH_EXPAND_LEAF_AABBS
+ // if using expanded AABB in the leaf, the redundancy check will already have been made
+ BOUNDS &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
+ item_get_AABB(p_handle, expanded_aabb);
+#else
// aabb check with expanded aabb. This greatly decreases processing
// at the cost of slightly less accurate pairing checks
// Note this pairing AABB is separate from the AABB in the actual tree
- Bounds &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
+ BOUNDS &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
// passing p_check_aabb false disables the optimization which prevents collision checks if
// the aabb hasn't changed. This is needed where set_pairable has been called, but the position
// has not changed.
- if (p_check_aabb && expanded_aabb.encloses(aabb)) {
+ if (p_check_aabb && tree.expanded_aabb_encloses_not_shrink(expanded_aabb, aabb)) {
return;
}
@@ -627,6 +721,7 @@ private:
// this tick, because it is vital that the AABB is kept up to date
expanded_aabb = aabb;
expanded_aabb.grow_by(tree._pairing_expansion);
+#endif
// this code is to ensure that changed items only appear once on the updated list
// collision checking them multiple times is not needed, and repeats the same thing
@@ -668,26 +763,54 @@ private:
tree._extra[p_handle.id()].last_updated_tick = 0;
}
- PairCallback pair_callback;
- UnpairCallback unpair_callback;
- void *pair_callback_userdata;
- void *unpair_callback_userdata;
+ PairCallback pair_callback = nullptr;
+ UnpairCallback unpair_callback = nullptr;
+ CheckPairCallback check_pair_callback = nullptr;
+ void *pair_callback_userdata = nullptr;
+ void *unpair_callback_userdata = nullptr;
+ void *check_pair_callback_userdata = nullptr;
BVHTREE_CLASS tree;
// for collision pairing,
// maintain a list of all items moved etc on each frame / tick
LocalVector<BVHHandle, uint32_t, true> changed_items;
- uint32_t _tick;
+ uint32_t _tick = 1; // Start from 1 so items with 0 indicate never updated.
+
+ class BVHLockedFunction {
+ public:
+ BVHLockedFunction(Mutex *p_mutex, bool p_thread_safe) {
+ // will be compiled out if not set in template
+ if (p_thread_safe) {
+ _mutex = p_mutex;
+
+ if (_mutex->try_lock() != OK) {
+ WARN_PRINT("Info : multithread BVH access detected (benign)");
+ _mutex->lock();
+ }
+
+ } else {
+ _mutex = nullptr;
+ }
+ }
+ ~BVHLockedFunction() {
+ // will be compiled out if not set in template
+ if (_mutex) {
+ _mutex->unlock();
+ }
+ }
+
+ private:
+ Mutex *_mutex = nullptr;
+ };
+
+ Mutex _mutex;
+
+ // local toggle for turning on and off thread safety in project settings
+ bool _thread_safe = BVH_THREAD_SAFE;
public:
- BVH_Manager() {
- _tick = 1; // start from 1 so items with 0 indicate never updated
- pair_callback = nullptr;
- unpair_callback = nullptr;
- pair_callback_userdata = nullptr;
- unpair_callback_userdata = nullptr;
- }
+ BVH_Manager() {}
};
#undef BVHTREE_CLASS
diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h
index 009032d34d..8a44f1c4da 100644
--- a/core/math/bvh_abb.h
+++ b/core/math/bvh_abb.h
@@ -32,7 +32,7 @@
#define BVH_ABB_H
// special optimized version of axis aligned bounding box
-template <class Bounds = AABB, class Point = Vector3>
+template <class BOUNDS = AABB, class POINT = Vector3>
struct BVH_ABB {
struct ConvexHull {
// convex hulls (optional)
@@ -43,8 +43,8 @@ struct BVH_ABB {
};
struct Segment {
- Point from;
- Point to;
+ POINT from;
+ POINT to;
};
enum IntersectResult {
@@ -54,47 +54,47 @@ struct BVH_ABB {
};
// we store mins with a negative value in order to test them with SIMD
- Point min;
- Point neg_max;
+ POINT min;
+ POINT neg_max;
bool operator==(const BVH_ABB &o) const { return (min == o.min) && (neg_max == o.neg_max); }
bool operator!=(const BVH_ABB &o) const { return (*this == o) == false; }
- void set(const Point &_min, const Point &_max) {
+ void set(const POINT &_min, const POINT &_max) {
min = _min;
neg_max = -_max;
}
// to and from standard AABB
- void from(const Bounds &p_aabb) {
+ void from(const BOUNDS &p_aabb) {
min = p_aabb.position;
neg_max = -(p_aabb.position + p_aabb.size);
}
- void to(Bounds &r_aabb) const {
+ void to(BOUNDS &r_aabb) const {
r_aabb.position = min;
r_aabb.size = calculate_size();
}
void merge(const BVH_ABB &p_o) {
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
neg_max[axis] = MIN(neg_max[axis], p_o.neg_max[axis]);
min[axis] = MIN(min[axis], p_o.min[axis]);
}
}
- Point calculate_size() const {
+ POINT calculate_size() const {
return -neg_max - min;
}
- Point calculate_centre() const {
- return Point((calculate_size() * 0.5) + min);
+ POINT calculate_centre() const {
+ return POINT((calculate_size() * 0.5) + min);
}
real_t get_proximity_to(const BVH_ABB &p_b) const {
- const Point d = (min - neg_max) - (p_b.min - p_b.neg_max);
+ const POINT d = (min - neg_max) - (p_b.min - p_b.neg_max);
real_t proximity = 0.0;
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
proximity += Math::abs(d[axis]);
}
return proximity;
@@ -104,7 +104,7 @@ struct BVH_ABB {
return (get_proximity_to(p_a) < get_proximity_to(p_b) ? 0 : 1);
}
- uint32_t find_cutting_planes(const BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
+ uint32_t find_cutting_planes(const typename BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
uint32_t count = 0;
for (int n = 0; n < p_hull.num_planes; n++) {
@@ -162,7 +162,7 @@ struct BVH_ABB {
}
bool intersects_convex_partial(const ConvexHull &p_hull) const {
- Bounds bb;
+ BOUNDS bb;
to(bb);
return bb.intersects_convex_shape(p_hull.planes, p_hull.num_planes, p_hull.points, p_hull.num_points);
}
@@ -182,7 +182,7 @@ struct BVH_ABB {
bool is_within_convex(const ConvexHull &p_hull) const {
// use half extents routine
- Bounds bb;
+ BOUNDS bb;
to(bb);
return bb.inside_convex_shape(p_hull.planes, p_hull.num_planes);
}
@@ -197,12 +197,12 @@ struct BVH_ABB {
}
bool intersects_segment(const Segment &p_s) const {
- Bounds bb;
+ BOUNDS bb;
to(bb);
return bb.intersects_segment(p_s.from, p_s.to);
}
- bool intersects_point(const Point &p_pt) const {
+ bool intersects_point(const POINT &p_pt) const {
if (_any_lessthan(-p_pt, neg_max)) {
return false;
}
@@ -212,6 +212,7 @@ struct BVH_ABB {
return true;
}
+ // Very hot in profiling, make sure optimized
bool intersects(const BVH_ABB &p_o) const {
if (_any_morethan(p_o.min, -neg_max)) {
return false;
@@ -222,6 +223,17 @@ struct BVH_ABB {
return true;
}
+ // for pre-swizzled tester (this object)
+ bool intersects_swizzled(const BVH_ABB &p_o) const {
+ if (_any_lessthan(min, p_o.min)) {
+ return false;
+ }
+ if (_any_lessthan(neg_max, p_o.neg_max)) {
+ return false;
+ }
+ return true;
+ }
+
bool is_other_within(const BVH_ABB &p_o) const {
if (_any_lessthan(p_o.neg_max, neg_max)) {
return false;
@@ -232,20 +244,20 @@ struct BVH_ABB {
return true;
}
- void grow(const Point &p_change) {
+ void grow(const POINT &p_change) {
neg_max -= p_change;
min -= p_change;
}
void expand(real_t p_change) {
- Point change;
+ POINT change;
change.set_all(p_change);
grow(change);
}
// Actually surface area metric.
float get_area() const {
- Point d = calculate_size();
+ POINT d = calculate_size();
return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x);
}
@@ -254,8 +266,8 @@ struct BVH_ABB {
min = neg_max;
}
- bool _any_morethan(const Point &p_a, const Point &p_b) const {
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ bool _any_morethan(const POINT &p_a, const POINT &p_b) const {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
if (p_a[axis] > p_b[axis]) {
return true;
}
@@ -263,8 +275,8 @@ struct BVH_ABB {
return false;
}
- bool _any_lessthan(const Point &p_a, const Point &p_b) const {
- for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ bool _any_lessthan(const POINT &p_a, const POINT &p_b) const {
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
if (p_a[axis] < p_b[axis]) {
return true;
}
diff --git a/core/math/bvh_cull.inc b/core/math/bvh_cull.inc
index ab468bfd29..11f50e41e6 100644
--- a/core/math/bvh_cull.inc
+++ b/core/math/bvh_cull.inc
@@ -9,20 +9,22 @@ struct CullParams {
T **result_array;
int *subindex_array;
- // nobody truly understands how masks are intended to work.
- uint32_t mask;
- uint32_t pairable_type;
+ // We now process masks etc in a user template function,
+ // and these for simplicity assume even for cull tests there is a
+ // testing object (which has masks etc) for the user cull checks.
+ // This means for cull tests on their own, the client will usually
+ // want to create a dummy object, just in order to specify masks etc.
+ const T *tester;
// optional components for different tests
- Point point;
+ POINT point;
BVHABB_CLASS abb;
typename BVHABB_CLASS::ConvexHull hull;
typename BVHABB_CLASS::Segment segment;
- // when collision testing, non pairable moving items
- // only need to be tested against the pairable tree.
- // collisions with other non pairable items are irrelevant.
- bool test_pairable_only;
+ // When collision testing, we can specify which tree ids
+ // to collide test against with the tree_collision_mask.
+ uint32_t tree_collision_mask;
};
private:
@@ -58,11 +60,22 @@ int cull_convex(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
+ continue;
+ }
+
_cull_convex_iterative(_root_node_id[n], r_params);
}
@@ -77,11 +90,22 @@ int cull_segment(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
+ continue;
+ }
+
_cull_segment_iterative(_root_node_id[n], r_params);
}
@@ -96,11 +120,22 @@ int cull_point(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
+ continue;
+ }
+
_cull_point_iterative(_root_node_id[n], r_params);
}
@@ -115,12 +150,20 @@ int cull_aabb(CullParams &r_params, bool p_translate_hits = true) {
_cull_hits.clear();
r_params.result_count = 0;
+ uint32_t tree_test_mask = 0;
+
for (int n = 0; n < NUM_TREES; n++) {
+ tree_test_mask <<= 1;
+ if (!tree_test_mask) {
+ tree_test_mask = 1;
+ }
+
if (_root_node_id[n] == BVHCommon::INVALID) {
continue;
}
- if ((n == 0) && r_params.test_pairable_only) {
+ // the tree collision mask determines which trees to collide test against
+ if (!(r_params.tree_collision_mask & tree_test_mask)) {
continue;
}
@@ -142,22 +185,6 @@ bool _cull_hits_full(const CullParams &p) {
return (int)_cull_hits.size() >= p.result_max;
}
-// write this logic once for use in all routines
-// double check this as a possible source of bugs in future.
-bool _cull_pairing_mask_test_hit(uint32_t p_maskA, uint32_t p_typeA, uint32_t p_maskB, uint32_t p_typeB) const {
- // double check this as a possible source of bugs in future.
- bool A_match_B = p_maskA & p_typeB;
-
- if (!A_match_B) {
- bool B_match_A = p_maskB & p_typeA;
- if (!B_match_A) {
- return false;
- }
- }
-
- return true;
-}
-
void _cull_hit(uint32_t p_ref_id, CullParams &p) {
// take into account masks etc
// this would be more efficient to do before plane checks,
@@ -165,7 +192,8 @@ void _cull_hit(uint32_t p_ref_id, CullParams &p) {
if (USE_PAIRS) {
const ItemExtra &ex = _extra[p_ref_id];
- if (!_cull_pairing_mask_test_hit(p.mask, p.pairable_type, ex.pairable_mask, ex.pairable_type)) {
+ // user supplied function (for e.g. pairable types and pairable masks in the render tree)
+ if (!USER_CULL_TEST_FUNCTION::user_cull_check(p.tester, ex.userdata)) {
return;
}
}
@@ -294,6 +322,7 @@ bool _cull_point_iterative(uint32_t p_node_id, CullParams &r_params) {
return true;
}
+// Note: This is a very hot loop profiling wise. Take care when changing this and profile.
bool _cull_aabb_iterative(uint32_t p_node_id, CullParams &r_params, bool p_fully_within = false) {
// our function parameters to keep on a stack
struct CullAABBParams {
@@ -336,16 +365,26 @@ bool _cull_aabb_iterative(uint32_t p_node_id, CullParams &r_params, bool p_fully
_cull_hit(child_id, r_params);
}
} else {
- for (int n = 0; n < leaf.num_items; n++) {
+ // This section is the hottest area in profiling, so
+ // is optimized highly
+ // get this into a local register and preconverted to correct type
+ int leaf_num_items = leaf.num_items;
+
+ BVHABB_CLASS swizzled_tester;
+ swizzled_tester.min = -r_params.abb.neg_max;
+ swizzled_tester.neg_max = -r_params.abb.min;
+
+ for (int n = 0; n < leaf_num_items; n++) {
const BVHABB_CLASS &aabb = leaf.get_aabb(n);
- if (aabb.intersects(r_params.abb)) {
+ if (swizzled_tester.intersects_swizzled(aabb)) {
uint32_t child_id = leaf.get_item_ref_id(n);
// register hit
_cull_hit(child_id, r_params);
}
}
+
} // not fully within
} else {
if (!cap.fully_within) {
diff --git a/core/math/bvh_debug.inc b/core/math/bvh_debug.inc
index 896c36ecf1..2e519ceb3d 100644
--- a/core/math/bvh_debug.inc
+++ b/core/math/bvh_debug.inc
@@ -7,12 +7,12 @@ void _debug_recursive_print_tree(int p_tree_id) const {
}
String _debug_aabb_to_string(const BVHABB_CLASS &aabb) const {
- Point size = aabb.calculate_size();
+ POINT size = aabb.calculate_size();
String sz;
float vol = 0.0;
- for (int i = 0; i < Point::AXES_COUNT; ++i) {
+ for (int i = 0; i < POINT::AXIS_COUNT; ++i) {
sz += "(";
sz += itos(aabb.min[i]);
sz += " ~ ";
diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc
index c65002a9fd..dd3b135bb5 100644
--- a/core/math/bvh_logic.inc
+++ b/core/math/bvh_logic.inc
@@ -42,9 +42,9 @@ BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) {
//--------------------------------------------------------------------------------------------------
/**
- * @file q3DynamicAABBTree.h
- * @author Randy Gaul
- * @date 10/10/2014
+ * @file q3DynamicAABBTree.h
+ * @author Randy Gaul
+ * @date 10/10/2014
* Copyright (c) 2014 Randy Gaul http://www.randygaul.net
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -75,11 +75,11 @@ int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) {
return iA;
}
- /* A
- * / \
- * B C
- * / \ / \
- * D E F G
+ /* A
+ * / \
+ * B C
+ * / \ / \
+ * D E F G
*/
CRASH_COND(A->num_children != 2);
diff --git a/core/math/bvh_misc.inc b/core/math/bvh_misc.inc
index 71aa0e4fe0..9b35a1d36d 100644
--- a/core/math/bvh_misc.inc
+++ b/core/math/bvh_misc.inc
@@ -1,11 +1,7 @@
int _handle_get_tree_id(BVHHandle p_handle) const {
if (USE_PAIRS) {
- int tree = 0;
- if (_extra[p_handle.id()].pairable) {
- tree = 1;
- }
- return tree;
+ return _extra[p_handle.id()].tree_id;
}
return 0;
}
diff --git a/core/math/bvh_pair.inc b/core/math/bvh_pair.inc
index a12acec2b6..7b9c7ce6ae 100644
--- a/core/math/bvh_pair.inc
+++ b/core/math/bvh_pair.inc
@@ -14,10 +14,10 @@ struct ItemPairs {
void clear() {
num_pairs = 0;
extended_pairs.reset();
- expanded_aabb = Bounds();
+ expanded_aabb = BOUNDS();
}
- Bounds expanded_aabb;
+ BOUNDS expanded_aabb;
// maybe we can just use the number in the vector TODO
int32_t num_pairs;
@@ -59,4 +59,14 @@ struct ItemPairs {
return userdata;
}
+
+ // experiment : scale the pairing expansion by the number of pairs.
+ // when the number of pairs is high, the density is high and a lower collision margin is better.
+ // when there are few local pairs, a larger margin is more optimal.
+ real_t scale_expansion_margin(real_t p_margin) const {
+ real_t x = real_t(num_pairs) * (1.0 / 9.0);
+ x = MIN(x, 1.0);
+ x = 1.0 - x;
+ return p_margin * x;
+ }
};
diff --git a/core/math/bvh_public.inc b/core/math/bvh_public.inc
index 2c1e406712..36b0bfeb13 100644
--- a/core/math/bvh_public.inc
+++ b/core/math/bvh_public.inc
@@ -1,5 +1,5 @@
public:
-BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p_subindex, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_invisible = false) {
+BVHHandle item_add(T *p_userdata, bool p_active, const BOUNDS &p_aabb, int32_t p_subindex, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_invisible = false) {
#ifdef BVH_VERBOSE_TREE
VERBOSE_PRINT("\nitem_add BEFORE");
_debug_recursive_print_tree(0);
@@ -9,6 +9,13 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p
BVHABB_CLASS abb;
abb.from(p_aabb);
+ // NOTE that we do not expand the AABB for the first create even if
+ // leaf expansion is switched on. This is for two reasons:
+ // (1) We don't know if this object will move in future, in which case a non-expanded
+ // bound would be better...
+ // (2) We don't yet know how many objects will be paired, which is used to modify
+ // the expansion margin.
+
// handle to be filled with the new item ref
BVHHandle handle;
@@ -40,29 +47,17 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p
extra->active_ref_id = _active_refs.size();
_active_refs.push_back(ref_id);
- if (USE_PAIRS) {
- extra->pairable_mask = p_pairable_mask;
- extra->pairable_type = p_pairable_type;
- extra->pairable = p_pairable;
- } else {
- // just for safety, in case this gets queried etc
- extra->pairable = 0;
- p_pairable = false;
- }
+ extra->tree_id = p_tree_id;
+ extra->tree_collision_mask = p_tree_collision_mask;
// assign to handle to return
handle.set_id(ref_id);
- uint32_t tree_id = 0;
- if (p_pairable) {
- tree_id = 1;
- }
-
- create_root_node(tree_id);
+ create_root_node(p_tree_id);
// we must choose where to add to tree
if (p_active) {
- ref->tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
+ ref->tnode_id = _logic_choose_item_add_node(_root_node_id[p_tree_id], abb);
bool refit = _node_add_item(ref->tnode_id, ref_id, abb);
@@ -70,7 +65,7 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p
// only need to refit from the parent
const TNode &add_node = _nodes[ref->tnode_id];
if (add_node.parent_id != BVHCommon::INVALID) {
- refit_upward_and_balance(add_node.parent_id, tree_id);
+ refit_upward_and_balance(add_node.parent_id, p_tree_id);
}
}
} else {
@@ -103,7 +98,7 @@ void _debug_print_refs() {
}
// returns false if noop
-bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
+bool item_move(BVHHandle p_handle, const BOUNDS &p_aabb) {
uint32_t ref_id = p_handle.id();
// get the reference
@@ -115,10 +110,19 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
BVHABB_CLASS abb;
abb.from(p_aabb);
+#ifdef BVH_EXPAND_LEAF_AABBS
+ if (USE_PAIRS) {
+ // scale the pairing expansion by the number of pairs.
+ abb.expand(_pairs[ref_id].scale_expansion_margin(_pairing_expansion));
+ } else {
+ abb.expand(_pairing_expansion);
+ }
+#endif
+
BVH_ASSERT(ref.tnode_id != BVHCommon::INVALID);
TNode &tnode = _nodes[ref.tnode_id];
- // does it fit within the current aabb?
+ // does it fit within the current leaf aabb?
if (tnode.aabb.is_other_within(abb)) {
// do nothing .. fast path .. not moved enough to need refit
@@ -129,9 +133,24 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
BVHABB_CLASS &leaf_abb = leaf.get_aabb(ref.item_id);
// no change?
+#ifdef BVH_EXPAND_LEAF_AABBS
+ BOUNDS leaf_aabb;
+ leaf_abb.to(leaf_aabb);
+
+ // This test should pass in a lot of cases, and by returning false we can avoid
+ // collision pairing checks later, which greatly reduces processing.
+ if (expanded_aabb_encloses_not_shrink(leaf_aabb, p_aabb)) {
+ return false;
+ }
+#else
if (leaf_abb == abb) {
return false;
}
+#endif
+
+#ifdef BVH_VERBOSE_MOVES
+ print_line("item_move " + itos(p_handle.id()) + "(within tnode aabb) : " + _debug_aabb_to_string(abb));
+#endif
leaf_abb = abb;
_integrity_check_all();
@@ -139,6 +158,10 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
return true;
}
+#ifdef BVH_VERBOSE_MOVES
+ print_line("item_move " + itos(p_handle.id()) + "(outside tnode aabb) : " + _debug_aabb_to_string(abb));
+#endif
+
uint32_t tree_id = _handle_get_tree_id(p_handle);
// remove and reinsert
@@ -206,7 +229,7 @@ void item_remove(BVHHandle p_handle) {
}
// returns success
-bool item_activate(BVHHandle p_handle, const Bounds &p_aabb) {
+bool item_activate(BVHHandle p_handle, const BOUNDS &p_aabb) {
uint32_t ref_id = p_handle.id();
ItemRef &ref = _refs[ref_id];
if (ref.is_active()) {
@@ -260,12 +283,14 @@ void item_fill_cullparams(BVHHandle p_handle, CullParams &r_params) const {
uint32_t ref_id = p_handle.id();
const ItemExtra &extra = _extra[ref_id];
- // testing from a non pairable item, we only want to test pairable items
- r_params.test_pairable_only = extra.pairable == 0;
+ // which trees does this item want to collide detect against?
+ r_params.tree_collision_mask = extra.tree_collision_mask;
- // we take into account the mask of the item testing from
- r_params.mask = extra.pairable_mask;
- r_params.pairable_type = extra.pairable_type;
+ // The testing user defined object is passed to the user defined cull check function
+ // for masks etc. This is usually a dummy object of type T with masks set.
+ // However, if not using the cull_check callback (i.e. returning true), you can pass
+ // a nullptr instead of dummy object, as it will not be used.
+ r_params.tester = extra.userdata;
}
bool item_is_pairable(const BVHHandle &p_handle) {
@@ -285,7 +310,7 @@ void item_get_ABB(const BVHHandle &p_handle, BVHABB_CLASS &r_abb) {
r_abb = leaf.get_aabb(ref.item_id);
}
-bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) {
+bool item_set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask) {
// change tree?
uint32_t ref_id = p_handle.id();
@@ -293,13 +318,15 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa
ItemRef &ref = _refs[ref_id];
bool active = ref.is_active();
- bool pairable_changed = (ex.pairable != 0) != p_pairable;
- bool state_changed = pairable_changed || (ex.pairable_type != p_pairable_type) || (ex.pairable_mask != p_pairable_mask);
+ bool tree_changed = ex.tree_id != p_tree_id;
+ bool mask_changed = ex.tree_collision_mask != p_tree_collision_mask;
+ bool state_changed = tree_changed | mask_changed;
- ex.pairable_type = p_pairable_type;
- ex.pairable_mask = p_pairable_mask;
+ // Keep an eye on this for bugs of not noticing changes to objects,
+ // especially when changing client user masks that will not be detected as a change
+ // in the BVH. You may need to force a collision check in this case with recheck_pairs().
- if (active && pairable_changed) {
+ if (active && (tree_changed | mask_changed)) {
// record abb
TNode &tnode = _nodes[ref.tnode_id];
TLeaf &leaf = _node_get_leaf(tnode);
@@ -313,7 +340,8 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa
// we must set the pairable AFTER getting the current tree
// because the pairable status determines which tree
- ex.pairable = p_pairable;
+ ex.tree_id = p_tree_id;
+ ex.tree_collision_mask = p_tree_collision_mask;
// add to new tree
tree_id = _handle_get_tree_id(p_handle);
@@ -333,7 +361,8 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa
}
} else {
// always keep this up to date
- ex.pairable = p_pairable;
+ ex.tree_id = p_tree_id;
+ ex.tree_collision_mask = p_tree_collision_mask;
}
return state_changed;
@@ -403,7 +432,7 @@ void update() {
// if there are no nodes, do nothing, but if there are...
if (bound_valid) {
- Bounds bb;
+ BOUNDS bb;
world_bound.to(bb);
real_t size = bb.get_longest_axis_size();
@@ -421,3 +450,50 @@ void update() {
}
#endif
}
+
+void params_set_pairing_expansion(real_t p_value) {
+ if (p_value < 0.0) {
+#ifdef BVH_ALLOW_AUTO_EXPANSION
+ _auto_pairing_expansion = true;
+#endif
+ return;
+ }
+#ifdef BVH_ALLOW_AUTO_EXPANSION
+ _auto_pairing_expansion = false;
+#endif
+
+ _pairing_expansion = p_value;
+
+ // calculate shrinking threshold
+ const real_t fudge_factor = 1.1;
+ _aabb_shrinkage_threshold = _pairing_expansion * POINT::AXIS_COUNT * 2.0 * fudge_factor;
+}
+
+// This routine is not just an enclose check, it also checks for special case of shrinkage
+bool expanded_aabb_encloses_not_shrink(const BOUNDS &p_expanded_aabb, const BOUNDS &p_aabb) const {
+ if (!p_expanded_aabb.encloses(p_aabb)) {
+ return false;
+ }
+
+ // Check for special case of shrinkage. If the aabb has shrunk
+ // significantly we want to create a new expanded bound, because
+ // the previous expanded bound will have diverged significantly.
+ const POINT &exp_size = p_expanded_aabb.size;
+ const POINT &new_size = p_aabb.size;
+
+ real_t exp_l = 0.0;
+ real_t new_l = 0.0;
+
+ for (int i = 0; i < POINT::AXIS_COUNT; ++i) {
+ exp_l += exp_size[i];
+ new_l += new_size[i];
+ }
+
+ // is difference above some metric
+ real_t diff = exp_l - new_l;
+ if (diff < _aabb_shrinkage_threshold) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc
index f19ee8a7da..ff07166d4a 100644
--- a/core/math/bvh_split.inc
+++ b/core/math/bvh_split.inc
@@ -25,16 +25,16 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
return;
}
- Point centre = full_bound.calculate_centre();
- Point size = full_bound.calculate_size();
+ POINT centre = full_bound.calculate_centre();
+ POINT size = full_bound.calculate_size();
- int order[Point::AXIS_COUNT];
+ int order[POINT::AXIS_COUNT];
order[0] = size.min_axis_index();
- order[Point::AXIS_COUNT - 1] = size.max_axis_index();
+ order[POINT::AXIS_COUNT - 1] = size.max_axis_index();
- static_assert(Point::AXIS_COUNT <= 3);
- if (Point::AXIS_COUNT == 3) {
+ static_assert(POINT::AXIS_COUNT <= 3, "BVH POINT::AXIS_COUNT has unexpected size");
+ if (POINT::AXIS_COUNT == 3) {
order[1] = 3 - (order[0] + order[2]);
}
@@ -58,7 +58,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
// detect when split on longest axis failed
int min_threshold = MAX_ITEMS / 4;
- int min_group_size[Point::AXIS_COUNT];
+ int min_group_size[POINT::AXIS_COUNT];
min_group_size[0] = MIN(num_a, num_b);
if (min_group_size[0] < min_threshold) {
// slow but sure .. first move everything back into a
@@ -68,7 +68,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
num_b = 0;
// now calculate the best split
- for (int axis = 1; axis < Point::AXIS_COUNT; axis++) {
+ for (int axis = 1; axis < POINT::AXIS_COUNT; axis++) {
split_axis = order[axis];
int count = 0;
@@ -86,7 +86,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
// best axis
int best_axis = 0;
int best_min = min_group_size[0];
- for (int axis = 1; axis < Point::AXIS_COUNT; axis++) {
+ for (int axis = 1; axis < POINT::AXIS_COUNT; axis++) {
if (min_group_size[axis] > best_min) {
best_min = min_group_size[axis];
best_axis = axis;
diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc
index 1d1e0e6468..58c8f0479a 100644
--- a/core/math/bvh_structs.inc
+++ b/core/math/bvh_structs.inc
@@ -14,25 +14,38 @@ struct ItemRef {
// extra info kept in separate parallel list to the references,
// as this is less used as keeps cache better
struct ItemExtra {
- uint32_t last_updated_tick;
- uint32_t pairable;
- uint32_t pairable_mask;
- uint32_t pairable_type;
+ // Before doing user defined pairing checks (especially in the find_leavers function),
+ // we may want to check that two items have compatible tree ids and tree masks,
+ // as if they are incompatible they should not pair / collide.
+ bool are_item_trees_compatible(const ItemExtra &p_other) const {
+ uint32_t other_type = 1 << p_other.tree_id;
+ if (tree_collision_mask & other_type) {
+ return true;
+ }
+ uint32_t our_type = 1 << tree_id;
+ if (p_other.tree_collision_mask & our_type) {
+ return true;
+ }
+ return false;
+ }
+
+ // There can be multiple user defined trees
+ uint32_t tree_id;
+
+ // Defines which trees this item should collision check against.
+ // 1 << tree_id, and normally items would collide against there own
+ // tree (but not always).
+ uint32_t tree_collision_mask;
+ uint32_t last_updated_tick;
int32_t subindex;
+ T *userdata;
+
// the active reference is a separate list of which references
// are active so that we can slowly iterate through it over many frames for
// slow optimize.
uint32_t active_ref_id;
-
- T *userdata;
-};
-
-// this is an item OR a child node depending on whether a leaf node
-struct Item {
- BVHABB_CLASS aabb;
- uint32_t item_ref_id;
};
// tree leaf
@@ -47,11 +60,23 @@ private:
public:
// accessors
- BVHABB_CLASS &get_aabb(uint32_t p_id) { return aabbs[p_id]; }
- const BVHABB_CLASS &get_aabb(uint32_t p_id) const { return aabbs[p_id]; }
+ BVHABB_CLASS &get_aabb(uint32_t p_id) {
+ BVH_ASSERT(p_id < MAX_ITEMS);
+ return aabbs[p_id];
+ }
+ const BVHABB_CLASS &get_aabb(uint32_t p_id) const {
+ BVH_ASSERT(p_id < MAX_ITEMS);
+ return aabbs[p_id];
+ }
- uint32_t &get_item_ref_id(uint32_t p_id) { return item_ref_ids[p_id]; }
- const uint32_t &get_item_ref_id(uint32_t p_id) const { return item_ref_ids[p_id]; }
+ uint32_t &get_item_ref_id(uint32_t p_id) {
+ BVH_ASSERT(p_id < MAX_ITEMS);
+ return item_ref_ids[p_id];
+ }
+ const uint32_t &get_item_ref_id(uint32_t p_id) const {
+ BVH_ASSERT(p_id < MAX_ITEMS);
+ return item_ref_ids[p_id];
+ }
bool is_dirty() const { return dirty; }
void set_dirty(bool p) { dirty = p; }
@@ -133,13 +158,13 @@ struct TNode {
// instead of using linked list we maintain
// item references (for quick lookup)
-PooledList<ItemRef, true> _refs;
-PooledList<ItemExtra, true> _extra;
+PooledList<ItemRef, uint32_t, true> _refs;
+PooledList<ItemExtra, uint32_t, true> _extra;
PooledList<ItemPairs> _pairs;
// these 2 are not in sync .. nodes != leaves!
-PooledList<TNode, true> _nodes;
-PooledList<TLeaf, true> _leaves;
+PooledList<TNode, uint32_t, true> _nodes;
+PooledList<TLeaf, uint32_t, true> _leaves;
// we can maintain an un-ordered list of which references are active,
// in order to do a slow incremental optimize of the tree over each frame.
@@ -152,15 +177,11 @@ uint32_t _current_active_ref = 0;
// for pairing collision detection
LocalVector<uint32_t, uint32_t, true> _cull_hits;
-// we now have multiple root nodes, allowing us to store
-// more than 1 tree. This can be more efficient, while sharing the same
-// common lists
-enum { NUM_TREES = 2,
-};
-
-// Tree 0 - Non pairable
-// Tree 1 - Pairable
-// This is more efficient because in physics we only need check non pairable against the pairable tree.
+// We can now have a user definable number of trees.
+// This allows using e.g. a non-pairable and pairable tree,
+// which can be more efficient for example, if we only need check non pairable against the pairable tree.
+// It also may be more efficient in terms of separating static from dynamic objects, by reducing housekeeping.
+// However this is a trade off, as there is a cost of traversing two trees.
uint32_t _root_node_id[NUM_TREES];
// these values may need tweaking according to the project
@@ -177,4 +198,14 @@ bool _auto_node_expansion = true;
// larger values gives more 'sticky' pairing, and is less likely to exhibit tunneling
// we can either use auto mode, where the expansion is based on the root node size, or specify manually
real_t _pairing_expansion = 0.1;
+
+#ifdef BVH_ALLOW_AUTO_EXPANSION
bool _auto_pairing_expansion = true;
+#endif
+
+// when using an expanded bound, we must detect the condition where a new AABB
+// is significantly smaller than the expanded bound, as this is a special case where we
+// should override the optimization and create a new expanded bound.
+// This threshold is derived from the _pairing_expansion, and should be recalculated
+// if _pairing_expansion is changed.
+real_t _aabb_shrinkage_threshold = 0.0;
diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h
index c948d83456..cdb2bb4413 100644
--- a/core/math/bvh_tree.h
+++ b/core/math/bvh_tree.h
@@ -48,12 +48,17 @@
#include "core/templates/pooled_list.h"
#include <limits.h>
-#define BVHABB_CLASS BVH_ABB<Bounds, Point>
+#define BVHABB_CLASS BVH_ABB<BOUNDS, POINT>
+
+// not sure if this is better yet so making optional
+#define BVH_EXPAND_LEAF_AABBS
// never do these checks in release
-#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
+#ifdef DEV_ENABLED
//#define BVH_VERBOSE
//#define BVH_VERBOSE_TREE
+//#define BVH_VERBOSE_PAIRING
+//#define BVH_VERBOSE_MOVES
//#define BVH_VERBOSE_FRAME
//#define BVH_CHECKS
@@ -148,7 +153,25 @@ public:
}
};
-template <class T, int MAX_CHILDREN, int MAX_ITEMS, bool USE_PAIRS = false, class Bounds = AABB, class Point = Vector3>
+template <class T>
+class BVH_DummyPairTestFunction {
+public:
+ static bool user_collision_check(T *p_a, T *p_b) {
+ // return false if no collision, decided by masks etc
+ return true;
+ }
+};
+
+template <class T>
+class BVH_DummyCullTestFunction {
+public:
+ static bool user_cull_check(T *p_a, T *p_b) {
+ // return false if no collision
+ return true;
+ }
+};
+
+template <class T, int NUM_TREES, int MAX_CHILDREN, int MAX_ITEMS, class USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, class USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, bool USE_PAIRS = false, class BOUNDS = AABB, class POINT = Vector3>
class BVH_Tree {
friend class BVH;
@@ -165,6 +188,11 @@ public:
// (as these ids are stored as negative numbers in the node)
uint32_t dummy_leaf_id;
_leaves.request(dummy_leaf_id);
+
+ // In many cases you may want to change this default in the client code,
+ // or expose this value to the user.
+ // This default may make sense for a typically scaled 3d game, but maybe not for 2d on a pixel scale.
+ params_set_pairing_expansion(0.1);
}
private:
@@ -189,7 +217,7 @@ private:
BVH_ASSERT(!parent.is_leaf());
int child_num = parent.find_child(p_old_child_id);
- BVH_ASSERT(child_num != BVHCommon::INVALID);
+ BVH_ASSERT(child_num != -1);
parent.children[child_num] = p_new_child_id;
TNode &new_child = _nodes[p_new_child_id];
@@ -201,7 +229,7 @@ private:
BVH_ASSERT(!parent.is_leaf());
int child_num = parent.find_child(p_child_id);
- BVH_ASSERT(child_num != BVHCommon::INVALID);
+ BVH_ASSERT(child_num != -1);
parent.remove_child_internal(child_num);
@@ -234,7 +262,7 @@ private:
change_root_node(sibling_id, p_tree_id);
// delete the old root node as no longer needed
- _nodes.free(p_parent_id);
+ node_free_node_and_leaf(p_parent_id);
}
return;
@@ -247,7 +275,19 @@ private:
}
// put the node on the free list to recycle
- _nodes.free(p_parent_id);
+ node_free_node_and_leaf(p_parent_id);
+ }
+
+ // A node can either be a node, or a node AND a leaf combo.
+ // Both must be deleted to prevent a leak.
+ void node_free_node_and_leaf(uint32_t p_node_id) {
+ TNode &node = _nodes[p_node_id];
+ if (node.is_leaf()) {
+ int leaf_id = node.get_leaf_id();
+ _leaves.free(leaf_id);
+ }
+
+ _nodes.free(p_node_id);
}
void change_root_node(uint32_t p_new_root_id, uint32_t p_tree_id) {
@@ -339,7 +379,7 @@ private:
refit_upward(parent_id);
// put the node on the free list to recycle
- _nodes.free(owner_node_id);
+ node_free_node_and_leaf(owner_node_id);
}
// else if no parent, it is the root node. Do not delete
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index f5d746ef0f..9443addd22 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -436,9 +436,7 @@ void CameraMatrix::invert() {
int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
real_t pvt_val; /* Value of current pivot element */
real_t hold; /* Temporary storage */
- real_t determinat; /* Determinant */
-
- determinat = 1.0;
+ real_t determinant = 1.0f;
for (k = 0; k < 4; k++) {
/** Locate k'th pivot element **/
pvt_val = matrix[k][k]; /** Initialize for search **/
@@ -446,7 +444,7 @@ void CameraMatrix::invert() {
pvt_j[k] = k;
for (i = k; i < 4; i++) {
for (j = k; j < 4; j++) {
- if (Math::absd(matrix[i][j]) > Math::absd(pvt_val)) {
+ if (Math::abs(matrix[i][j]) > Math::abs(pvt_val)) {
pvt_i[k] = i;
pvt_j[k] = j;
pvt_val = matrix[i][j];
@@ -455,9 +453,9 @@ void CameraMatrix::invert() {
}
/** Product of pivots, gives determinant when finished **/
- determinat *= pvt_val;
- if (Math::absd(determinat) < 1e-7) {
- return; //(false); /** Matrix is singular (zero determinant). **/
+ determinant *= pvt_val;
+ if (Math::is_zero_approx(determinant)) {
+ return; /** Matrix is singular (zero determinant). **/
}
/** "Interchange" rows (with sign change stuff) **/
@@ -716,17 +714,17 @@ CameraMatrix::operator Transform3D() const {
Transform3D tr;
const real_t *m = &matrix[0][0];
- tr.basis.elements[0][0] = m[0];
- tr.basis.elements[1][0] = m[1];
- tr.basis.elements[2][0] = m[2];
+ tr.basis.rows[0][0] = m[0];
+ tr.basis.rows[1][0] = m[1];
+ tr.basis.rows[2][0] = m[2];
- tr.basis.elements[0][1] = m[4];
- tr.basis.elements[1][1] = m[5];
- tr.basis.elements[2][1] = m[6];
+ tr.basis.rows[0][1] = m[4];
+ tr.basis.rows[1][1] = m[5];
+ tr.basis.rows[2][1] = m[6];
- tr.basis.elements[0][2] = m[8];
- tr.basis.elements[1][2] = m[9];
- tr.basis.elements[2][2] = m[10];
+ tr.basis.rows[0][2] = m[8];
+ tr.basis.rows[1][2] = m[9];
+ tr.basis.rows[2][2] = m[10];
tr.origin.x = m[12];
tr.origin.y = m[13];
@@ -739,17 +737,17 @@ CameraMatrix::CameraMatrix(const Transform3D &p_transform) {
const Transform3D &tr = p_transform;
real_t *m = &matrix[0][0];
- m[0] = tr.basis.elements[0][0];
- m[1] = tr.basis.elements[1][0];
- m[2] = tr.basis.elements[2][0];
+ m[0] = tr.basis.rows[0][0];
+ m[1] = tr.basis.rows[1][0];
+ m[2] = tr.basis.rows[2][0];
m[3] = 0.0;
- m[4] = tr.basis.elements[0][1];
- m[5] = tr.basis.elements[1][1];
- m[6] = tr.basis.elements[2][1];
+ m[4] = tr.basis.rows[0][1];
+ m[5] = tr.basis.rows[1][1];
+ m[6] = tr.basis.rows[2][1];
m[7] = 0.0;
- m[8] = tr.basis.elements[0][2];
- m[9] = tr.basis.elements[1][2];
- m[10] = tr.basis.elements[2][2];
+ m[8] = tr.basis.rows[0][2];
+ m[9] = tr.basis.rows[1][2];
+ m[10] = tr.basis.rows[2][2];
m[11] = 0.0;
m[12] = tr.origin.x;
m[13] = tr.origin.y;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 285d2ae384..f1aea5e4e8 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -33,6 +33,7 @@
#include "core/math/math_defs.h"
#include "core/math/vector3.h"
+#include "core/templates/vector.h"
struct AABB;
struct Plane;
diff --git a/core/math/color.h b/core/math/color.h
index 429807e4a6..91e0bf5532 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -138,7 +138,7 @@ struct _NO_DISCARD_ Color {
float cMax = MAX(cRed, MAX(cGreen, cBlue));
- float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B;
+ float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
@@ -169,14 +169,14 @@ struct _NO_DISCARD_ Color {
return res;
}
- _FORCE_INLINE_ Color to_linear() const {
+ _FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
r < 0.04045f ? r * (1.0 / 12.92) : Math::pow((r + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
g < 0.04045f ? g * (1.0 / 12.92) : Math::pow((g + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
b < 0.04045f ? b * (1.0 / 12.92) : Math::pow((b + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
a);
}
- _FORCE_INLINE_ Color to_srgb() const {
+ _FORCE_INLINE_ Color linear_to_srgb() const {
return Color(
r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math::pow(r, 1.0f / 2.4f) - 0.055f,
g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math::pow(g, 1.0f / 2.4f) - 0.055f,
diff --git a/core/math/color_names.inc b/core/math/color_names.inc
index 2020bdbfca..654fa83877 100644
--- a/core/math/color_names.inc
+++ b/core/math/color_names.inc
@@ -13,151 +13,151 @@ struct NamedColor {
// modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
static NamedColor named_colors[] = {
- { "ALICE_BLUE", Color(0.94, 0.97, 1.00) },
- { "ANTIQUE_WHITE", Color(0.98, 0.92, 0.84) },
- { "AQUA", Color(0.00, 1.00, 1.00) },
- { "AQUAMARINE", Color(0.50, 1.00, 0.83) },
- { "AZURE", Color(0.94, 1.00, 1.00) },
- { "BEIGE", Color(0.96, 0.96, 0.86) },
- { "BISQUE", Color(1.00, 0.89, 0.77) },
- { "BLACK", Color(0.00, 0.00, 0.00) },
- { "BLANCHED_ALMOND", Color(1.00, 0.92, 0.80) },
- { "BLUE", Color(0.00, 0.00, 1.00) },
- { "BLUE_VIOLET", Color(0.54, 0.17, 0.89) },
- { "BROWN", Color(0.65, 0.16, 0.16) },
- { "BURLYWOOD", Color(0.87, 0.72, 0.53) },
- { "CADET_BLUE", Color(0.37, 0.62, 0.63) },
- { "CHARTREUSE", Color(0.50, 1.00, 0.00) },
- { "CHOCOLATE", Color(0.82, 0.41, 0.12) },
- { "CORAL", Color(1.00, 0.50, 0.31) },
- { "CORNFLOWER_BLUE", Color(0.39, 0.58, 0.93) },
- { "CORNSILK", Color(1.00, 0.97, 0.86) },
- { "CRIMSON", Color(0.86, 0.08, 0.24) },
- { "CYAN", Color(0.00, 1.00, 1.00) },
- { "DARK_BLUE", Color(0.00, 0.00, 0.55) },
- { "DARK_CYAN", Color(0.00, 0.55, 0.55) },
- { "DARK_GOLDENROD", Color(0.72, 0.53, 0.04) },
- { "DARK_GRAY", Color(0.66, 0.66, 0.66) },
- { "DARK_GREEN", Color(0.00, 0.39, 0.00) },
- { "DARK_KHAKI", Color(0.74, 0.72, 0.42) },
- { "DARK_MAGENTA", Color(0.55, 0.00, 0.55) },
- { "DARK_OLIVE_GREEN", Color(0.33, 0.42, 0.18) },
- { "DARK_ORANGE", Color(1.00, 0.55, 0.00) },
- { "DARK_ORCHID", Color(0.60, 0.20, 0.80) },
- { "DARK_RED", Color(0.55, 0.00, 0.00) },
- { "DARK_SALMON", Color(0.91, 0.59, 0.48) },
- { "DARK_SEA_GREEN", Color(0.56, 0.74, 0.56) },
- { "DARK_SLATE_BLUE", Color(0.28, 0.24, 0.55) },
- { "DARK_SLATE_GRAY", Color(0.18, 0.31, 0.31) },
- { "DARK_TURQUOISE", Color(0.00, 0.81, 0.82) },
- { "DARK_VIOLET", Color(0.58, 0.00, 0.83) },
- { "DEEP_PINK", Color(1.00, 0.08, 0.58) },
- { "DEEP_SKY_BLUE", Color(0.00, 0.75, 1.00) },
- { "DIM_GRAY", Color(0.41, 0.41, 0.41) },
- { "DODGER_BLUE", Color(0.12, 0.56, 1.00) },
- { "FIREBRICK", Color(0.70, 0.13, 0.13) },
- { "FLORAL_WHITE", Color(1.00, 0.98, 0.94) },
- { "FOREST_GREEN", Color(0.13, 0.55, 0.13) },
- { "FUCHSIA", Color(1.00, 0.00, 1.00) },
- { "GAINSBORO", Color(0.86, 0.86, 0.86) },
- { "GHOST_WHITE", Color(0.97, 0.97, 1.00) },
- { "GOLD", Color(1.00, 0.84, 0.00) },
- { "GOLDENROD", Color(0.85, 0.65, 0.13) },
- { "GRAY", Color(0.75, 0.75, 0.75) },
- { "GREEN", Color(0.00, 1.00, 0.00) },
- { "GREEN_YELLOW", Color(0.68, 1.00, 0.18) },
- { "HONEYDEW", Color(0.94, 1.00, 0.94) },
- { "HOT_PINK", Color(1.00, 0.41, 0.71) },
- { "INDIAN_RED", Color(0.80, 0.36, 0.36) },
- { "INDIGO", Color(0.29, 0.00, 0.51) },
- { "IVORY", Color(1.00, 1.00, 0.94) },
- { "KHAKI", Color(0.94, 0.90, 0.55) },
- { "LAVENDER", Color(0.90, 0.90, 0.98) },
- { "LAVENDER_BLUSH", Color(1.00, 0.94, 0.96) },
- { "LAWN_GREEN", Color(0.49, 0.99, 0.00) },
- { "LEMON_CHIFFON", Color(1.00, 0.98, 0.80) },
- { "LIGHT_BLUE", Color(0.68, 0.85, 0.90) },
- { "LIGHT_CORAL", Color(0.94, 0.50, 0.50) },
- { "LIGHT_CYAN", Color(0.88, 1.00, 1.00) },
- { "LIGHT_GOLDENROD", Color(0.98, 0.98, 0.82) },
- { "LIGHT_GRAY", Color(0.83, 0.83, 0.83) },
- { "LIGHT_GREEN", Color(0.56, 0.93, 0.56) },
- { "LIGHT_PINK", Color(1.00, 0.71, 0.76) },
- { "LIGHT_SALMON", Color(1.00, 0.63, 0.48) },
- { "LIGHT_SEA_GREEN", Color(0.13, 0.70, 0.67) },
- { "LIGHT_SKY_BLUE", Color(0.53, 0.81, 0.98) },
- { "LIGHT_SLATE_GRAY", Color(0.47, 0.53, 0.60) },
- { "LIGHT_STEEL_BLUE", Color(0.69, 0.77, 0.87) },
- { "LIGHT_YELLOW", Color(1.00, 1.00, 0.88) },
- { "LIME", Color(0.00, 1.00, 0.00) },
- { "LIME_GREEN", Color(0.20, 0.80, 0.20) },
- { "LINEN", Color(0.98, 0.94, 0.90) },
- { "MAGENTA", Color(1.00, 0.00, 1.00) },
- { "MAROON", Color(0.69, 0.19, 0.38) },
- { "MEDIUM_AQUAMARINE", Color(0.40, 0.80, 0.67) },
- { "MEDIUM_BLUE", Color(0.00, 0.00, 0.80) },
- { "MEDIUM_ORCHID", Color(0.73, 0.33, 0.83) },
- { "MEDIUM_PURPLE", Color(0.58, 0.44, 0.86) },
- { "MEDIUM_SEA_GREEN", Color(0.24, 0.70, 0.44) },
- { "MEDIUM_SLATE_BLUE", Color(0.48, 0.41, 0.93) },
- { "MEDIUM_SPRING_GREEN", Color(0.00, 0.98, 0.60) },
- { "MEDIUM_TURQUOISE", Color(0.28, 0.82, 0.80) },
- { "MEDIUM_VIOLET_RED", Color(0.78, 0.08, 0.52) },
- { "MIDNIGHT_BLUE", Color(0.10, 0.10, 0.44) },
- { "MINT_CREAM", Color(0.96, 1.00, 0.98) },
- { "MISTY_ROSE", Color(1.00, 0.89, 0.88) },
- { "MOCCASIN", Color(1.00, 0.89, 0.71) },
- { "NAVAJO_WHITE", Color(1.00, 0.87, 0.68) },
- { "NAVY_BLUE", Color(0.00, 0.00, 0.50) },
- { "OLD_LACE", Color(0.99, 0.96, 0.90) },
- { "OLIVE", Color(0.50, 0.50, 0.00) },
- { "OLIVE_DRAB", Color(0.42, 0.56, 0.14) },
- { "ORANGE", Color(1.00, 0.65, 0.00) },
- { "ORANGE_RED", Color(1.00, 0.27, 0.00) },
- { "ORCHID", Color(0.85, 0.44, 0.84) },
- { "PALE_GOLDENROD", Color(0.93, 0.91, 0.67) },
- { "PALE_GREEN", Color(0.60, 0.98, 0.60) },
- { "PALE_TURQUOISE", Color(0.69, 0.93, 0.93) },
- { "PALE_VIOLET_RED", Color(0.86, 0.44, 0.58) },
- { "PAPAYA_WHIP", Color(1.00, 0.94, 0.84) },
- { "PEACH_PUFF", Color(1.00, 0.85, 0.73) },
- { "PERU", Color(0.80, 0.52, 0.25) },
- { "PINK", Color(1.00, 0.75, 0.80) },
- { "PLUM", Color(0.87, 0.63, 0.87) },
- { "POWDER_BLUE", Color(0.69, 0.88, 0.90) },
- { "PURPLE", Color(0.63, 0.13, 0.94) },
- { "REBECCA_PURPLE", Color(0.40, 0.20, 0.60) },
- { "RED", Color(1.00, 0.00, 0.00) },
- { "ROSY_BROWN", Color(0.74, 0.56, 0.56) },
- { "ROYAL_BLUE", Color(0.25, 0.41, 0.88) },
- { "SADDLE_BROWN", Color(0.55, 0.27, 0.07) },
- { "SALMON", Color(0.98, 0.50, 0.45) },
- { "SANDY_BROWN", Color(0.96, 0.64, 0.38) },
- { "SEA_GREEN", Color(0.18, 0.55, 0.34) },
- { "SEASHELL", Color(1.00, 0.96, 0.93) },
- { "SIENNA", Color(0.63, 0.32, 0.18) },
- { "SILVER", Color(0.75, 0.75, 0.75) },
- { "SKY_BLUE", Color(0.53, 0.81, 0.92) },
- { "SLATE_BLUE", Color(0.42, 0.35, 0.80) },
- { "SLATE_GRAY", Color(0.44, 0.50, 0.56) },
- { "SNOW", Color(1.00, 0.98, 0.98) },
- { "SPRING_GREEN", Color(0.00, 1.00, 0.50) },
- { "STEEL_BLUE", Color(0.27, 0.51, 0.71) },
- { "TAN", Color(0.82, 0.71, 0.55) },
- { "TEAL", Color(0.00, 0.50, 0.50) },
- { "THISTLE", Color(0.85, 0.75, 0.85) },
- { "TOMATO", Color(1.00, 0.39, 0.28) },
- { "TRANSPARENT", Color(1.00, 1.00, 1.00, 0.00) },
- { "TURQUOISE", Color(0.25, 0.88, 0.82) },
- { "VIOLET", Color(0.93, 0.51, 0.93) },
- { "WEB_GRAY", Color(0.50, 0.50, 0.50) },
- { "WEB_GREEN", Color(0.00, 0.50, 0.00) },
- { "WEB_MAROON", Color(0.50, 0.00, 0.00) },
- { "WEB_PURPLE", Color(0.50, 0.00, 0.50) },
- { "WHEAT", Color(0.96, 0.87, 0.70) },
- { "WHITE", Color(1.00, 1.00, 1.00) },
- { "WHITE_SMOKE", Color(0.96, 0.96, 0.96) },
- { "YELLOW", Color(1.00, 1.00, 0.00) },
- { "YELLOW_GREEN", Color(0.60, 0.80, 0.20) },
+ { "ALICE_BLUE", Color::hex(0xF0F8FFFF) },
+ { "ANTIQUE_WHITE", Color::hex(0xFAEBD7FF) },
+ { "AQUA", Color::hex(0x00FFFFFF) },
+ { "AQUAMARINE", Color::hex(0x7FFFD4FF) },
+ { "AZURE", Color::hex(0xF0FFFFFF) },
+ { "BEIGE", Color::hex(0xF5F5DCFF) },
+ { "BISQUE", Color::hex(0xFFE4C4FF) },
+ { "BLACK", Color::hex(0x000000FF) },
+ { "BLANCHED_ALMOND", Color::hex(0xFFEBCDFF) },
+ { "BLUE", Color::hex(0x0000FFFF) },
+ { "BLUE_VIOLET", Color::hex(0x8A2BE2FF) },
+ { "BROWN", Color::hex(0xA52A2AFF) },
+ { "BURLYWOOD", Color::hex(0xDEB887FF) },
+ { "CADET_BLUE", Color::hex(0x5F9EA0FF) },
+ { "CHARTREUSE", Color::hex(0x7FFF00FF) },
+ { "CHOCOLATE", Color::hex(0xD2691EFF) },
+ { "CORAL", Color::hex(0xFF7F50FF) },
+ { "CORNFLOWER_BLUE", Color::hex(0x6495EDFF) },
+ { "CORNSILK", Color::hex(0xFFF8DCFF) },
+ { "CRIMSON", Color::hex(0xDC143CFF) },
+ { "CYAN", Color::hex(0x00FFFFFF) },
+ { "DARK_BLUE", Color::hex(0x00008BFF) },
+ { "DARK_CYAN", Color::hex(0x008B8BFF) },
+ { "DARK_GOLDENROD", Color::hex(0xB8860BFF) },
+ { "DARK_GRAY", Color::hex(0xA9A9A9FF) },
+ { "DARK_GREEN", Color::hex(0x006400FF) },
+ { "DARK_KHAKI", Color::hex(0xBDB76BFF) },
+ { "DARK_MAGENTA", Color::hex(0x8B008BFF) },
+ { "DARK_OLIVE_GREEN", Color::hex(0x556B2FFF) },
+ { "DARK_ORANGE", Color::hex(0xFF8C00FF) },
+ { "DARK_ORCHID", Color::hex(0x9932CCFF) },
+ { "DARK_RED", Color::hex(0x8B0000FF) },
+ { "DARK_SALMON", Color::hex(0xE9967AFF) },
+ { "DARK_SEA_GREEN", Color::hex(0x8FBC8FFF) },
+ { "DARK_SLATE_BLUE", Color::hex(0x483D8BFF) },
+ { "DARK_SLATE_GRAY", Color::hex(0x2F4F4FFF) },
+ { "DARK_TURQUOISE", Color::hex(0x00CED1FF) },
+ { "DARK_VIOLET", Color::hex(0x9400D3FF) },
+ { "DEEP_PINK", Color::hex(0xFF1493FF) },
+ { "DEEP_SKY_BLUE", Color::hex(0x00BFFFFF) },
+ { "DIM_GRAY", Color::hex(0x696969FF) },
+ { "DODGER_BLUE", Color::hex(0x1E90FFFF) },
+ { "FIREBRICK", Color::hex(0xB22222FF) },
+ { "FLORAL_WHITE", Color::hex(0xFFFAF0FF) },
+ { "FOREST_GREEN", Color::hex(0x228B22FF) },
+ { "FUCHSIA", Color::hex(0xFF00FFFF) },
+ { "GAINSBORO", Color::hex(0xDCDCDCFF) },
+ { "GHOST_WHITE", Color::hex(0xF8F8FFFF) },
+ { "GOLD", Color::hex(0xFFD700FF) },
+ { "GOLDENROD", Color::hex(0xDAA520FF) },
+ { "GRAY", Color::hex(0xBEBEBEFF) },
+ { "GREEN", Color::hex(0x00FF00FF) },
+ { "GREEN_YELLOW", Color::hex(0xADFF2FFF) },
+ { "HONEYDEW", Color::hex(0xF0FFF0FF) },
+ { "HOT_PINK", Color::hex(0xFF69B4FF) },
+ { "INDIAN_RED", Color::hex(0xCD5C5CFF) },
+ { "INDIGO", Color::hex(0x4B0082FF) },
+ { "IVORY", Color::hex(0xFFFFF0FF) },
+ { "KHAKI", Color::hex(0xF0E68CFF) },
+ { "LAVENDER", Color::hex(0xE6E6FAFF) },
+ { "LAVENDER_BLUSH", Color::hex(0xFFF0F5FF) },
+ { "LAWN_GREEN", Color::hex(0x7CFC00FF) },
+ { "LEMON_CHIFFON", Color::hex(0xFFFACDFF) },
+ { "LIGHT_BLUE", Color::hex(0xADD8E6FF) },
+ { "LIGHT_CORAL", Color::hex(0xF08080FF) },
+ { "LIGHT_CYAN", Color::hex(0xE0FFFFFF) },
+ { "LIGHT_GOLDENROD", Color::hex(0xFAFAD2FF) },
+ { "LIGHT_GRAY", Color::hex(0xD3D3D3FF) },
+ { "LIGHT_GREEN", Color::hex(0x90EE90FF) },
+ { "LIGHT_PINK", Color::hex(0xFFB6C1FF) },
+ { "LIGHT_SALMON", Color::hex(0xFFA07AFF) },
+ { "LIGHT_SEA_GREEN", Color::hex(0x20B2AAFF) },
+ { "LIGHT_SKY_BLUE", Color::hex(0x87CEFAFF) },
+ { "LIGHT_SLATE_GRAY", Color::hex(0x778899FF) },
+ { "LIGHT_STEEL_BLUE", Color::hex(0xB0C4DEFF) },
+ { "LIGHT_YELLOW", Color::hex(0xFFFFE0FF) },
+ { "LIME", Color::hex(0x00FF00FF) },
+ { "LIME_GREEN", Color::hex(0x32CD32FF) },
+ { "LINEN", Color::hex(0xFAF0E6FF) },
+ { "MAGENTA", Color::hex(0xFF00FFFF) },
+ { "MAROON", Color::hex(0xB03060FF) },
+ { "MEDIUM_AQUAMARINE", Color::hex(0x66CDAAFF) },
+ { "MEDIUM_BLUE", Color::hex(0x0000CDFF) },
+ { "MEDIUM_ORCHID", Color::hex(0xBA55D3FF) },
+ { "MEDIUM_PURPLE", Color::hex(0x9370DBFF) },
+ { "MEDIUM_SEA_GREEN", Color::hex(0x3CB371FF) },
+ { "MEDIUM_SLATE_BLUE", Color::hex(0x7B68EEFF) },
+ { "MEDIUM_SPRING_GREEN", Color::hex(0x00FA9AFF) },
+ { "MEDIUM_TURQUOISE", Color::hex(0x48D1CCFF) },
+ { "MEDIUM_VIOLET_RED", Color::hex(0xC71585FF) },
+ { "MIDNIGHT_BLUE", Color::hex(0x191970FF) },
+ { "MINT_CREAM", Color::hex(0xF5FFFAFF) },
+ { "MISTY_ROSE", Color::hex(0xFFE4E1FF) },
+ { "MOCCASIN", Color::hex(0xFFE4B5FF) },
+ { "NAVAJO_WHITE", Color::hex(0xFFDEADFF) },
+ { "NAVY_BLUE", Color::hex(0x000080FF) },
+ { "OLD_LACE", Color::hex(0xFDF5E6FF) },
+ { "OLIVE", Color::hex(0x808000FF) },
+ { "OLIVE_DRAB", Color::hex(0x6B8E23FF) },
+ { "ORANGE", Color::hex(0xFFA500FF) },
+ { "ORANGE_RED", Color::hex(0xFF4500FF) },
+ { "ORCHID", Color::hex(0xDA70D6FF) },
+ { "PALE_GOLDENROD", Color::hex(0xEEE8AAFF) },
+ { "PALE_GREEN", Color::hex(0x98FB98FF) },
+ { "PALE_TURQUOISE", Color::hex(0xAFEEEEFF) },
+ { "PALE_VIOLET_RED", Color::hex(0xDB7093FF) },
+ { "PAPAYA_WHIP", Color::hex(0xFFEFD5FF) },
+ { "PEACH_PUFF", Color::hex(0xFFDAB9FF) },
+ { "PERU", Color::hex(0xCD853FFF) },
+ { "PINK", Color::hex(0xFFC0CBFF) },
+ { "PLUM", Color::hex(0xDDA0DDFF) },
+ { "POWDER_BLUE", Color::hex(0xB0E0E6FF) },
+ { "PURPLE", Color::hex(0xA020F0FF) },
+ { "REBECCA_PURPLE", Color::hex(0x663399FF) },
+ { "RED", Color::hex(0xFF0000FF) },
+ { "ROSY_BROWN", Color::hex(0xBC8F8FFF) },
+ { "ROYAL_BLUE", Color::hex(0x4169E1FF) },
+ { "SADDLE_BROWN", Color::hex(0x8B4513FF) },
+ { "SALMON", Color::hex(0xFA8072FF) },
+ { "SANDY_BROWN", Color::hex(0xF4A460FF) },
+ { "SEA_GREEN", Color::hex(0x2E8B57FF) },
+ { "SEASHELL", Color::hex(0xFFF5EEFF) },
+ { "SIENNA", Color::hex(0xA0522DFF) },
+ { "SILVER", Color::hex(0xC0C0C0FF) },
+ { "SKY_BLUE", Color::hex(0x87CEEBFF) },
+ { "SLATE_BLUE", Color::hex(0x6A5ACDFF) },
+ { "SLATE_GRAY", Color::hex(0x708090FF) },
+ { "SNOW", Color::hex(0xFFFAFAFF) },
+ { "SPRING_GREEN", Color::hex(0x00FF7FFF) },
+ { "STEEL_BLUE", Color::hex(0x4682B4FF) },
+ { "TAN", Color::hex(0xD2B48CFF) },
+ { "TEAL", Color::hex(0x008080FF) },
+ { "THISTLE", Color::hex(0xD8BFD8FF) },
+ { "TOMATO", Color::hex(0xFF6347FF) },
+ { "TRANSPARENT", Color::hex(0xFFFFFF00) },
+ { "TURQUOISE", Color::hex(0x40E0D0FF) },
+ { "VIOLET", Color::hex(0xEE82EEFF) },
+ { "WEB_GRAY", Color::hex(0x808080FF) },
+ { "WEB_GREEN", Color::hex(0x008000FF) },
+ { "WEB_MAROON", Color::hex(0x800000FF) },
+ { "WEB_PURPLE", Color::hex(0x800080FF) },
+ { "WHEAT", Color::hex(0xF5DEB3FF) },
+ { "WHITE", Color::hex(0xFFFFFFFF) },
+ { "WHITE_SMOKE", Color::hex(0xF5F5F5FF) },
+ { "YELLOW", Color::hex(0xFFFF00FF) },
+ { "YELLOW_GREEN", Color::hex(0x9ACD32FF) },
{ nullptr, Color() },
};
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index bd292f4c2a..996f4f4d67 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -509,7 +509,7 @@ public:
Face() {
}
- void init(Vertex *p_a, Vertex *p_b, Vertex *p_c) {
+ void init(Vertex *p_a, const Vertex *p_b, const Vertex *p_c) {
nearby_vertex = p_a;
origin = p_a->point;
dir0 = *p_b - *p_a;
@@ -614,7 +614,7 @@ private:
static Orientation get_orientation(const Edge *p_prev, const Edge *p_next, const Point32 &p_s, const Point32 &p_t);
Edge *find_max_angle(bool p_ccw, const Vertex *p_start, const Point32 &p_s, const Point64 &p_rxs, const Point64 &p_ssxrxs, Rational64 &p_min_cot);
- void find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, Vertex *p_stop0, Vertex *p_stop1);
+ void find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, const Vertex *p_stop0, const Vertex *p_stop1);
Edge *new_edge_pair(Vertex *p_from, Vertex *p_to);
@@ -666,7 +666,7 @@ public:
face_pool.reset(true);
}
- Vertex *vertex_list;
+ Vertex *vertex_list = nullptr;
void compute(const Vector3 *p_coords, int32_t p_count);
@@ -1189,7 +1189,7 @@ ConvexHullInternal::Edge *ConvexHullInternal::find_max_angle(bool p_ccw, const V
return min_edge;
}
-void ConvexHullInternal::find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, Vertex *p_stop0, Vertex *p_stop1) {
+void ConvexHullInternal::find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, const Vertex *p_stop0, const Vertex *p_stop1) {
Edge *start0 = p_e0;
Edge *start1 = p_e1;
Point32 et0 = start0 ? start0->target->point : p_c0->point;
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 0ddac9744e..9dd1257474 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -1440,7 +1440,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
}
Callable::CallError ce;
- base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
+ base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
diff --git a/core/math/expression.h b/core/math/expression.h
index 9b87bdd6ec..d43cc4091a 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -147,7 +147,7 @@ private:
bool is_op = false;
union {
Variant::Operator op;
- ENode *node;
+ ENode *node = nullptr;
};
};
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index 9c968df19b..fb92f6b0df 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -42,7 +42,7 @@ int Face3::split_by_plane(const Plane &p_plane, Face3 p_res[3], bool p_is_point_
int below_count = 0;
for (int i = 0; i < 3; i++) {
- if (p_plane.has_point(vertex[i], CMP_EPSILON)) { // point is in plane
+ if (p_plane.has_point(vertex[i], (real_t)CMP_EPSILON)) { // point is in plane
ERR_FAIL_COND_V(above_count >= 4, 0);
above[above_count++] = vertex[i];
@@ -117,7 +117,7 @@ bool Face3::intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vect
bool Face3::is_degenerate() const {
Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]);
- return (normal.length_squared() < CMP_EPSILON2);
+ return (normal.length_squared() < (real_t)CMP_EPSILON2);
}
Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) const {
@@ -208,7 +208,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const {
/** TEST ALL EDGES **/
- Vector3 edge_norms[3] = {
+ const Vector3 edge_norms[3] = {
vertex[0] - vertex[1],
vertex[1] - vertex[2],
vertex[2] - vertex[0],
diff --git a/core/math/face3.h b/core/math/face3.h
index c61d6ad66e..23260336fa 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -133,7 +133,7 @@ bool Face3::intersects_aabb2(const AABB &p_aabb) const {
#undef TEST_AXIS
- Vector3 edge_norms[3] = {
+ const Vector3 edge_norms[3] = {
vertex[0] - vertex[1],
vertex[1] - vertex[2],
vertex[2] - vertex[0],
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index b1af91c49c..31fade5a99 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -74,14 +74,14 @@ Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(Vector<Point2> p
struct _AtlasWorkRect {
Size2i s;
Point2i p;
- int idx;
+ int idx = 0;
_FORCE_INLINE_ bool operator<(const _AtlasWorkRect &p_r) const { return s.width > p_r.s.width; };
};
struct _AtlasWorkRectResult {
Vector<_AtlasWorkRect> result;
- int max_w;
- int max_h;
+ int max_w = 0;
+ int max_h = 0;
};
void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) {
@@ -218,10 +218,10 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath_a.size(); ++i) {
- path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR);
+ path_a << IntPoint(p_polypath_a[i].x * (real_t)SCALE_FACTOR, p_polypath_a[i].y * (real_t)SCALE_FACTOR);
}
for (int i = 0; i != p_polypath_b.size(); ++i) {
- path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR);
+ path_b << IntPoint(p_polypath_b[i].x * (real_t)SCALE_FACTOR, p_polypath_b[i].y * (real_t)SCALE_FACTOR);
}
Clipper clp;
clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0.
@@ -246,8 +246,8 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
}
polypaths.push_back(polypath);
}
@@ -290,17 +290,17 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
et = etOpenRound;
break;
}
- ClipperOffset co(2.0, 0.25f * SCALE_FACTOR); // Defaults from ClipperOffset.
+ ClipperOffset co(2.0, 0.25f * (real_t)SCALE_FACTOR); // Defaults from ClipperOffset.
Path path;
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath.size(); ++i) {
- path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR);
+ path << IntPoint(p_polypath[i].x * (real_t)SCALE_FACTOR, p_polypath[i].y * (real_t)SCALE_FACTOR);
}
co.AddPath(path, jt, et);
Paths paths;
- co.Execute(paths, p_delta * SCALE_FACTOR); // Inflate/deflate.
+ co.Execute(paths, p_delta * (real_t)SCALE_FACTOR); // Inflate/deflate.
// Have to scale points down now.
Vector<Vector<Point2>> polypaths;
@@ -312,8 +312,8 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
}
polypaths.push_back(polypath);
}
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 4fdb8ee36a..62786d69be 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -51,20 +51,20 @@ public:
real_t f = d2.dot(r);
real_t s, t;
// Check if either or both segments degenerate into points.
- if (a <= CMP_EPSILON && e <= CMP_EPSILON) {
+ if (a <= (real_t)CMP_EPSILON && e <= (real_t)CMP_EPSILON) {
// Both segments degenerate into points.
c1 = p1;
c2 = p2;
return Math::sqrt((c1 - c2).dot(c1 - c2));
}
- if (a <= CMP_EPSILON) {
+ if (a <= (real_t)CMP_EPSILON) {
// First segment degenerates into a point.
s = 0.0;
t = f / e; // s = 0 => t = (b*s + f) / e = f / e
t = CLAMP(t, 0.0f, 1.0f);
} else {
real_t c = d1.dot(r);
- if (e <= CMP_EPSILON) {
+ if (e <= (real_t)CMP_EPSILON) {
// Second segment degenerates into a point.
t = 0.0;
s = CLAMP(-c / a, 0.0f, 1.0f); // t = 0 => s = (b*t - c) / a = -c / a
@@ -185,7 +185,7 @@ public:
D = Vector2(D.x * Bn.x + D.y * Bn.y, D.y * Bn.x - D.x * Bn.y);
// Fail if C x B and D x B have the same sign (segments don't intersect).
- if ((C.y < -CMP_EPSILON && D.y < -CMP_EPSILON) || (C.y > CMP_EPSILON && D.y > CMP_EPSILON)) {
+ if ((C.y < (real_t)-CMP_EPSILON && D.y < (real_t)-CMP_EPSILON) || (C.y > (real_t)CMP_EPSILON && D.y > (real_t)CMP_EPSILON)) {
return false;
}
@@ -198,7 +198,7 @@ public:
real_t ABpos = D.x + (C.x - D.x) * D.y / (D.y - C.y);
// Fail if segment C-D crosses line A-B outside of segment A-B.
- if (ABpos < 0 || ABpos > 1.0f) {
+ if ((ABpos < 0) || (ABpos > 1)) {
return false;
}
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 7eeb37df46..f76de079e4 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -879,7 +879,7 @@ Vector<Vector3> Geometry3D::compute_convex_mesh_points(const Plane *p_planes, in
for (int n = 0; n < p_plane_count; n++) {
if (n != i && n != j && n != k) {
real_t dp = p_planes[n].normal.dot(convex_shape_point);
- if (dp - p_planes[n].d > CMP_EPSILON) {
+ if (dp - p_planes[n].d > (real_t)CMP_EPSILON) {
excluded = true;
break;
}
@@ -904,8 +904,8 @@ Vector<Vector3> Geometry3D::compute_convex_mesh_points(const Plane *p_planes, in
/* dt of 1d function using squared distance */
static void edt(float *f, int stride, int n) {
float *d = (float *)alloca(sizeof(float) * n + sizeof(int) * n + sizeof(float) * (n + 1));
- int *v = (int *)&(d[n]);
- float *z = (float *)&v[n];
+ int *v = reinterpret_cast<int *>(&(d[n]));
+ float *z = reinterpret_cast<float *>(&v[n]);
int k = 0;
v[0] = 0;
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 482c7ea604..59c56906f4 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -76,7 +76,7 @@ public:
real_t tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
// Compute the line parameters of the two closest points.
- if (D < CMP_EPSILON) { // The lines are almost parallel.
+ 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;
@@ -142,7 +142,7 @@ public:
Vector3 s = p_from - p_v0;
real_t u = f * s.dot(h);
- if (u < 0.0f || u > 1.0f) {
+ if ((u < 0.0f) || (u > 1.0f)) {
return false;
}
@@ -150,7 +150,7 @@ public:
real_t v = f * p_dir.dot(q);
- if (v < 0.0f || u + v > 1.0f) {
+ if ((v < 0.0f) || (u + v > 1.0f)) {
return false;
}
@@ -183,7 +183,7 @@ public:
Vector3 s = p_from - p_v0;
real_t u = f * s.dot(h);
- if (u < 0.0f || u > 1.0f) {
+ if ((u < 0.0f) || (u > 1.0f)) {
return false;
}
@@ -191,7 +191,7 @@ public:
real_t v = f * rel.dot(q);
- if (v < 0.0f || u + v > 1.0f) {
+ if ((v < 0.0f) || (u + v > 1.0f)) {
return false;
}
@@ -199,7 +199,7 @@ public:
// the intersection point is on the line.
real_t t = f * e2.dot(q);
- if (t > CMP_EPSILON && t <= 1.0f) { // Ray intersection.
+ if (t > (real_t)CMP_EPSILON && t <= 1.0f) { // Ray intersection.
if (r_res) {
*r_res = p_from + rel * t;
}
@@ -213,7 +213,7 @@ public:
Vector3 sphere_pos = p_sphere_pos - p_from;
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false; // Both points are the same.
}
Vector3 normal = rel / rel_l;
@@ -229,7 +229,7 @@ public:
real_t inters_d2 = p_sphere_radius * p_sphere_radius - ray_distance * ray_distance;
real_t inters_d = sphere_d;
- if (inters_d2 >= CMP_EPSILON) {
+ if (inters_d2 >= (real_t)CMP_EPSILON) {
inters_d -= Math::sqrt(inters_d2);
}
@@ -253,7 +253,7 @@ public:
static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr, int p_cylinder_axis = 2) {
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false; // Both points are the same.
}
@@ -269,7 +269,7 @@ public:
Vector3 axis_dir;
- if (crs_l < CMP_EPSILON) {
+ if (crs_l < (real_t)CMP_EPSILON) {
Vector3 side_axis;
side_axis[(p_cylinder_axis + 1) % 3] = 1.0f; // Any side axis OK.
axis_dir = side_axis;
@@ -285,7 +285,7 @@ public:
// Convert to 2D.
real_t w2 = p_radius * p_radius - dist * dist;
- if (w2 < CMP_EPSILON) {
+ if (w2 < (real_t)CMP_EPSILON) {
return false; // Avoid numerical error.
}
Size2 size(Math::sqrt(w2), p_height * 0.5f);
@@ -366,7 +366,7 @@ public:
Vector3 rel = p_to - p_from;
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false;
}
@@ -379,7 +379,7 @@ public:
real_t den = p.normal.dot(dir);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::abs(den) <= (real_t)CMP_EPSILON) {
continue; // Ignore parallel plane.
}
@@ -564,11 +564,11 @@ public:
for (int a = 0; a < polygon.size(); a++) {
real_t dist = p_plane.distance_to(polygon[a]);
- if (dist < -CMP_POINT_IN_PLANE_EPSILON) {
+ if (dist < (real_t)-CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_INSIDE;
inside_count++;
} else {
- if (dist > CMP_POINT_IN_PLANE_EPSILON) {
+ if (dist > (real_t)CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_OUTSIDE;
outside_count++;
} else {
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index 1717ecd74b..4be4809e3f 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -115,12 +115,12 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
case Variant::TRANSFORM2D: {
SETUP_TYPE(Transform2D)
- /**/ TRY_TRANSFER_FIELD("xx", elements[0][0])
- else TRY_TRANSFER_FIELD("xy", elements[0][1])
- else TRY_TRANSFER_FIELD("yx", elements[1][0])
- else TRY_TRANSFER_FIELD("yy", elements[1][1])
- else TRY_TRANSFER_FIELD("ox", elements[2][0])
- else TRY_TRANSFER_FIELD("oy", elements[2][1])
+ /**/ TRY_TRANSFER_FIELD("xx", columns[0][0])
+ else TRY_TRANSFER_FIELD("xy", columns[0][1])
+ else TRY_TRANSFER_FIELD("yx", columns[1][0])
+ else TRY_TRANSFER_FIELD("yy", columns[1][1])
+ else TRY_TRANSFER_FIELD("ox", columns[2][0])
+ else TRY_TRANSFER_FIELD("oy", columns[2][1])
return target;
}
@@ -128,15 +128,15 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
case Variant::BASIS: {
SETUP_TYPE(Basis)
- /**/ TRY_TRANSFER_FIELD("xx", elements[0][0])
- else TRY_TRANSFER_FIELD("xy", elements[0][1])
- else TRY_TRANSFER_FIELD("xz", elements[0][2])
- else TRY_TRANSFER_FIELD("yx", elements[1][0])
- else TRY_TRANSFER_FIELD("yy", elements[1][1])
- else TRY_TRANSFER_FIELD("yz", elements[1][2])
- else TRY_TRANSFER_FIELD("zx", elements[2][0])
- else TRY_TRANSFER_FIELD("zy", elements[2][1])
- else TRY_TRANSFER_FIELD("zz", elements[2][2])
+ /**/ TRY_TRANSFER_FIELD("xx", rows[0][0])
+ else TRY_TRANSFER_FIELD("xy", rows[0][1])
+ else TRY_TRANSFER_FIELD("xz", rows[0][2])
+ else TRY_TRANSFER_FIELD("yx", rows[1][0])
+ else TRY_TRANSFER_FIELD("yy", rows[1][1])
+ else TRY_TRANSFER_FIELD("yz", rows[1][2])
+ else TRY_TRANSFER_FIELD("zx", rows[2][0])
+ else TRY_TRANSFER_FIELD("zy", rows[2][1])
+ else TRY_TRANSFER_FIELD("zz", rows[2][2])
return target;
}
@@ -144,15 +144,15 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
case Variant::TRANSFORM3D: {
SETUP_TYPE(Transform3D)
- /**/ TRY_TRANSFER_FIELD("xx", basis.elements[0][0])
- else TRY_TRANSFER_FIELD("xy", basis.elements[0][1])
- else TRY_TRANSFER_FIELD("xz", basis.elements[0][2])
- else TRY_TRANSFER_FIELD("yx", basis.elements[1][0])
- else TRY_TRANSFER_FIELD("yy", basis.elements[1][1])
- else TRY_TRANSFER_FIELD("yz", basis.elements[1][2])
- else TRY_TRANSFER_FIELD("zx", basis.elements[2][0])
- else TRY_TRANSFER_FIELD("zy", basis.elements[2][1])
- else TRY_TRANSFER_FIELD("zz", basis.elements[2][2])
+ /**/ TRY_TRANSFER_FIELD("xx", basis.rows[0][0])
+ else TRY_TRANSFER_FIELD("xy", basis.rows[0][1])
+ else TRY_TRANSFER_FIELD("xz", basis.rows[0][2])
+ else TRY_TRANSFER_FIELD("yx", basis.rows[1][0])
+ else TRY_TRANSFER_FIELD("yy", basis.rows[1][1])
+ else TRY_TRANSFER_FIELD("yz", basis.rows[1][2])
+ else TRY_TRANSFER_FIELD("zx", basis.rows[2][0])
+ else TRY_TRANSFER_FIELD("zy", basis.rows[2][1])
+ else TRY_TRANSFER_FIELD("zz", basis.rows[2][2])
else TRY_TRANSFER_FIELD("xo", origin.x)
else TRY_TRANSFER_FIELD("yo", origin.y)
else TRY_TRANSFER_FIELD("zo", origin.z)
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 47e5ab2709..068bc0397e 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -64,7 +64,7 @@ public:
static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
- static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc(Math_PI * p_x); }
+ static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc((float)Math_PI * p_x); }
static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); }
static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
@@ -103,6 +103,9 @@ public:
static _ALWAYS_INLINE_ double log(double p_x) { return ::log(p_x); }
static _ALWAYS_INLINE_ float log(float p_x) { return ::logf(p_x); }
+ static _ALWAYS_INLINE_ double log1p(double p_x) { return ::log1p(p_x); }
+ static _ALWAYS_INLINE_ float log1p(float p_x) { return ::log1pf(p_x); }
+
static _ALWAYS_INLINE_ double log2(double p_x) { return ::log2(p_x); }
static _ALWAYS_INLINE_ float log2(float p_x) { return ::log2f(p_x); }
@@ -187,7 +190,7 @@ public:
static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) {
double value = Math::fmod(p_x, p_y);
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0;
@@ -195,7 +198,7 @@ public:
}
static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) {
float value = Math::fmod(p_x, p_y);
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0f;
@@ -220,17 +223,17 @@ public:
static _ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) {
int64_t value = p_x % p_y;
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
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 * (Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ float deg2rad(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 * (180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ float rad2deg(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; }
@@ -285,10 +288,10 @@ public:
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) * 8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ float linear2db(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 * 0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ float db2linear(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); }
@@ -322,7 +325,7 @@ public:
// double only, as these functions are mainly used by the editor and not performance-critical,
static double ease(double p_x, double p_c);
static int step_decimals(double p_step);
- static int range_step_decimals(double p_step);
+ static int range_step_decimals(double p_step); // For editor use only.
static double snapped(double p_value, double p_step);
static uint32_t larger_prime(uint32_t p_val);
@@ -345,9 +348,9 @@ public:
return true;
}
// Then check for approximate equality.
- float tolerance = CMP_EPSILON * abs(a);
- if (tolerance < CMP_EPSILON) {
- tolerance = CMP_EPSILON;
+ float tolerance = (float)CMP_EPSILON * abs(a);
+ if (tolerance < (float)CMP_EPSILON) {
+ tolerance = (float)CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
@@ -362,7 +365,7 @@ public:
}
static _ALWAYS_INLINE_ bool is_zero_approx(float s) {
- return abs(s) < CMP_EPSILON;
+ return abs(s) < (float)CMP_EPSILON;
}
static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b) {
@@ -473,16 +476,16 @@ public:
uint32_t x = ci.ui;
uint32_t sign = (unsigned short)(x >> 31);
uint32_t mantissa;
- uint32_t exp;
+ uint32_t exponent;
uint16_t hf;
// get mantissa
mantissa = x & ((1 << 23) - 1);
// get exponent bits
- exp = x & (0xFF << 23);
- if (exp >= 0x47800000) {
+ exponent = x & (0xFF << 23);
+ if (exponent >= 0x47800000) {
// check if the original single precision float number is a NaN
- if (mantissa && (exp == (0xFF << 23))) {
+ if (mantissa && (exponent == (0xFF << 23))) {
// we have a single precision NaN
mantissa = (1 << 23) - 1;
} else {
@@ -493,17 +496,18 @@ public:
(uint16_t)(mantissa >> 13);
}
// check if exponent is <= -15
- else if (exp <= 0x38000000) {
- /*// store a denorm half-float value or zero
- exp = (0x38000000 - exp) >> 23;
- mantissa >>= (14 + exp);
-
- hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
- */
+ else if (exponent <= 0x38000000) {
+ /*
+ // store a denorm half-float value or zero
+ exponent = (0x38000000 - exponent) >> 23;
+ mantissa >>= (14 + exponent);
+
+ hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
+ */
hf = 0; //denormals do not work for 3D, convert to zero
} else {
hf = (((uint16_t)sign) << 15) |
- (uint16_t)((exp - 0x38000000) >> 13) |
+ (uint16_t)((exponent - 0x38000000) >> 13) |
(uint16_t)(mantissa >> 13);
}
diff --git a/core/math/octree.h b/core/math/octree.h
index e73f8213b3..65ab9e2292 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -134,7 +134,7 @@ private:
List<PairData *, AL> pair_list;
struct OctantOwner {
- Octant *octant;
+ Octant *octant = nullptr;
typename List<Element *, AL>::Element *E;
}; // an element can be in max 8 octants
@@ -147,7 +147,7 @@ private:
int refcount;
bool intersect;
Element *A, *B;
- void *ud;
+ void *ud = nullptr;
typename List<PairData *, AL>::Element *eA, *eB;
};
@@ -156,18 +156,18 @@ private:
ElementMap element_map;
PairMap pair_map;
- PairCallback pair_callback;
- UnpairCallback unpair_callback;
- void *pair_callback_userdata;
- void *unpair_callback_userdata;
+ PairCallback pair_callback = nullptr;
+ UnpairCallback unpair_callback = nullptr;
+ void *pair_callback_userdata = nullptr;
+ void *unpair_callback_userdata = nullptr;
- OctreeElementID last_element_id;
- uint64_t pass;
+ OctreeElementID last_element_id = 1;
+ uint64_t pass = 1;
- real_t unit_size;
- Octant *root;
- int octant_count;
- int pair_count;
+ real_t unit_size = 1.0;
+ Octant *root = nullptr;
+ int octant_count = 0;
+ int pair_count = 0;
_FORCE_INLINE_ void _pair_check(PairData *p_pair) {
bool intersect = p_pair->A->aabb.intersects_inclusive(p_pair->B->aabb);
@@ -294,7 +294,7 @@ private:
const Vector3 *points;
int point_count;
T **result_array;
- int *result_idx;
+ int *result_idx = nullptr;
int result_max;
uint32_t mask;
};
@@ -1265,18 +1265,7 @@ void Octree<T, use_pairs, AL>::set_unpair_callback(UnpairCallback p_callback, vo
template <class T, bool use_pairs, class AL>
Octree<T, use_pairs, AL>::Octree(real_t p_unit_size) {
- last_element_id = 1;
- pass = 1;
unit_size = p_unit_size;
- root = nullptr;
-
- octant_count = 0;
- pair_count = 0;
-
- pair_callback = nullptr;
- unpair_callback = nullptr;
- pair_callback_userdata = nullptr;
- unpair_callback_userdata = nullptr;
}
#endif // OCTREE_H
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 0ce8aed51c..6881ad4014 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -106,7 +106,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
real_t dist = (normal.dot(p_from) - d) / den;
//printf("dist is %i\n",dist);
- if (dist > CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
+ if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
return false;
}
@@ -129,7 +129,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
real_t dist = (normal.dot(p_begin) - d) / den;
//printf("dist is %i\n",dist);
- if (dist < -CMP_EPSILON || dist > (1.0f + CMP_EPSILON)) {
+ if (dist < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) {
return false;
}
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index ade252d628..11bfcc1a6f 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -102,6 +102,22 @@ Quaternion Quaternion::inverse() const {
return Quaternion(-x, -y, -z, w);
}
+Quaternion Quaternion::log() const {
+ Quaternion src = *this;
+ Vector3 src_v = src.get_axis() * src.get_angle();
+ return Quaternion(src_v.x, src_v.y, src_v.z, 0);
+}
+
+Quaternion Quaternion::exp() const {
+ Quaternion src = *this;
+ Vector3 src_v = Vector3(src.x, src.y, src.z);
+ float theta = src_v.length();
+ if (theta < CMP_EPSILON) {
+ return Quaternion(0, 0, 0, 1);
+ }
+ return Quaternion(src_v.normalized(), theta);
+}
+
Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
@@ -129,7 +145,7 @@ Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) con
// calculate coefficients
- if ((1.0f - cosom) > CMP_EPSILON) {
+ if ((1.0f - cosom) > (real_t)CMP_EPSILON) {
// standard case (slerp)
omega = Math::acos(cosom);
sinom = Math::sin(omega);
@@ -190,6 +206,9 @@ Quaternion::operator String() const {
}
Vector3 Quaternion::get_axis() const {
+ if (Math::abs(w) > 1 - CMP_EPSILON) {
+ return Vector3(x, y, z);
+ }
real_t r = ((real_t)1) / Math::sqrt(1 - w * w);
return Vector3(x * r, y * r, z * r);
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index f8a2c6456e..9801746659 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -60,6 +60,8 @@ struct _NO_DISCARD_ Quaternion {
Quaternion normalized() const;
bool is_normalized() const;
Quaternion inverse() const;
+ Quaternion log() const;
+ Quaternion exp() const;
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
@@ -145,7 +147,7 @@ struct _NO_DISCARD_ Quaternion {
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
- if (d < -1.0f + CMP_EPSILON) {
+ if (d < -1.0f + (real_t)CMP_EPSILON) {
x = 0;
y = 1;
z = 0;
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index 974dbbfc2e..a088b30d17 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -61,8 +61,8 @@ static int __bsr_clz32(uint32_t x) {
class RandomPCG {
pcg32_random_t pcg;
- uint64_t current_seed; // The seed the current generator state started from.
- uint64_t current_inc;
+ uint64_t current_seed = 0; // The seed the current generator state started from.
+ uint64_t current_inc = 0;
public:
static const uint64_t DEFAULT_SEED = 12047754176567800795U;
@@ -129,7 +129,7 @@ public:
return p_mean + p_deviation * (cos(Math_TAU * randd()) * sqrt(-2.0 * log(randd()))); // Box-Muller transform
}
_FORCE_INLINE_ float randfn(float p_mean, float p_deviation) {
- return p_mean + p_deviation * (cos(Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
+ return p_mean + p_deviation * (cos((float)Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
}
double random(double p_from, double p_to);
diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp
index d6e20bdc3c..9e78ead816 100644
--- a/core/math/rect2.cpp
+++ b/core/math/rect2.cpp
@@ -201,33 +201,33 @@ next4:
Vector2(position.x + size.x, position.y + size.y),
};
- real_t maxa = p_xform.elements[0].dot(xf_points2[0]);
+ real_t maxa = p_xform.columns[0].dot(xf_points2[0]);
real_t mina = maxa;
- real_t dp = p_xform.elements[0].dot(xf_points2[1]);
+ real_t dp = p_xform.columns[0].dot(xf_points2[1]);
maxa = MAX(dp, maxa);
mina = MIN(dp, mina);
- dp = p_xform.elements[0].dot(xf_points2[2]);
+ dp = p_xform.columns[0].dot(xf_points2[2]);
maxa = MAX(dp, maxa);
mina = MIN(dp, mina);
- dp = p_xform.elements[0].dot(xf_points2[3]);
+ dp = p_xform.columns[0].dot(xf_points2[3]);
maxa = MAX(dp, maxa);
mina = MIN(dp, mina);
- real_t maxb = p_xform.elements[0].dot(xf_points[0]);
+ real_t maxb = p_xform.columns[0].dot(xf_points[0]);
real_t minb = maxb;
- dp = p_xform.elements[0].dot(xf_points[1]);
+ dp = p_xform.columns[0].dot(xf_points[1]);
maxb = MAX(dp, maxb);
minb = MIN(dp, minb);
- dp = p_xform.elements[0].dot(xf_points[2]);
+ dp = p_xform.columns[0].dot(xf_points[2]);
maxb = MAX(dp, maxb);
minb = MIN(dp, minb);
- dp = p_xform.elements[0].dot(xf_points[3]);
+ dp = p_xform.columns[0].dot(xf_points[3]);
maxb = MAX(dp, maxb);
minb = MIN(dp, minb);
@@ -238,33 +238,33 @@ next4:
return false;
}
- maxa = p_xform.elements[1].dot(xf_points2[0]);
+ maxa = p_xform.columns[1].dot(xf_points2[0]);
mina = maxa;
- dp = p_xform.elements[1].dot(xf_points2[1]);
+ dp = p_xform.columns[1].dot(xf_points2[1]);
maxa = MAX(dp, maxa);
mina = MIN(dp, mina);
- dp = p_xform.elements[1].dot(xf_points2[2]);
+ dp = p_xform.columns[1].dot(xf_points2[2]);
maxa = MAX(dp, maxa);
mina = MIN(dp, mina);
- dp = p_xform.elements[1].dot(xf_points2[3]);
+ dp = p_xform.columns[1].dot(xf_points2[3]);
maxa = MAX(dp, maxa);
mina = MIN(dp, mina);
- maxb = p_xform.elements[1].dot(xf_points[0]);
+ maxb = p_xform.columns[1].dot(xf_points[0]);
minb = maxb;
- dp = p_xform.elements[1].dot(xf_points[1]);
+ dp = p_xform.columns[1].dot(xf_points[1]);
maxb = MAX(dp, maxb);
minb = MIN(dp, minb);
- dp = p_xform.elements[1].dot(xf_points[2]);
+ dp = p_xform.columns[1].dot(xf_points[2]);
maxb = MAX(dp, maxb);
minb = MIN(dp, minb);
- dp = p_xform.elements[1].dot(xf_points[3]);
+ dp = p_xform.columns[1].dot(xf_points[3]);
maxb = MAX(dp, maxb);
minb = MIN(dp, minb);
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 55c1f06ff5..cbd2fd3fa1 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -35,8 +35,8 @@
void Transform2D::invert() {
// FIXME: this function assumes the basis is a rotation matrix, with no scaling.
// Transform2D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that.
- SWAP(elements[0][1], elements[1][0]);
- elements[2] = basis_xform(-elements[2]);
+ SWAP(columns[0][1], columns[1][0]);
+ columns[2] = basis_xform(-columns[2]);
}
Transform2D Transform2D::inverse() const {
@@ -52,11 +52,11 @@ void Transform2D::affine_invert() {
#endif
real_t idet = 1.0f / det;
- SWAP(elements[0][0], elements[1][1]);
- elements[0] *= Vector2(idet, -idet);
- elements[1] *= Vector2(-idet, idet);
+ SWAP(columns[0][0], columns[1][1]);
+ columns[0] *= Vector2(idet, -idet);
+ columns[1] *= Vector2(-idet, idet);
- elements[2] = basis_xform(-elements[2]);
+ columns[2] = basis_xform(-columns[2]);
}
Transform2D Transform2D::affine_inverse() const {
@@ -65,75 +65,75 @@ Transform2D Transform2D::affine_inverse() const {
return inv;
}
-void Transform2D::rotate(const real_t p_phi) {
- *this = Transform2D(p_phi, Vector2()) * (*this);
+void Transform2D::rotate(const real_t p_angle) {
+ *this = Transform2D(p_angle, Vector2()) * (*this);
}
real_t Transform2D::get_skew() const {
real_t det = basis_determinant();
- return Math::acos(elements[0].normalized().dot(SIGN(det) * elements[1].normalized())) - Math_PI * 0.5f;
+ return Math::acos(columns[0].normalized().dot(SIGN(det) * columns[1].normalized())) - (real_t)Math_PI * 0.5f;
}
void Transform2D::set_skew(const real_t p_angle) {
real_t det = basis_determinant();
- elements[1] = SIGN(det) * elements[0].rotated((Math_PI * 0.5f + p_angle)).normalized() * elements[1].length();
+ columns[1] = SIGN(det) * columns[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * columns[1].length();
}
real_t Transform2D::get_rotation() const {
- return Math::atan2(elements[0].y, elements[0].x);
+ return Math::atan2(columns[0].y, columns[0].x);
}
void Transform2D::set_rotation(const real_t p_rot) {
Size2 scale = get_scale();
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
- elements[0][0] = cr;
- elements[0][1] = sr;
- elements[1][0] = -sr;
- elements[1][1] = cr;
+ columns[0][0] = cr;
+ columns[0][1] = sr;
+ columns[1][0] = -sr;
+ columns[1][1] = cr;
set_scale(scale);
}
Transform2D::Transform2D(const real_t p_rot, const Vector2 &p_pos) {
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
- elements[0][0] = cr;
- elements[0][1] = sr;
- elements[1][0] = -sr;
- elements[1][1] = cr;
- elements[2] = p_pos;
+ columns[0][0] = cr;
+ columns[0][1] = sr;
+ columns[1][0] = -sr;
+ columns[1][1] = cr;
+ columns[2] = p_pos;
}
Transform2D::Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos) {
- elements[0][0] = Math::cos(p_rot) * p_scale.x;
- elements[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
- elements[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
- elements[0][1] = Math::sin(p_rot) * p_scale.x;
- elements[2] = p_pos;
+ columns[0][0] = Math::cos(p_rot) * p_scale.x;
+ columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
+ columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
+ columns[0][1] = Math::sin(p_rot) * p_scale.x;
+ columns[2] = p_pos;
}
Size2 Transform2D::get_scale() const {
real_t det_sign = SIGN(basis_determinant());
- return Size2(elements[0].length(), det_sign * elements[1].length());
+ return Size2(columns[0].length(), det_sign * columns[1].length());
}
void Transform2D::set_scale(const Size2 &p_scale) {
- elements[0].normalize();
- elements[1].normalize();
- elements[0] *= p_scale.x;
- elements[1] *= p_scale.y;
+ columns[0].normalize();
+ columns[1].normalize();
+ columns[0] *= p_scale.x;
+ columns[1] *= p_scale.y;
}
void Transform2D::scale(const Size2 &p_scale) {
scale_basis(p_scale);
- elements[2] *= p_scale;
+ columns[2] *= p_scale;
}
void Transform2D::scale_basis(const Size2 &p_scale) {
- elements[0][0] *= p_scale.x;
- elements[0][1] *= p_scale.y;
- elements[1][0] *= p_scale.x;
- elements[1][1] *= p_scale.y;
+ columns[0][0] *= p_scale.x;
+ columns[0][1] *= p_scale.y;
+ columns[1][0] *= p_scale.x;
+ columns[1][1] *= p_scale.y;
}
void Transform2D::translate(const real_t p_tx, const real_t p_ty) {
@@ -141,21 +141,21 @@ void Transform2D::translate(const real_t p_tx, const real_t p_ty) {
}
void Transform2D::translate(const Vector2 &p_translation) {
- elements[2] += basis_xform(p_translation);
+ columns[2] += basis_xform(p_translation);
}
void Transform2D::orthonormalize() {
// Gram-Schmidt Process
- Vector2 x = elements[0];
- Vector2 y = elements[1];
+ Vector2 x = columns[0];
+ Vector2 y = columns[1];
x.normalize();
y = (y - x * (x.dot(y)));
y.normalize();
- elements[0] = x;
- elements[1] = y;
+ columns[0] = x;
+ columns[1] = y;
}
Transform2D Transform2D::orthonormalized() const {
@@ -165,7 +165,7 @@ Transform2D Transform2D::orthonormalized() const {
}
bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
- return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]);
+ return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
}
Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
@@ -177,7 +177,7 @@ Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
bool Transform2D::operator==(const Transform2D &p_transform) const {
for (int i = 0; i < 3; i++) {
- if (elements[i] != p_transform.elements[i]) {
+ if (columns[i] != p_transform.columns[i]) {
return false;
}
}
@@ -187,7 +187,7 @@ bool Transform2D::operator==(const Transform2D &p_transform) const {
bool Transform2D::operator!=(const Transform2D &p_transform) const {
for (int i = 0; i < 3; i++) {
- if (elements[i] != p_transform.elements[i]) {
+ if (columns[i] != p_transform.columns[i]) {
return true;
}
}
@@ -196,19 +196,19 @@ bool Transform2D::operator!=(const Transform2D &p_transform) const {
}
void Transform2D::operator*=(const Transform2D &p_transform) {
- elements[2] = xform(p_transform.elements[2]);
+ columns[2] = xform(p_transform.columns[2]);
real_t x0, x1, y0, y1;
- x0 = tdotx(p_transform.elements[0]);
- x1 = tdoty(p_transform.elements[0]);
- y0 = tdotx(p_transform.elements[1]);
- y1 = tdoty(p_transform.elements[1]);
+ x0 = tdotx(p_transform.columns[0]);
+ x1 = tdoty(p_transform.columns[0]);
+ y0 = tdotx(p_transform.columns[1]);
+ y1 = tdoty(p_transform.columns[1]);
- elements[0][0] = x0;
- elements[0][1] = x1;
- elements[1][0] = y0;
- elements[1][1] = y1;
+ columns[0][0] = x0;
+ columns[0][1] = x1;
+ columns[1][0] = y0;
+ columns[1][1] = y1;
}
Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
@@ -231,7 +231,7 @@ Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
Transform2D Transform2D::untranslated() const {
Transform2D copy = *this;
- copy.elements[2] = Vector2();
+ copy.columns[2] = Vector2();
return copy;
}
@@ -241,14 +241,14 @@ Transform2D Transform2D::translated(const Vector2 &p_offset) const {
return copy;
}
-Transform2D Transform2D::rotated(const real_t p_phi) const {
+Transform2D Transform2D::rotated(const real_t p_angle) const {
Transform2D copy = *this;
- copy.rotate(p_phi);
+ copy.rotate(p_angle);
return copy;
}
real_t Transform2D::basis_determinant() const {
- return elements[0].x * elements[1].y - elements[0].y * elements[1].x;
+ return columns[0].x * columns[1].y - columns[0].y * columns[1].x;
}
Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const real_t p_c) const {
@@ -287,9 +287,9 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const
}
void Transform2D::operator*=(const real_t p_val) {
- elements[0] *= p_val;
- elements[1] *= p_val;
- elements[2] *= p_val;
+ columns[0] *= p_val;
+ columns[1] *= p_val;
+ columns[2] *= p_val;
}
Transform2D Transform2D::operator*(const real_t p_val) const {
@@ -299,7 +299,7 @@ Transform2D Transform2D::operator*(const real_t p_val) const {
}
Transform2D::operator String() const {
- return "[X: " + elements[0].operator String() +
- ", Y: " + elements[1].operator String() +
- ", O: " + elements[2].operator String() + "]";
+ return "[X: " + columns[0].operator String() +
+ ", Y: " + columns[1].operator String() +
+ ", O: " + columns[2].operator String() + "]";
}
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index f4546c13c8..72d34a5d4c 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -39,33 +39,24 @@
class String;
struct _NO_DISCARD_ Transform2D {
- // Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper":
- // M = (elements[0][0] elements[1][0])
- // (elements[0][1] elements[1][1])
- // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as elements[i].
- // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to elements[1][0] here.
+ // Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper":
+ // M = (columns[0][0] columns[1][0])
+ // (columns[0][1] columns[1][1])
+ // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as columns[i].
+ // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to columns[1][0] here.
// This requires additional care when working with explicit indices.
// See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading.
// Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down,
// and angle is measure from +X to +Y in a clockwise-fashion.
- Vector2 elements[3];
+ Vector2 columns[3];
- _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return elements[0][0] * v.x + elements[1][0] * v.y; }
- _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return elements[0][1] * v.x + elements[1][1] * v.y; }
+ _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; }
+ _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; }
- const Vector2 &operator[](int p_idx) const { return elements[p_idx]; }
- Vector2 &operator[](int p_idx) { return elements[p_idx]; }
-
- _FORCE_INLINE_ Vector2 get_axis(int p_axis) const {
- ERR_FAIL_INDEX_V(p_axis, 3, Vector2());
- return elements[p_axis];
- }
- _FORCE_INLINE_ void set_axis(int p_axis, const Vector2 &p_vec) {
- ERR_FAIL_INDEX(p_axis, 3);
- elements[p_axis] = p_vec;
- }
+ const Vector2 &operator[](int p_idx) const { return columns[p_idx]; }
+ Vector2 &operator[](int p_idx) { return columns[p_idx]; }
void invert();
Transform2D inverse() const;
@@ -79,7 +70,7 @@ struct _NO_DISCARD_ Transform2D {
void set_skew(const real_t p_angle);
_FORCE_INLINE_ void set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale);
_FORCE_INLINE_ void set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew);
- void rotate(const real_t p_phi);
+ void rotate(const real_t p_angle);
void scale(const Size2 &p_scale);
void scale_basis(const Size2 &p_scale);
@@ -91,13 +82,13 @@ struct _NO_DISCARD_ Transform2D {
Size2 get_scale() const;
void set_scale(const Size2 &p_scale);
- _FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; }
- _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; }
+ _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 translated(const Vector2 &p_offset) const;
- Transform2D rotated(const real_t p_phi) const;
+ Transform2D rotated(const real_t p_angle) const;
Transform2D untranslated() const;
@@ -129,18 +120,18 @@ struct _NO_DISCARD_ Transform2D {
operator String() const;
Transform2D(const real_t xx, const real_t xy, const real_t yx, const real_t yy, const real_t ox, const real_t oy) {
- elements[0][0] = xx;
- elements[0][1] = xy;
- elements[1][0] = yx;
- elements[1][1] = yy;
- elements[2][0] = ox;
- elements[2][1] = oy;
+ columns[0][0] = xx;
+ columns[0][1] = xy;
+ columns[1][0] = yx;
+ columns[1][1] = yy;
+ columns[2][0] = ox;
+ columns[2][1] = oy;
}
Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) {
- elements[0] = p_x;
- elements[1] = p_y;
- elements[2] = p_origin;
+ columns[0] = p_x;
+ columns[1] = p_y;
+ columns[2] = p_origin;
}
Transform2D(const real_t p_rot, const Vector2 &p_pos);
@@ -148,8 +139,8 @@ struct _NO_DISCARD_ Transform2D {
Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos);
Transform2D() {
- elements[0][0] = 1.0;
- elements[1][1] = 1.0;
+ columns[0][0] = 1.0;
+ columns[1][1] = 1.0;
}
};
@@ -161,28 +152,28 @@ Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const {
Vector2 Transform2D::basis_xform_inv(const Vector2 &p_vec) const {
return Vector2(
- elements[0].dot(p_vec),
- elements[1].dot(p_vec));
+ columns[0].dot(p_vec),
+ columns[1].dot(p_vec));
}
Vector2 Transform2D::xform(const Vector2 &p_vec) const {
return Vector2(
tdotx(p_vec),
tdoty(p_vec)) +
- elements[2];
+ columns[2];
}
Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const {
- Vector2 v = p_vec - elements[2];
+ Vector2 v = p_vec - columns[2];
return Vector2(
- elements[0].dot(v),
- elements[1].dot(v));
+ columns[0].dot(v),
+ columns[1].dot(v));
}
Rect2 Transform2D::xform(const Rect2 &p_rect) const {
- Vector2 x = elements[0] * p_rect.size.x;
- Vector2 y = elements[1] * p_rect.size.y;
+ Vector2 x = columns[0] * p_rect.size.x;
+ Vector2 y = columns[1] * p_rect.size.y;
Vector2 pos = xform(p_rect.position);
Rect2 new_rect;
@@ -194,17 +185,17 @@ Rect2 Transform2D::xform(const Rect2 &p_rect) const {
}
void Transform2D::set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale) {
- elements[0][0] = Math::cos(p_rot) * p_scale.x;
- elements[1][1] = Math::cos(p_rot) * p_scale.y;
- elements[1][0] = -Math::sin(p_rot) * p_scale.y;
- elements[0][1] = Math::sin(p_rot) * p_scale.x;
+ columns[0][0] = Math::cos(p_rot) * p_scale.x;
+ columns[1][1] = Math::cos(p_rot) * p_scale.y;
+ columns[1][0] = -Math::sin(p_rot) * p_scale.y;
+ columns[0][1] = Math::sin(p_rot) * p_scale.x;
}
void Transform2D::set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew) {
- elements[0][0] = Math::cos(p_rot) * p_scale.x;
- elements[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
- elements[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
- elements[0][1] = Math::sin(p_rot) * p_scale.x;
+ columns[0][0] = Math::cos(p_rot) * p_scale.x;
+ columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
+ columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
+ columns[0][1] = Math::sin(p_rot) * p_scale.x;
}
Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const {
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index e5374315e2..76b31daa76 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -57,16 +57,16 @@ Transform3D Transform3D::inverse() const {
return ret;
}
-void Transform3D::rotate(const Vector3 &p_axis, real_t p_phi) {
- *this = rotated(p_axis, p_phi);
+void Transform3D::rotate(const Vector3 &p_axis, real_t p_angle) {
+ *this = rotated(p_axis, p_angle);
}
-Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_phi) const {
- return Transform3D(Basis(p_axis, p_phi), Vector3()) * (*this);
+Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_angle) const {
+ return Transform3D(Basis(p_axis, p_angle), Vector3()) * (*this);
}
-void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) {
- basis.rotate(p_axis, p_phi);
+void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) {
+ basis.rotate(p_axis, p_angle);
}
Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const {
@@ -194,9 +194,9 @@ Transform3D Transform3D::operator*(const real_t p_val) const {
}
Transform3D::operator String() const {
- return "[X: " + basis.get_axis(0).operator String() +
- ", Y: " + basis.get_axis(1).operator String() +
- ", Z: " + basis.get_axis(2).operator String() +
+ return "[X: " + basis.get_column(0).operator String() +
+ ", Y: " + basis.get_column(1).operator String() +
+ ", Z: " + basis.get_column(2).operator String() +
", O: " + origin.operator String() + "]";
}
@@ -207,9 +207,9 @@ Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) :
Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) :
origin(p_origin) {
- basis.set_axis(0, p_x);
- basis.set_axis(1, p_y);
- basis.set_axis(2, p_z);
+ basis.set_column(0, p_x);
+ basis.set_column(1, p_y);
+ basis.set_column(2, p_z);
}
Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) {
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index 3b4762e221..25832434cd 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -45,10 +45,10 @@ struct _NO_DISCARD_ Transform3D {
void affine_invert();
Transform3D affine_inverse() const;
- Transform3D rotated(const Vector3 &p_axis, real_t p_phi) const;
+ Transform3D rotated(const Vector3 &p_axis, real_t p_angle) const;
- void rotate(const Vector3 &p_axis, real_t p_phi);
- void rotate_basis(const Vector3 &p_axis, real_t p_phi);
+ void rotate(const Vector3 &p_axis, real_t p_angle);
+ void rotate_basis(const Vector3 &p_axis, real_t p_angle);
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
@@ -135,9 +135,9 @@ _FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const {
Vector3 v = p_vector - origin;
return Vector3(
- (basis.elements[0][0] * v.x) + (basis.elements[1][0] * v.y) + (basis.elements[2][0] * v.z),
- (basis.elements[0][1] * v.x) + (basis.elements[1][1] * v.y) + (basis.elements[2][1] * v.z),
- (basis.elements[0][2] * v.x) + (basis.elements[1][2] * v.y) + (basis.elements[2][2] * v.z));
+ (basis.rows[0][0] * v.x) + (basis.rows[1][0] * v.y) + (basis.rows[2][0] * v.z),
+ (basis.rows[0][1] * v.x) + (basis.rows[1][1] * v.y) + (basis.rows[2][1] * v.z),
+ (basis.rows[0][2] * v.x) + (basis.rows[1][2] * v.y) + (basis.rows[2][2] * v.z));
}
// Neither the plane regular xform or xform_inv are particularly efficient,
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index debc5cd00d..e146c4a4e3 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -231,14 +231,14 @@ Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const {
}
case VISIT_LEFT_BIT: {
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.left | TEST_AABB_BIT;
level++;
+ stack[level] = b.left | TEST_AABB_BIT;
continue;
}
case VISIT_RIGHT_BIT: {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.right | TEST_AABB_BIT;
level++;
+ stack[level] = b.right | TEST_AABB_BIT;
continue;
}
case VISIT_DONE_BIT: {
@@ -331,14 +331,14 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en
}
case VISIT_LEFT_BIT: {
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.left | TEST_AABB_BIT;
level++;
+ stack[level] = b.left | TEST_AABB_BIT;
continue;
}
case VISIT_RIGHT_BIT: {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.right | TEST_AABB_BIT;
level++;
+ stack[level] = b.right | TEST_AABB_BIT;
continue;
}
case VISIT_DONE_BIT: {
@@ -431,14 +431,14 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
}
case VISIT_LEFT_BIT: {
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.left | TEST_AABB_BIT;
level++;
+ stack[level] = b.left | TEST_AABB_BIT;
continue;
}
case VISIT_RIGHT_BIT: {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.right | TEST_AABB_BIT;
level++;
+ stack[level] = b.right | TEST_AABB_BIT;
continue;
}
case VISIT_DONE_BIT: {
@@ -551,14 +551,14 @@ bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_cou
}
case VISIT_LEFT_BIT: {
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.left | TEST_AABB_BIT;
level++;
+ stack[level] = b.left | TEST_AABB_BIT;
continue;
}
case VISIT_RIGHT_BIT: {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.right | TEST_AABB_BIT;
level++;
+ stack[level] = b.right | TEST_AABB_BIT;
continue;
}
case VISIT_DONE_BIT: {
@@ -644,14 +644,14 @@ bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count,
}
case VISIT_LEFT_BIT: {
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.left | TEST_AABB_BIT;
level++;
+ stack[level] = b.left | TEST_AABB_BIT;
continue;
}
case VISIT_RIGHT_BIT: {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = b.right | TEST_AABB_BIT;
level++;
+ stack[level] = b.right | TEST_AABB_BIT;
continue;
}
case VISIT_DONE_BIT: {
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index ed4266b115..a27227905c 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -163,7 +163,7 @@ Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const {
Vector2 v = *this;
Vector2 vd = p_to - v;
real_t len = vd.length();
- return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+ return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
// slide returns the component of the vector along the given plane, specified by its normal vector.
diff --git a/core/math/vector2.h b/core/math/vector2.h
index a2680b84fc..bd67299f33 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -31,6 +31,7 @@
#ifndef VECTOR2_H
#define VECTOR2_H
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
class String;
@@ -60,9 +61,11 @@ struct _NO_DISCARD_ Vector2 {
};
_FORCE_INLINE_ real_t &operator[](int p_idx) {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index 3f5f12d4dd..13b70031bd 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -31,6 +31,7 @@
#ifndef VECTOR2I_H
#define VECTOR2I_H
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
class String;
@@ -58,9 +59,11 @@ struct _NO_DISCARD_ Vector2i {
};
_FORCE_INLINE_ int32_t &operator[](int p_idx) {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ const int32_t &operator[](int p_idx) const {
+ DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 998c437a22..f94f39b7f2 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -31,14 +31,17 @@
#include "vector3.h"
#include "core/math/basis.h"
+#include "core/math/vector2.h"
+#include "core/math/vector3i.h"
+#include "core/string/ustring.h"
-void Vector3::rotate(const Vector3 &p_axis, const real_t p_phi) {
- *this = Basis(p_axis, p_phi).xform(*this);
+void Vector3::rotate(const Vector3 &p_axis, const real_t p_angle) {
+ *this = Basis(p_axis, p_angle).xform(*this);
}
-Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_phi) const {
+Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_angle) const {
Vector3 r = *this;
- r.rotate(p_axis, p_phi);
+ r.rotate(p_axis, p_angle);
return r;
}
@@ -94,7 +97,32 @@ Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const {
Vector3 v = *this;
Vector3 vd = p_to - v;
real_t len = vd.length();
- return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+ return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
+}
+
+Vector2 Vector3::octahedron_encode() const {
+ Vector3 n = *this;
+ n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z);
+ Vector2 o;
+ if (n.z >= 0.0f) {
+ o.x = n.x;
+ o.y = n.y;
+ } else {
+ o.x = (1.0f - Math::abs(n.y)) * (n.x >= 0.0f ? 1.0f : -1.0f);
+ o.y = (1.0f - Math::abs(n.x)) * (n.y >= 0.0f ? 1.0f : -1.0f);
+ }
+ o.x = o.x * 0.5f + 0.5f;
+ o.y = o.y * 0.5f + 0.5f;
+ return o;
+}
+
+Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
+ Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f);
+ Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y));
+ float t = CLAMP(-n.z, 0.0f, 1.0f);
+ n.x += n.x >= 0 ? -t : t;
+ n.y += n.y >= 0 ? -t : t;
+ return n.normalized();
}
Basis Vector3::outer(const Vector3 &p_with) const {
@@ -112,3 +140,7 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const {
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
+
+Vector3::operator Vector3i() const {
+ return Vector3i(x, y, z);
+}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index c1da159e00..8891532f42 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -31,12 +31,13 @@
#ifndef VECTOR3_H
#define VECTOR3_H
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
-#include "core/math/vector2.h"
-#include "core/math/vector3i.h"
-#include "core/string/ustring.h"
+class String;
struct Basis;
+struct Vector2;
+struct Vector3i;
struct _NO_DISCARD_ Vector3 {
static const int AXIS_COUNT = 3;
@@ -58,10 +59,12 @@ struct _NO_DISCARD_ Vector3 {
};
_FORCE_INLINE_ const real_t &operator[](const int p_axis) const {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
_FORCE_INLINE_ real_t &operator[](const int p_axis) {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
@@ -94,8 +97,8 @@ struct _NO_DISCARD_ Vector3 {
void snap(const Vector3 p_val);
Vector3 snapped(const Vector3 p_val) const;
- void rotate(const Vector3 &p_axis, const real_t p_phi);
- Vector3 rotated(const Vector3 &p_axis, const real_t p_phi) const;
+ void rotate(const Vector3 &p_axis, const real_t p_angle);
+ Vector3 rotated(const Vector3 &p_axis, const real_t p_angle) const;
/* Static Methods between 2 vector3s */
@@ -104,30 +107,8 @@ struct _NO_DISCARD_ Vector3 {
Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const;
Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const;
- _FORCE_INLINE_ Vector2 octahedron_encode() const {
- Vector3 n = *this;
- n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z);
- Vector2 o;
- if (n.z >= 0.0f) {
- o.x = n.x;
- o.y = n.y;
- } else {
- o.x = (1.0f - Math::abs(n.y)) * (n.x >= 0.0f ? 1.0f : -1.0f);
- o.y = (1.0f - Math::abs(n.x)) * (n.y >= 0.0f ? 1.0f : -1.0f);
- }
- o.x = o.x * 0.5f + 0.5f;
- o.y = o.y * 0.5f + 0.5f;
- return o;
- }
-
- static _FORCE_INLINE_ Vector3 octahedron_decode(const Vector2 &p_oct) {
- Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f);
- Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y));
- float t = CLAMP(-n.z, 0.0f, 1.0f);
- n.x += n.x >= 0 ? -t : t;
- n.y += n.y >= 0 ? -t : t;
- return n.normalized();
- }
+ Vector2 octahedron_encode() const;
+ static Vector3 octahedron_decode(const Vector2 &p_oct);
_FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const;
_FORCE_INLINE_ real_t dot(const Vector3 &p_with) const;
@@ -183,16 +164,9 @@ struct _NO_DISCARD_ Vector3 {
_FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const;
operator String() const;
- _FORCE_INLINE_ operator Vector3i() const {
- return Vector3i(x, y, z);
- }
+ operator Vector3i() const;
_FORCE_INLINE_ Vector3() {}
- _FORCE_INLINE_ Vector3(const Vector3i &p_ivec) {
- x = p_ivec.x;
- y = p_ivec.y;
- z = p_ivec.z;
- }
_FORCE_INLINE_ Vector3(const real_t p_x, const real_t p_y, const real_t p_z) {
x = p_x;
y = p_y;
@@ -344,7 +318,7 @@ Vector3 &Vector3::operator*=(const real_t p_scalar) {
}
// Multiplication operators required to workaround issues with LLVM using implicit conversion
-// to Vector2i instead for integers where it should not.
+// to Vector3i instead for integers where it should not.
_FORCE_INLINE_ Vector3 operator*(const float p_scalar, const Vector3 &p_vec) {
return p_vec * p_scalar;
diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp
index ac79b3c7ea..b8e74ea6d2 100644
--- a/core/math/vector3i.cpp
+++ b/core/math/vector3i.cpp
@@ -30,6 +30,9 @@
#include "vector3i.h"
+#include "core/math/vector3.h"
+#include "core/string/ustring.h"
+
void Vector3i::set_axis(const int p_axis, const int32_t p_value) {
ERR_FAIL_INDEX(p_axis, 3);
coord[p_axis] = p_value;
@@ -58,3 +61,7 @@ Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const {
Vector3i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")";
}
+
+Vector3i::operator Vector3() const {
+ return Vector3(x, y, z);
+}
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index d166de80aa..b49c1142ed 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -31,9 +31,11 @@
#ifndef VECTOR3I_H
#define VECTOR3I_H
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
-#include "core/string/ustring.h"
-#include "core/typedefs.h"
+
+class String;
+struct Vector3;
struct _NO_DISCARD_ Vector3i {
enum Axis {
@@ -53,10 +55,12 @@ struct _NO_DISCARD_ Vector3i {
};
_FORCE_INLINE_ const int32_t &operator[](const int p_axis) const {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
_FORCE_INLINE_ int32_t &operator[](const int p_axis) {
+ DEV_ASSERT((unsigned int)p_axis < 3);
return coord[p_axis];
}
@@ -105,6 +109,7 @@ struct _NO_DISCARD_ Vector3i {
_FORCE_INLINE_ bool operator>=(const Vector3i &p_v) const;
operator String() const;
+ operator Vector3() const;
_FORCE_INLINE_ Vector3i() {}
_FORCE_INLINE_ Vector3i(const int32_t p_x, const int32_t p_y, const int32_t p_z) {
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h
index 3cd9ad3819..577d4b9fbd 100644
--- a/core/object/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -38,7 +38,7 @@
#include "core/variant/callable.h"
class CallableCustomMethodPointerBase : public CallableCustom {
- uint32_t *comp_ptr;
+ uint32_t *comp_ptr = nullptr;
uint32_t comp_size;
uint32_t h;
#ifdef DEBUG_METHODS_ENABLED
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index c29316c089..593f27b7cf 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -37,192 +37,19 @@
#define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock);
#define OBJTYPE_WLOCK RWLockWrite _rw_lockw_(lock);
-MethodDefinition D_METHOD(const char *p_name) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.push_back(StaticCString::create(p_arg1));
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(2);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(3);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(4);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(5);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(6);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(7);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- md.args.write[6] = StaticCString::create(p_arg7);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(8);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- md.args.write[6] = StaticCString::create(p_arg7);
- md.args.write[7] = StaticCString::create(p_arg8);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(9);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- md.args.write[6] = StaticCString::create(p_arg7);
- md.args.write[7] = StaticCString::create(p_arg8);
- md.args.write[8] = StaticCString::create(p_arg9);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(10);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- md.args.write[6] = StaticCString::create(p_arg7);
- md.args.write[7] = StaticCString::create(p_arg8);
- md.args.write[8] = StaticCString::create(p_arg9);
- md.args.write[9] = StaticCString::create(p_arg10);
- return md;
-}
-
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(11);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- md.args.write[6] = StaticCString::create(p_arg7);
- md.args.write[7] = StaticCString::create(p_arg8);
- md.args.write[8] = StaticCString::create(p_arg9);
- md.args.write[9] = StaticCString::create(p_arg10);
- md.args.write[10] = StaticCString::create(p_arg11);
- return md;
-}
+#ifdef DEBUG_METHODS_ENABLED
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12) {
+MethodDefinition D_METHODP(const char *p_name, const char *const **p_args, uint32_t p_argcount) {
MethodDefinition md;
md.name = StaticCString::create(p_name);
- md.args.resize(12);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- md.args.write[6] = StaticCString::create(p_arg7);
- md.args.write[7] = StaticCString::create(p_arg8);
- md.args.write[8] = StaticCString::create(p_arg9);
- md.args.write[9] = StaticCString::create(p_arg10);
- md.args.write[10] = StaticCString::create(p_arg11);
- md.args.write[11] = StaticCString::create(p_arg12);
+ md.args.resize(p_argcount);
+ for (uint32_t i = 0; i < p_argcount; i++) {
+ md.args.write[i] = StaticCString::create(*p_args[i]);
+ }
return md;
}
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13) {
- MethodDefinition md;
- md.name = StaticCString::create(p_name);
- md.args.resize(13);
- md.args.write[0] = StaticCString::create(p_arg1);
- md.args.write[1] = StaticCString::create(p_arg2);
- md.args.write[2] = StaticCString::create(p_arg3);
- md.args.write[3] = StaticCString::create(p_arg4);
- md.args.write[4] = StaticCString::create(p_arg5);
- md.args.write[5] = StaticCString::create(p_arg6);
- md.args.write[6] = StaticCString::create(p_arg7);
- md.args.write[7] = StaticCString::create(p_arg8);
- md.args.write[8] = StaticCString::create(p_arg9);
- md.args.write[9] = StaticCString::create(p_arg10);
- md.args.write[10] = StaticCString::create(p_arg11);
- md.args.write[11] = StaticCString::create(p_arg12);
- md.args.write[12] = StaticCString::create(p_arg13);
- return md;
-}
+#endif
ClassDB::APIType ClassDB::current_api = API_CORE;
@@ -557,6 +384,19 @@ bool ClassDB::can_instantiate(const StringName &p_class) {
return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance));
}
+bool ClassDB::is_virtual(const StringName &p_class) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *ti = classes.getptr(p_class);
+ ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+#ifdef TOOLS_ENABLED
+ if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
+ return false;
+ }
+#endif
+ return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance) && ti->is_virtual);
+}
+
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
OBJTYPE_WLOCK;
@@ -1197,7 +1037,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
if (psg->_setptr) {
psg->_setptr->call(p_object, arg, 2, ce);
} else {
- p_object->call(psg->setter, arg, 2, ce);
+ p_object->callp(psg->setter, arg, 2, ce);
}
} else {
@@ -1205,7 +1045,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
if (psg->_setptr) {
psg->_setptr->call(p_object, arg, 1, ce);
} else {
- p_object->call(psg->setter, arg, 1, ce);
+ p_object->callp(psg->setter, arg, 1, ce);
}
}
@@ -1238,14 +1078,14 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia
Variant index = psg->index;
const Variant *arg[1] = { &index };
Callable::CallError ce;
- r_value = p_object->call(psg->getter, arg, 1, ce);
+ r_value = p_object->callp(psg->getter, arg, 1, ce);
} else {
Callable::CallError ce;
if (psg->_getptr) {
r_value = psg->_getptr->call(p_object, nullptr, 0, ce);
} else {
- r_value = p_object->call(psg->getter, nullptr, 0, ce);
+ r_value = p_object->callp(psg->getter, nullptr, 0, ce);
}
}
return true;
@@ -1407,8 +1247,13 @@ void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method
type->method_map[p_method->get_name()] = p_method;
}
+#ifdef DEBUG_METHODS_ENABLED
MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
StringName mdname = method_name.name;
+#else
+MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount) {
+ StringName mdname = StaticCString::create(method_name);
+#endif
OBJTYPE_WLOCK;
ERR_FAIL_COND_V(!p_bind, nullptr);
@@ -1472,9 +1317,10 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
if (p_object_core) {
mi.flags |= METHOD_FLAG_OBJECT_CORE;
}
- if (p_arg_names.size()) {
+
+ if (!p_object_core) {
if (p_arg_names.size() != mi.arguments.size()) {
- WARN_PRINT("Mismatch argument name count for virtual function: " + String(p_class) + "::" + p_method.name);
+ WARN_PRINT("Mismatch argument name count for virtual method: " + String(p_class) + "::" + p_method.name);
} else {
for (int i = 0; i < p_arg_names.size(); i++) {
mi.arguments[i].name = p_arg_names[i];
@@ -1482,6 +1328,10 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
}
}
+ if (classes[p_class].virtual_methods_map.has(p_method.name)) {
+ // overloading not supported
+ ERR_FAIL_MSG("Virtual method already bound '" + String(p_class) + "::" + p_method.name + "'.");
+ }
classes[p_class].virtual_methods.push_back(mi);
classes[p_class].virtual_methods_map[p_method.name] = mi;
@@ -1538,15 +1388,6 @@ bool ClassDB::is_class_exposed(const StringName &p_class) {
return ti->exposed;
}
-StringName ClassDB::get_category(const StringName &p_node) {
- ERR_FAIL_COND_V(!classes.has(p_node), StringName());
-#ifdef DEBUG_ENABLED
- return classes[p_node].category;
-#else
- return StringName();
-#endif
-}
-
void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) {
if (resource_base_extensions.has(p_extension)) {
return;
@@ -1593,7 +1434,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
if (Engine::get_singleton()->has_singleton(p_class)) {
c = Engine::get_singleton()->get_singleton_object(p_class);
cleanup_c = false;
- } else if (ClassDB::can_instantiate(p_class)) {
+ } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) {
c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
@@ -1681,6 +1522,30 @@ void ClassDB::unregister_extension_class(const StringName &p_class) {
classes.erase(p_class);
}
+Map<StringName, ClassDB::NativeStruct> ClassDB::native_structs;
+void ClassDB::register_native_struct(const StringName &p_name, const String &p_code, uint64_t p_current_size) {
+ NativeStruct ns;
+ ns.ccode = p_code;
+ ns.struct_size = p_current_size;
+ native_structs[p_name] = ns;
+}
+
+void ClassDB::get_native_struct_list(List<StringName> *r_names) {
+ for (const KeyValue<StringName, NativeStruct> &E : native_structs) {
+ r_names->push_back(E.key);
+ }
+}
+
+String ClassDB::get_native_struct_code(const StringName &p_name) {
+ ERR_FAIL_COND_V(!native_structs.has(p_name), String());
+ return native_structs[p_name].ccode;
+}
+
+uint64_t ClassDB::get_native_struct_size(const StringName &p_name) {
+ ERR_FAIL_COND_V(!native_structs.has(p_name), 0);
+ return native_structs[p_name].struct_size;
+}
+
RWLock ClassDB::lock;
void ClassDB::cleanup_defaults() {
@@ -1704,6 +1569,7 @@ void ClassDB::cleanup() {
classes.clear();
resource_base_extensions.clear();
compat_classes.clear();
+ native_structs.clear();
}
//
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 5d258a29bf..d4e1fc4e76 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -35,16 +35,14 @@
#include "core/object/object.h"
#include "core/string/print_string.h"
-/** To bind more then 6 parameters include this:
- *
- */
-
// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
#include "core/object/callable_method_pointer.h"
#define DEFVAL(m_defval) (m_defval)
+#ifdef DEBUG_METHODS_ENABLED
+
struct MethodDefinition {
StringName name;
Vector<StringName> args;
@@ -55,20 +53,26 @@ struct MethodDefinition {
name(p_name) {}
};
-MethodDefinition D_METHOD(const char *p_name);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12);
-MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13);
+MethodDefinition D_METHODP(const char *p_name, const char *const **p_args, uint32_t p_argcount);
+
+template <typename... VarArgs>
+MethodDefinition D_METHOD(const char *p_name, const VarArgs... p_args) {
+ const char *args[sizeof...(p_args) + 1] = { p_args..., nullptr }; // +1 makes sure zero sized arrays are also supported.
+ const char *const *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ return D_METHODP(p_name, sizeof...(p_args) == 0 ? nullptr : (const char *const **)argptrs, sizeof...(p_args));
+}
+
+#else
+
+// When DEBUG_METHODS_ENABLED is set this will let the engine know
+// the argument names for easier debugging.
+#define D_METHOD(m_c, ...) m_c
+
+#endif
class ClassDB {
public:
@@ -85,8 +89,8 @@ public:
int index;
StringName setter;
StringName getter;
- MethodBind *_setptr;
- MethodBind *_getptr;
+ MethodBind *_setptr = nullptr;
+ MethodBind *_getptr = nullptr;
Variant::Type type;
};
@@ -109,7 +113,6 @@ public:
Set<StringName> methods_in_properties;
List<MethodInfo> virtual_methods;
Map<StringName, MethodInfo> virtual_methods_map;
- StringName category;
Map<StringName, Vector<Error>> method_error_values;
#endif
HashMap<StringName, PropertySetGet> property_setget;
@@ -118,6 +121,7 @@ public:
StringName name;
bool disabled = false;
bool exposed = false;
+ bool is_virtual = false;
Object *(*creation_func)() = nullptr;
ClassInfo() {}
@@ -134,7 +138,11 @@ public:
static HashMap<StringName, StringName> resource_base_extensions;
static HashMap<StringName, StringName> compat_classes;
+#ifdef DEBUG_METHODS_ENABLED
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount);
+#else
+ static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount);
+#endif
static APIType current_api;
@@ -143,6 +151,13 @@ public:
static HashMap<StringName, HashMap<StringName, Variant>> default_values;
static Set<StringName> default_values_cached;
+ // Native structs, used by binder
+ struct NativeStruct {
+ String ccode; // C code to create the native struct, fields separated by ; Arrays accepted (even containing other structs), also function pointers. All types must be Godot types.
+ uint64_t struct_size; // local size of struct, for comparison
+ };
+ static Map<StringName, NativeStruct> native_structs;
+
private:
// Non-locking variants of get_parent_class and is_parent_class.
static StringName _get_parent_class(const StringName &p_class);
@@ -156,20 +171,21 @@ public:
}
template <class T>
- static void register_class() {
+ static void register_class(bool p_virtual = false) {
GLOBAL_LOCK_FUNCTION;
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_COND(!t);
t->creation_func = &creator<T>;
t->exposed = true;
+ t->is_virtual = p_virtual;
t->class_ptr = T::get_class_ptr_static();
t->api = current_api;
T::register_custom_data_to_otdb();
}
template <class T>
- static void register_virtual_class() {
+ static void register_abstract_class() {
GLOBAL_LOCK_FUNCTION;
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@@ -210,6 +226,7 @@ public:
static bool class_exists(const StringName &p_class);
static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
static bool can_instantiate(const StringName &p_class);
+ static bool is_virtual(const StringName &p_class);
static Object *instantiate(const StringName &p_class);
static void set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance);
@@ -217,75 +234,27 @@ public:
static uint64_t get_api_hash(APIType p_api);
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method) {
- MethodBind *bind = create_method_bind(p_method);
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, nullptr, 0); //use static function, much smaller binary usage
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[1] = { &p_def1 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 1);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[2] = { &p_def1, &p_def2 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 2);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[3] = { &p_def1, &p_def2, &p_def3 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 3);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[4] = { &p_def1, &p_def2, &p_def3, &p_def4 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 4);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[5] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 5);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[6] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 6);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6, const Variant &p_def7) {
+ template <class N, class M, typename... VarArgs>
+ static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[7] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6, &p_def7 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 7);
+ return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6, const Variant &p_def7, const Variant &p_def8) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[8] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6, &p_def7, &p_def8 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 8);
+ template <class N, class M, typename... VarArgs>
+ static MethodBind *bind_static_method(const StringName &p_class, N p_method_name, M p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ MethodBind *bind = create_static_method_bind(p_method);
+ bind->set_instance_class(p_class);
+ return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
template <class M>
@@ -369,8 +338,6 @@ public:
static Vector<Error> get_method_error_return_values(const StringName &p_class, const StringName &p_method);
static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr);
- static StringName get_category(const StringName &p_node);
-
static void set_class_enabled(const StringName &p_class, bool p_enable);
static bool is_class_enabled(const StringName &p_class);
@@ -387,6 +354,11 @@ public:
static APIType get_current_api();
static void cleanup_defaults();
static void cleanup();
+
+ static void register_native_struct(const StringName &p_name, const String &p_code, uint64_t p_current_size);
+ static void get_native_struct_list(List<StringName> *r_names);
+ static String get_native_struct_code(const StringName &p_name);
+ static uint64_t get_native_struct_size(const StringName &p_name); // Used for asserting
};
#ifdef DEBUG_METHODS_ENABLED
@@ -436,11 +408,17 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
::ClassDB::register_class<m_class>(); \
}
-#define GDREGISTER_VIRTUAL_CLASS(m_class) \
- if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
- ::ClassDB::register_virtual_class<m_class>(); \
+#define GDREGISTER_VIRTUAL_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ::ClassDB::register_class<m_class>(true); \
+ }
+#define GDREGISTER_ABSTRACT_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ::ClassDB::register_abstract_class<m_class>(); \
}
+#define GDREGISTER_NATIVE_STRUCT(m_class, m_code) ClassDB::register_native_struct(#m_class, m_code, sizeof(m_class))
+
#include "core/disabled_classes.gen.h"
#endif // CLASS_DB_H
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index 5de1b49026..c18d70d9f6 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -3,12 +3,13 @@ proto = """
StringName _gdvirtual_##m_name##_sn = #m_name;\\
mutable bool _gdvirtual_##m_name##_initialized = false;\\
mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
+template<bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
if (script_instance) {\\
Callable::CallError ce; \\
$CALLSIARGS\\
- $CALLSIBEGINscript_instance->call(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
+ $CALLSIBEGINscript_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
if (ce.error == Callable::CallError::CALL_OK) {\\
$CALLSIRET\\
return true;\\
@@ -25,6 +26,11 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
$CALLPTRRET\\
return true;\\
}\\
+ \\
+ if (required) {\\
+ ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");\\
+ $RVOID\\
+ }\\
\\
return false;\\
}\\
@@ -61,10 +67,12 @@ def generate_version(argcount, const=False, returns=False):
if returns:
sproto += "R"
s = s.replace("$RET", "m_ret, ")
+ s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors
s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;")
method_info += "\tmethod_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
else:
s = s.replace("$RET", "")
+ s = s.replace("$RVOID", "")
s = s.replace("$CALLPTRRETDEF", "")
if const:
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index 3c828eabd9..79c36ac81f 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
+#include "core/object/class_db.h"
#include "core/object/script_language.h"
MessageQueue *MessageQueue::singleton = nullptr;
@@ -40,23 +41,8 @@ MessageQueue *MessageQueue::get_singleton() {
return singleton;
}
-Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
- return push_callable(Callable(p_id, p_method), p_args, p_argcount, p_show_error);
-}
-
-Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return push_call(p_id, p_method, argptr, argc, false);
+Error MessageQueue::push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
+ return push_callablep(Callable(p_id, p_method), p_args, p_argcount, p_show_error);
}
Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value) {
@@ -113,8 +99,8 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) {
return OK;
}
-Error MessageQueue::push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- return push_call(p_object->get_instance_id(), p_method, VARIANT_ARG_PASS);
+Error MessageQueue::push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
+ return push_callp(p_object->get_instance_id(), p_method, p_args, p_argcount, p_show_error);
}
Error MessageQueue::push_notification(Object *p_object, int p_notification) {
@@ -125,7 +111,7 @@ Error MessageQueue::push_set(Object *p_object, const StringName &p_prop, const V
return push_set(p_object->get_instance_id(), p_prop, p_value);
}
-Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) {
+Error MessageQueue::push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) {
_THREAD_SAFE_METHOD_
int room_needed = sizeof(Message) + sizeof(Variant) * p_argcount;
@@ -155,21 +141,6 @@ Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_
return OK;
}
-Error MessageQueue::push_callable(const Callable &p_callable, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return push_callable(p_callable, argptr, argc);
-}
-
void MessageQueue::statistics() {
Map<StringName, int> set_count;
Map<int, int> notify_count;
diff --git a/core/object/message_queue.h b/core/object/message_queue.h
index a4449cf473..2219cdb8f6 100644
--- a/core/object/message_queue.h
+++ b/core/object/message_queue.h
@@ -31,8 +31,11 @@
#ifndef MESSAGE_QUEUE_H
#define MESSAGE_QUEUE_H
-#include "core/object/class_db.h"
+#include "core/object/object_id.h"
#include "core/os/thread_safe.h"
+#include "core/variant/variant.h"
+
+class Object;
class MessageQueue {
_THREAD_SAFE_CLASS_
@@ -59,10 +62,10 @@ class MessageQueue {
};
};
- uint8_t *buffer;
+ uint8_t *buffer = nullptr;
uint32_t buffer_end = 0;
uint32_t buffer_max_used = 0;
- uint32_t buffer_size;
+ uint32_t buffer_size = 0;
void _call_function(const Callable &p_callable, const Variant *p_args, int p_argcount, bool p_show_error);
@@ -73,14 +76,42 @@ class MessageQueue {
public:
static MessageQueue *get_singleton();
- Error push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
- Error push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_LIST);
+ Error push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
+ template <typename... VarArgs>
+ Error push_call(ObjectID p_id, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callp(p_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
Error push_notification(ObjectID p_id, int p_notification);
Error push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value);
- Error push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false);
- Error push_callable(const Callable &p_callable, VARIANT_ARG_LIST);
+ Error push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false);
+
+ template <typename... VarArgs>
+ Error push_callable(const Callable &p_callable, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callablep(p_callable, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ Error push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
+ template <typename... VarArgs>
+ Error push_call(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
- Error push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
Error push_notification(Object *p_object, int p_notification);
Error push_set(Object *p_object, const StringName &p_prop, const Variant &p_value);
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index 32269b5f19..a208c1a2b2 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -69,8 +69,6 @@ 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));
-#else
- info.name = String("arg" + itos(p_argument));
#endif
return info;
}
@@ -83,6 +81,10 @@ void MethodBind::_set_const(bool p_const) {
_const = p_const;
}
+void MethodBind::_set_static(bool p_static) {
+ _static = p_static;
+}
+
void MethodBind::_set_returns(bool p_returns) {
_returns = p_returns;
}
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index 02b73fa273..2870195911 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -60,6 +60,7 @@ class MethodBind {
int default_argument_count = 0;
int argument_count = 0;
+ bool _static = false;
bool _const = false;
bool _returns = false;
@@ -69,6 +70,7 @@ protected:
Vector<StringName> arg_names;
#endif
void _set_const(bool p_const);
+ void _set_static(bool p_static);
void _set_returns(bool p_returns);
virtual Variant::Type _gen_argument_type(int p_arg) const = 0;
virtual PropertyInfo _gen_argument_type_info(int p_arg) const = 0;
@@ -116,7 +118,7 @@ public:
#endif
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
- uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
+ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0) | (is_static() ? METHOD_FLAG_STATIC : 0); }
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
_FORCE_INLINE_ void set_instance_class(const StringName &p_class) { instance_class = p_class; }
@@ -129,6 +131,7 @@ public:
void set_name(const StringName &p_name);
_FORCE_INLINE_ int get_method_id() const { return method_id; }
_FORCE_INLINE_ bool is_const() const { return _const; }
+ _FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ bool has_return() const { return _returns; }
virtual bool is_vararg() const { return false; }
@@ -140,54 +143,60 @@ public:
virtual ~MethodBind();
};
-template <class T>
-class MethodBindVarArg : public MethodBind {
-public:
- typedef Variant (T::*NativeCall)(const Variant **, int, Callable::CallError &);
-
+// MethodBindVarArg base CRTP
+template <class Derived, class T, class R, bool should_returns>
+class MethodBindVarArgBase : public MethodBind {
protected:
- NativeCall call_method = nullptr;
- MethodInfo arguments;
+ R(T::*method)
+ (const Variant **, int, Callable::CallError &);
+ MethodInfo method_info;
public:
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
if (p_arg < 0) {
- return arguments.return_val;
- } else if (p_arg < arguments.arguments.size()) {
- return arguments.arguments[p_arg];
+ return _gen_return_type_info();
+ } else if (p_arg < method_info.arguments.size()) {
+ return method_info.arguments[p_arg];
} else {
return PropertyInfo(Variant::NIL, "arg_" + itos(p_arg), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
}
- virtual Variant::Type _gen_argument_type(int p_arg) const {
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
return _gen_argument_type_info(p_arg).type;
}
#ifdef DEBUG_METHODS_ENABLED
- virtual GodotTypeInfo::Metadata get_argument_meta(int) const {
+ virtual GodotTypeInfo::Metadata get_argument_meta(int) const override {
return GodotTypeInfo::METADATA_NONE;
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- T *instance = static_cast<T *>(p_object);
- return (instance->*call_method)(p_args, p_arg_count, r_error);
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ ERR_FAIL(); // Can't call.
}
- void set_method_info(const MethodInfo &p_info, bool p_return_nil_is_variant) {
- set_argument_count(p_info.arguments.size());
- Variant::Type *at = memnew_arr(Variant::Type, p_info.arguments.size() + 1);
- at[0] = p_info.return_val.type;
- if (p_info.arguments.size()) {
+ virtual bool is_const() const { return false; }
+
+ virtual bool is_vararg() const override { return true; }
+
+ MethodBindVarArgBase(
+ R (T::*p_method)(const Variant **, int, Callable::CallError &),
+ const MethodInfo &p_method_info,
+ bool p_return_nil_is_variant) :
+ method(p_method), method_info(p_method_info) {
+ set_argument_count(method_info.arguments.size());
+ Variant::Type *at = memnew_arr(Variant::Type, method_info.arguments.size() + 1);
+ at[0] = _gen_return_type_info().type;
+ if (method_info.arguments.size()) {
#ifdef DEBUG_METHODS_ENABLED
Vector<StringName> names;
- names.resize(p_info.arguments.size());
+ names.resize(method_info.arguments.size());
#endif
- for (int i = 0; i < p_info.arguments.size(); i++) {
- at[i + 1] = p_info.arguments[i].type;
+ for (int i = 0; i < method_info.arguments.size(); i++) {
+ at[i + 1] = method_info.arguments[i].type;
#ifdef DEBUG_METHODS_ENABLED
- names.write[i] = p_info.arguments[i].name;
+ names.write[i] = method_info.arguments[i].name;
#endif
}
@@ -196,31 +205,76 @@ public:
#endif
}
argument_types = at;
- arguments = p_info;
if (p_return_nil_is_variant) {
- arguments.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ method_info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
}
+
+ _set_returns(should_returns);
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
- ERR_FAIL(); // Can't call.
+private:
+ PropertyInfo _gen_return_type_info() const {
+ return Derived::_gen_return_type_info_impl();
}
+};
- void set_method(NativeCall p_method) { call_method = p_method; }
- virtual bool is_const() const { return false; }
+// variadic, no return
+template <class T>
+class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
+ friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
+
+public:
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)(p_args, p_arg_count, r_error);
+ return {};
+ }
- virtual bool is_vararg() const { return true; }
+ MethodBindVarArgT(
+ void (T::*p_method)(const Variant **, int, Callable::CallError &),
+ const MethodInfo &p_method_info,
+ bool p_return_nil_is_variant) :
+ MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>(p_method, p_method_info, p_return_nil_is_variant) {
+ }
- MethodBindVarArg() {
- _set_returns(true);
+private:
+ static PropertyInfo _gen_return_type_info_impl() {
+ return {};
}
};
template <class T>
-MethodBind *create_vararg_method_bind(Variant (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
- MethodBindVarArg<T> *a = memnew((MethodBindVarArg<T>));
- a->set_method(p_method);
- a->set_method_info(p_info, p_return_nil_is_variant);
+MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
+ MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
+ a->set_instance_class(T::get_class_static());
+ return a;
+}
+
+// variadic, return
+template <class T, class R>
+class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
+ friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
+
+public:
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error);
+ }
+
+ MethodBindVarArgTR(
+ R (T::*p_method)(const Variant **, int, Callable::CallError &),
+ const MethodInfo &p_info,
+ bool p_return_nil_is_variant) :
+ MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>(p_method, p_info, p_return_nil_is_variant) {
+ }
+
+private:
+ static PropertyInfo _gen_return_type_info_impl() {
+ return GetTypeInfo<R>::get_class_info();
+ }
+};
+
+template <class T, class R>
+MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
+ MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
return a;
}
@@ -249,7 +303,7 @@ protected:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
- virtual Variant::Type _gen_argument_type(int p_arg) const {
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
@@ -260,7 +314,7 @@ protected:
#pragma GCC diagnostic pop
#endif
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
return pi;
@@ -268,25 +322,25 @@ protected:
public:
#ifdef DEBUG_METHODS_ENABLED
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
return call_get_argument_metadata<P...>(p_arg);
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
#ifdef TYPED_METHOD_BIND
call_with_variant_args_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
#else
- call_with_variant_args_dv((MB_T *)(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
+ call_with_variant_args_dv(reinterpret_cast<MB_T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
#endif
return Variant();
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args<T, P...>(static_cast<T *>(p_object), method, p_args);
#else
- call_with_ptr_args<MB_T, P...>((MB_T *)(p_object), method, p_args);
+ call_with_ptr_args<MB_T, P...>(reinterpret_cast<MB_T *>(p_object), method, p_args);
#endif
}
@@ -308,7 +362,7 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) {
return a;
}
-// no return, not const
+// no return, const
#ifdef TYPED_METHOD_BIND
template <class T, class... P>
@@ -324,7 +378,7 @@ protected:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
- virtual Variant::Type _gen_argument_type(int p_arg) const {
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
@@ -335,7 +389,7 @@ protected:
#pragma GCC diagnostic pop
#endif
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
return pi;
@@ -343,25 +397,25 @@ protected:
public:
#ifdef DEBUG_METHODS_ENABLED
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
return call_get_argument_metadata<P...>(p_arg);
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
#ifdef TYPED_METHOD_BIND
call_with_variant_argsc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
#else
- call_with_variant_argsc_dv((MB_T *)(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
+ call_with_variant_argsc_dv(reinterpret_cast<MB_T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
#endif
return Variant();
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_argsc<T, P...>(static_cast<T *>(p_object), method, p_args);
#else
- call_with_ptr_argsc<MB_T, P...>((MB_T *)(p_object), method, p_args);
+ call_with_ptr_argsc<MB_T, P...>(reinterpret_cast<MB_T *>(p_object), method, p_args);
#endif
}
@@ -401,7 +455,7 @@ protected:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
- virtual Variant::Type _gen_argument_type(int p_arg) const {
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
@@ -409,7 +463,7 @@ protected:
}
}
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
PropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
@@ -424,7 +478,7 @@ protected:
public:
#ifdef DEBUG_METHODS_ENABLED
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
if (p_arg >= 0) {
return call_get_argument_metadata<P...>(p_arg);
} else {
@@ -433,21 +487,21 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
Variant ret;
#ifdef TYPED_METHOD_BIND
call_with_variant_args_ret_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
#else
- call_with_variant_args_ret_dv((MB_T *)p_object, method, p_args, p_arg_count, ret, r_error, get_default_arguments());
+ call_with_variant_args_ret_dv(reinterpret_cast<MB_T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
#endif
return ret;
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args_ret<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
#else
- call_with_ptr_args_ret<MB_T, R, P...>((MB_T *)(p_object), method, p_args, r_ret);
+ call_with_ptr_args_ret<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_object), method, p_args, r_ret);
#endif
}
@@ -488,7 +542,7 @@ protected:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
- virtual Variant::Type _gen_argument_type(int p_arg) const {
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
@@ -496,7 +550,7 @@ protected:
}
}
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
PropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
@@ -511,7 +565,7 @@ protected:
public:
#ifdef DEBUG_METHODS_ENABLED
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
if (p_arg >= 0) {
return call_get_argument_metadata<P...>(p_arg);
} else {
@@ -520,21 +574,21 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
Variant ret;
#ifdef TYPED_METHOD_BIND
call_with_variant_args_retc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
#else
- call_with_variant_args_retc_dv((MB_T *)(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
+ call_with_variant_args_retc_dv(reinterpret_cast<MB_T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
#endif
return ret;
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args_retc<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
#else
- call_with_ptr_args_retc<MB_T, R, P...>((MB_T *)(p_object), method, p_args, r_ret);
+ call_with_ptr_args_retc<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_object), method, p_args, r_ret);
#endif
}
@@ -558,4 +612,139 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
return a;
}
+/* STATIC BINDS */
+
+// no return
+
+template <class... P>
+class MethodBindTS : public MethodBind {
+ void (*function)(P...);
+
+protected:
+// GCC raises warnings in the case P = {} as the comparison is always false...
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ return Variant::NIL;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ }
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
+ return call_get_argument_metadata<P...>(p_arg);
+ }
+
+#endif
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ (void)p_object; // unused
+ call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments());
+ return Variant();
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ (void)p_object;
+ (void)r_ret;
+ call_with_ptr_args_static_method(function, p_args);
+ }
+
+ MethodBindTS(void (*p_function)(P...)) {
+ function = p_function;
+ _generate_argument_types(sizeof...(P));
+ set_argument_count(sizeof...(P));
+ _set_static(true);
+ }
+};
+
+template <class... P>
+MethodBind *create_static_method_bind(void (*p_method)(P...)) {
+ MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
+ return a;
+}
+
+// return
+
+template <class R, class... P>
+class MethodBindTRS : public MethodBind {
+ R(*function)
+ (P...);
+
+protected:
+// GCC raises warnings in the case P = {} as the comparison is always false...
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ } else {
+ return GetTypeInfo<R>::get_class_info();
+ }
+ }
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
+ if (p_arg >= 0) {
+ return call_get_argument_metadata<P...>(p_arg);
+ } else {
+ return GetTypeInfo<R>::METADATA;
+ }
+ }
+
+#endif
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ Variant ret;
+ call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments());
+ return ret;
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ (void)p_object;
+ call_with_ptr_args_static_method_ret(function, p_args, r_ret);
+ }
+
+ MethodBindTRS(R (*p_function)(P...)) {
+ function = p_function;
+ _generate_argument_types(sizeof...(P));
+ set_argument_count(sizeof...(P));
+ _set_static(true);
+ _set_returns(true);
+ }
+};
+
+template <class R, class... P>
+MethodBind *create_static_method_bind(R (*p_method)(P...)) {
+ MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
+ return a;
+}
+
#endif // METHOD_BIND_H
diff --git a/core/object/object.cpp b/core/object/object.cpp
index a8a49bd22e..2b62041533 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -416,21 +416,22 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
return;
- } else if (p_name == CoreStringNames::get_singleton()->_meta) {
- metadata = p_value.duplicate();
- if (r_valid) {
- *r_valid = true;
- }
- return;
- }
-
- // Something inside the object... :|
- bool success = _setv(p_name, p_value);
- if (success) {
- if (r_valid) {
- *r_valid = true;
+ } else {
+ OrderedHashMap<StringName, Variant>::Element *E = metadata_properties.getptr(p_name);
+ if (E) {
+ E->get() = p_value;
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
+ } else if (p_name.operator String().begins_with("metadata/")) {
+ // Must exist, otherwise duplicate() will not work.
+ set_meta(p_name.operator String().replace_first("metadata/", ""), p_value);
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
}
- return;
}
#ifdef TOOLS_ENABLED
@@ -446,6 +447,15 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
#endif
+ // Something inside the object... :|
+ bool success = _setv(p_name, p_value);
+ if (success) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
+ }
+
if (r_valid) {
*r_valid = false;
}
@@ -496,24 +506,18 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
*r_valid = true;
}
return ret;
+ }
- } else if (p_name == CoreStringNames::get_singleton()->_meta) {
- ret = metadata;
+ const OrderedHashMap<StringName, Variant>::Element *E = metadata_properties.getptr(p_name);
+
+ if (E) {
+ ret = E->get();
if (r_valid) {
*r_valid = true;
}
return ret;
} else {
- // Something inside the object... :|
- bool success = _getv(p_name, ret);
- if (success) {
- if (r_valid) {
- *r_valid = true;
- }
- return ret;
- }
-
#ifdef TOOLS_ENABLED
if (script_instance) {
bool valid;
@@ -526,6 +530,14 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
}
}
#endif
+ // Something inside the object... :|
+ bool success = _getv(p_name, ret);
+ if (success) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return ret;
+ }
if (r_valid) {
*r_valid = false;
@@ -624,8 +636,12 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
if (_extension) {
- p_list->push_back(PropertyInfo(Variant::NIL, _extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
- ClassDB::get_property_list(_extension->class_name, p_list, true, this);
+ const ObjectNativeExtension *current_extension = _extension;
+ while (current_extension) {
+ p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
+ ClassDB::get_property_list(current_extension->class_name, p_list, true, this);
+ current_extension = current_extension->parent;
+ }
}
if (_extension && _extension->get_property_list) {
@@ -644,13 +660,20 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (!is_class("Script")) { // can still be set, but this is for user-friendliness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
- if (!metadata.is_empty()) {
- p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- }
+
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);
}
+
+ for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
+ PropertyInfo pi = PropertyInfo(K.value().get_type(), "metadata/" + K.key().operator String());
+ if (K.value().get_type() == Variant::OBJECT) {
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Resource";
+ }
+ p_list->push_back(pi);
+ }
}
void Object::_validate_property(PropertyInfo &property) const {
@@ -679,7 +702,7 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal
StringName method = *p_args[0];
- return call(method, &p_args[1], p_argcount - 1, r_error);
+ return callp(method, &p_args[1], p_argcount - 1, r_error);
}
Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -700,7 +723,7 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call
StringName method = *p_args[0];
- MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
+ MessageQueue::get_singleton()->push_callp(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
return Variant();
}
@@ -750,31 +773,14 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) {
}
Callable::CallError ce;
- Variant ret = call(p_method, argptrs, p_args.size(), ce);
+ Variant ret = callp(p_method, argptrs, p_args.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + ".");
}
return ret;
}
-Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
-
- Variant ret = call(p_name, argptr, argc, error);
- return ret;
-}
-
-Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
if (p_method == CoreStringNames::get_singleton()->_free) {
@@ -808,7 +814,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
OBJ_DEBUG_LOCK
if (script_instance) {
- ret = script_instance->call(p_method, p_args, p_argcount, r_error);
+ ret = script_instance->callp(p_method, p_args, p_argcount, r_error);
//force jumptable
switch (r_error.error) {
case Callable::CallError::CALL_OK:
@@ -858,7 +864,9 @@ String Object::to_string() {
}
}
if (_extension && _extension->to_string) {
- return _extension->to_string(_extension_instance);
+ String ret;
+ _extension->to_string(_extension_instance, &ret);
+ return ret;
}
return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
}
@@ -928,20 +936,38 @@ bool Object::has_meta(const StringName &p_name) const {
void Object::set_meta(const StringName &p_name, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
- metadata.erase(p_name);
+ if (metadata.has(p_name)) {
+ metadata.erase(p_name);
+ metadata_properties.erase("metadata/" + p_name.operator String());
+ notify_property_list_changed();
+ }
return;
}
- metadata[p_name] = p_value;
+ OrderedHashMap<StringName, Variant>::Element E = metadata.find(p_name);
+ if (E) {
+ E.value() = p_value;
+ } else {
+ ERR_FAIL_COND(!p_name.operator String().is_valid_identifier());
+ E = metadata.insert(p_name, p_value);
+ metadata_properties["metadata/" + p_name.operator String()] = E;
+ notify_property_list_changed();
+ }
}
-Variant Object::get_meta(const StringName &p_name) const {
- ERR_FAIL_COND_V_MSG(!metadata.has(p_name), Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'.");
+Variant Object::get_meta(const StringName &p_name, const Variant &p_default) const {
+ if (!metadata.has(p_name)) {
+ if (p_default != Variant()) {
+ return p_default;
+ } else {
+ ERR_FAIL_V_MSG(Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'.");
+ }
+ }
return metadata[p_name];
}
void Object::remove_meta(const StringName &p_name) {
- metadata.erase(p_name);
+ set_meta(p_name, Variant());
}
Array Object::_get_property_list_bind() const {
@@ -967,20 +993,16 @@ Array Object::_get_method_list_bind() const {
Vector<StringName> Object::_get_meta_list_bind() const {
Vector<StringName> _metaret;
- List<Variant> keys;
- metadata.get_key_list(&keys);
- for (const Variant &E : keys) {
- _metaret.push_back(E);
+ for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
+ _metaret.push_back(K.key());
}
return _metaret;
}
void Object::get_meta_list(List<StringName> *p_list) const {
- List<Variant> keys;
- metadata.get_key_list(&keys);
- for (const Variant &E : keys) {
- p_list->push_back(E);
+ for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
+ p_list->push_back(K.key());
}
}
@@ -1005,15 +1027,15 @@ struct _ObjectSignalDisconnectData {
Callable callable;
};
-Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- ERR_FAIL_COND_V(p_argcount < 1, Variant());
+ ERR_FAIL_COND_V(p_argcount < 1, Error::ERR_INVALID_PARAMETER);
if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING_NAME;
- ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING, Variant());
+ ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING, Error::ERR_INVALID_PARAMETER);
}
r_error.error = Callable::CallError::CALL_OK;
@@ -1027,12 +1049,10 @@ Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::C
args = &p_args[1];
}
- emit_signal(signal, args, argc);
-
- return Variant();
+ return emit_signalp(signal, args, argc);
}
-Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount) {
+Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) {
if (_block_signals) {
return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked
}
@@ -1091,7 +1111,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
}
if (c.flags & CONNECT_DEFERRED) {
- MessageQueue::get_singleton()->push_callable(c.callable, args, argc, true);
+ MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true);
} else {
Callable::CallError ce;
_emitting = true;
@@ -1139,21 +1159,6 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
return err;
}
-Error Object::emit_signal(const StringName &p_name, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return emit_signal(p_name, argptr, argc);
-}
-
void Object::_add_user_signal(const String &p_name, const Array &p_args) {
// this version of add_user_signal is meant to be used from scripts or external apis
// without access to ADD_SIGNAL in bind_methods
@@ -1470,7 +1475,7 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu
void Object::_clear_internal_resource_paths(const Variant &p_var) {
switch (p_var.get_type()) {
case Variant::OBJECT: {
- RES r = p_var;
+ Ref<Resource> r = p_var;
if (!r.is_valid()) {
return;
}
@@ -1557,7 +1562,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
- ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta);
+ ClassDB::bind_method(D_METHOD("get_meta", "name", "default"), &Object::get_meta, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
@@ -1648,10 +1653,6 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
-void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) {
- MessageQueue::get_singleton()->push_call(this, p_method, VARIANT_ARG_PASS);
-}
-
void Object::set_deferred(const StringName &p_property, const Variant &p_value) {
MessageQueue::get_singleton()->push_set(this, p_property, p_value);
}
@@ -1846,6 +1847,13 @@ Object::Object() {
_construct_object(false);
}
+void Object::detach_from_objectdb() {
+ if (_instance_id != ObjectID()) {
+ ObjectDB::remove_instance(this);
+ _instance_id = ObjectID();
+ }
+}
+
Object::~Object() {
if (script_instance) {
memdelete(script_instance);
@@ -1885,8 +1893,10 @@ Object::~Object() {
c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true);
}
- ObjectDB::remove_instance(this);
- _instance_id = ObjectID();
+ if (_instance_id != ObjectID()) {
+ ObjectDB::remove_instance(this);
+ _instance_id = ObjectID();
+ }
_predelete_ok = 2;
if (_instance_bindings != nullptr) {
diff --git a/core/object/object.h b/core/object/object.h
index b5be1cf0e7..c3e3c68b59 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -32,26 +32,20 @@
#define OBJECT_H
#include "core/extension/gdnative_interface.h"
+#include "core/object/message_queue.h"
#include "core/object/object_id.h"
#include "core/os/rw_lock.h"
#include "core/os/spin_lock.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
+#include "core/templates/ordered_hash_map.h"
#include "core/templates/safe_refcount.h"
#include "core/templates/set.h"
#include "core/templates/vmap.h"
#include "core/variant/callable_bind.h"
#include "core/variant/variant.h"
-#define VARIANT_ARG_LIST const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant()
-#define VARIANT_ARG_PASS p_arg1, p_arg2, p_arg3, p_arg4, p_arg5, p_arg6, p_arg7, p_arg8
-#define VARIANT_ARG_DECLARE const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8
-#define VARIANT_ARG_MAX 8
-#define VARIANT_ARGPTRS const Variant *argptr[8] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5, &p_arg6, &p_arg7, &p_arg8 };
-#define VARIANT_ARGPTRS_PASS *argptr[0], *argptr[1], *argptr[2], *argptr[3], *argptr[4], *argptr[5], *argptr[6]], *argptr[7]
-#define VARIANT_ARGS_FROM_ARRAY(m_arr) m_arr[0], m_arr[1], m_arr[2], m_arr[3], m_arr[4], m_arr[5], m_arr[6], m_arr[7]
-
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range.
@@ -95,6 +89,7 @@ enum PropertyHint {
PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_INT_IS_POINTER,
PROPERTY_HINT_LOCALE_ID,
+ PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -262,6 +257,7 @@ struct ObjectNativeExtension {
GDNativeExtensionClassToString to_string;
GDNativeExtensionClassReference reference;
GDNativeExtensionClassReference unreference;
+ GDNativeExtensionClassGetRID get_rid;
_FORCE_INLINE_ bool is_class(const String &p_class) const {
const ObjectNativeExtension *e = this;
@@ -280,8 +276,12 @@ struct ObjectNativeExtension {
GDNativeExtensionClassGetVirtual get_virtual;
};
-#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__)
-#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call(__VA_ARGS__)
+#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
+#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<false>(__VA_ARGS__)
+
+#define GDVIRTUAL_REQUIRED_CALL(m_name, ...) _gdvirtual_##m_name##_call<true>(__VA_ARGS__)
+#define GDVIRTUAL_REQUIRED_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<true>(__VA_ARGS__)
+
#ifdef DEBUG_METHODS_ENABLED
#define GDVIRTUAL_BIND(m_name, ...) ::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), true, sarray(__VA_ARGS__));
#else
@@ -344,16 +344,6 @@ public:
m_inherits::get_inheritance_list_static(p_inheritance_list); \
p_inheritance_list->push_back(String(#m_class)); \
} \
- static String get_category_static() { \
- String category = m_inherits::get_category_static(); \
- if (_get_category != m_inherits::_get_category) { \
- if (!category.is_empty()) { \
- category += "/"; \
- } \
- category += _get_category(); \
- } \
- return category; \
- } \
virtual bool is_class(const String &p_class) const override { \
if (_get_extension() && _get_extension()->is_class(p_class)) { \
return true; \
@@ -454,12 +444,6 @@ protected:
\
private:
-#define OBJ_CATEGORY(m_category) \
-protected: \
- _FORCE_INLINE_ static String _get_category() { return m_category; } \
- \
-private:
-
#define OBJ_SAVE_TYPE(m_class) \
public: \
virtual String get_save_class() const override { return #m_class; } \
@@ -531,13 +515,14 @@ private:
#endif
ScriptInstance *script_instance = nullptr;
Variant script; // Reference does not exist yet, store it in a Variant.
- Dictionary metadata;
+ OrderedHashMap<StringName, Variant> metadata;
+ HashMap<StringName, OrderedHashMap<StringName, Variant>::Element> metadata_properties;
mutable StringName _class_name;
mutable const StringName *_class_ptr = nullptr;
void _add_user_signal(const String &p_name, const Array &p_args = Array());
bool _has_user_signal(const StringName &p_name) const;
- Variant _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ 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 String &p_signal) const;
Array _get_incoming_connections() const;
@@ -553,8 +538,8 @@ private:
std::mutex _instance_binding_mutex;
struct InstanceBinding {
- void *binding;
- void *token;
+ void *binding = nullptr;
+ void *token = nullptr;
GDNativeInstanceBindingFreeCallback free_callback = nullptr;
GDNativeInstanceBindingReferenceCallback reference_callback = nullptr;
};
@@ -589,7 +574,6 @@ protected:
virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const {};
virtual void _notificationv(int p_notification, bool p_reversed) {}
- static String _get_category() { return ""; }
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; };
@@ -649,6 +633,7 @@ public:
bool _is_gpl_reversed() const { return false; }
+ void detach_from_objectdb();
_FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
template <class T>
@@ -693,7 +678,6 @@ public:
static String get_class_static() { return "Object"; }
static String get_parent_class_static() { return String(); }
- static String get_category_static() { return String(); }
virtual String get_class() const {
if (_extension) {
@@ -734,8 +718,18 @@ public:
bool has_method(const StringName &p_method) const;
void get_method_list(List<MethodInfo> *p_list) const;
Variant callv(const StringName &p_method, const Array &p_args);
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
+ }
void notification(int p_notification, bool p_reversed = false);
virtual String to_string();
@@ -752,7 +746,7 @@ public:
bool has_meta(const StringName &p_name) const;
void set_meta(const StringName &p_name, const Variant &p_value);
void remove_meta(const StringName &p_name);
- Variant get_meta(const StringName &p_name) const;
+ Variant get_meta(const StringName &p_name, const Variant &p_default = Variant()) const;
void get_meta_list(List<StringName> *p_list) const;
#ifdef TOOLS_ENABLED
@@ -769,8 +763,18 @@ public:
void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance);
void add_user_signal(const MethodInfo &p_signal);
- Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST);
- Error emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ Error emit_signal(const StringName &p_name, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return emit_signalp(p_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount);
bool has_signal(const StringName &p_name) const;
void get_signal_list(List<MethodInfo> *p_signals) const;
void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
@@ -782,7 +786,11 @@ public:
void disconnect(const StringName &p_signal, const Callable &p_callable);
bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
- void call_deferred(const StringName &p_method, VARIANT_ARG_LIST);
+ template <typename... VarArgs>
+ void call_deferred(const StringName &p_name, VarArgs... p_args) {
+ MessageQueue::get_singleton()->push_call(this, p_name, p_args...);
+ }
+
void set_deferred(const StringName &p_property, const Variant &p_value);
void set_block_signals(bool p_block);
@@ -842,7 +850,7 @@ class ObjectDB {
uint64_t validator : OBJECTDB_VALIDATOR_BITS;
uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS;
uint64_t is_ref_counted : 1;
- Object *object;
+ Object *object = nullptr;
};
static SpinLock spin_lock;
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index c9a7b2a608..726e2c012c 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -108,7 +108,7 @@ Variant WeakRef::get_ref() const {
}
RefCounted *r = cast_to<RefCounted>(obj);
if (r) {
- return REF(r);
+ return Ref<RefCounted>(r);
}
return obj;
@@ -118,7 +118,7 @@ void WeakRef::set_obj(Object *p_object) {
ref = p_object ? p_object->get_instance_id() : ObjectID();
}
-void WeakRef::set_ref(const REF &p_ref) {
+void WeakRef::set_ref(const Ref<RefCounted> &p_ref) {
ref = p_ref.is_valid() ? p_ref->get_instance_id() : ObjectID();
}
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index 8eb1c97cce..bd06a84bd8 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -234,8 +234,6 @@ public:
}
};
-typedef Ref<RefCounted> REF;
-
class WeakRef : public RefCounted {
GDCLASS(WeakRef, RefCounted);
@@ -247,7 +245,7 @@ protected:
public:
Variant get_ref() const;
void set_obj(Object *p_object);
- void set_ref(const REF &p_ref);
+ void set_ref(const Ref<RefCounted> &p_ref);
WeakRef() {}
};
@@ -261,7 +259,7 @@ struct PtrToArg<Ref<T>> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) {
- *(Ref<RefCounted> *)p_ptr = p_val;
+ *(const_cast<Ref<RefCounted> *>(reinterpret_cast<const Ref<RefCounted> *>(p_ptr))) = p_val;
}
};
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index b14296b815..a5d25bf533 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -144,7 +144,7 @@ void ScriptServer::register_language(ScriptLanguage *p_language) {
_languages[_language_count++] = p_language;
}
-void ScriptServer::unregister_language(ScriptLanguage *p_language) {
+void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
for (int i = 0; i < _language_count; i++) {
if (_languages[i] == p_language) {
_language_count--;
@@ -310,20 +310,6 @@ void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state)
}
}
-Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
- return call(p_method, argptr, argc, error);
-}
-
void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) {
if (r_valid) {
*r_valid = false;
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 4b18d9a5e8..f58ef45743 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -68,7 +68,7 @@ public:
_FORCE_INLINE_ static int get_language_count() { return _language_count; }
static ScriptLanguage *get_language(int p_idx);
static void register_language(ScriptLanguage *p_language);
- static void unregister_language(ScriptLanguage *p_language);
+ static void unregister_language(const ScriptLanguage *p_language);
static void set_reload_scripts_on_save(bool p_enable);
static bool is_reload_scripts_on_save_enabled();
@@ -132,7 +132,7 @@ public:
virtual Error reload(bool p_keep_state = false) = 0;
#ifdef TOOLS_ENABLED
- virtual const Vector<DocData::ClassDoc> &get_documentation() const = 0;
+ virtual Vector<DocData::ClassDoc> get_documentation() const = 0;
#endif // TOOLS_ENABLED
virtual bool has_method(const StringName &p_method) const = 0;
@@ -176,8 +176,20 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const = 0;
virtual bool has_method(const StringName &p_method) const = 0;
- virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST);
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
+ }
+
virtual void notification(int p_notification) = 0;
virtual String to_string(bool *r_valid) {
if (r_valid) {
@@ -200,44 +212,12 @@ public:
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid);
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid);
- virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const = 0;
+ virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const { return get_script()->get_rpc_methods(); }
virtual ScriptLanguage *get_language() = 0;
virtual ~ScriptInstance();
};
-struct ScriptCodeCompletionOption {
- /* Keep enum in Sync with: */
- /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */
- enum Kind {
- KIND_CLASS,
- KIND_FUNCTION,
- KIND_SIGNAL,
- KIND_VARIABLE,
- KIND_MEMBER,
- KIND_ENUM,
- KIND_CONSTANT,
- KIND_NODE_PATH,
- KIND_FILE_PATH,
- KIND_PLAIN_TEXT,
- };
- Kind kind = KIND_PLAIN_TEXT;
- String display;
- String insert_text;
- Color font_color;
- RES icon;
- Variant default_value;
- Vector<Pair<int, int>> matches;
-
- ScriptCodeCompletionOption() {}
-
- ScriptCodeCompletionOption(const String &p_text, Kind p_kind) {
- display = p_text;
- insert_text = p_text;
- kind = p_kind;
- }
-};
-
class ScriptCodeCompletionCache {
static ScriptCodeCompletionCache *singleton;
@@ -249,7 +229,8 @@ public:
virtual ~ScriptCodeCompletionCache() {}
};
-class ScriptLanguage {
+class ScriptLanguage : public Object {
+ GDCLASS(ScriptLanguage, Object)
public:
virtual String get_name() const = 0;
@@ -314,19 +295,64 @@ public:
virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; }
virtual bool overrides_external_editor() { return false; }
- virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
+ /* Keep enum in Sync with: */
+ /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */
+ enum CodeCompletionKind {
+ CODE_COMPLETION_KIND_CLASS,
+ CODE_COMPLETION_KIND_FUNCTION,
+ CODE_COMPLETION_KIND_SIGNAL,
+ CODE_COMPLETION_KIND_VARIABLE,
+ CODE_COMPLETION_KIND_MEMBER,
+ CODE_COMPLETION_KIND_ENUM,
+ CODE_COMPLETION_KIND_CONSTANT,
+ CODE_COMPLETION_KIND_NODE_PATH,
+ CODE_COMPLETION_KIND_FILE_PATH,
+ CODE_COMPLETION_KIND_PLAIN_TEXT,
+ CODE_COMPLETION_KIND_MAX
+ };
+
+ enum CodeCompletionLocation {
+ LOCATION_LOCAL = 0,
+ LOCATION_PARENT_MASK = 1 << 8,
+ LOCATION_OTHER_USER_CODE = 1 << 9,
+ LOCATION_OTHER = 1 << 10,
+ };
+
+ struct CodeCompletionOption {
+ CodeCompletionKind kind = CODE_COMPLETION_KIND_PLAIN_TEXT;
+ String display;
+ String insert_text;
+ Color font_color;
+ Ref<Resource> icon;
+ Variant default_value;
+ Vector<Pair<int, int>> matches;
+ int location = LOCATION_OTHER;
+
+ CodeCompletionOption() {}
+
+ CodeCompletionOption(const String &p_text, CodeCompletionKind p_kind, int p_location = LOCATION_OTHER) {
+ display = p_text;
+ insert_text = p_text;
+ kind = p_kind;
+ location = p_location;
+ }
+ };
+
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
+
+ enum LookupResultType {
+ LOOKUP_RESULT_SCRIPT_LOCATION,
+ LOOKUP_RESULT_CLASS,
+ LOOKUP_RESULT_CLASS_CONSTANT,
+ LOOKUP_RESULT_CLASS_PROPERTY,
+ LOOKUP_RESULT_CLASS_METHOD,
+ LOOKUP_RESULT_CLASS_ENUM,
+ LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE,
+ LOOKUP_RESULT_MAX
+ };
struct LookupResult {
- enum Type {
- RESULT_SCRIPT_LOCATION,
- RESULT_CLASS,
- RESULT_CLASS_CONSTANT,
- RESULT_CLASS_PROPERTY,
- RESULT_CLASS_METHOD,
- RESULT_CLASS_ENUM,
- RESULT_CLASS_TBD_GLOBALSCOPE
- };
- Type type;
+ LookupResultType type;
Ref<Script> script;
String class_name;
String class_member;
@@ -404,42 +430,42 @@ public:
extern uint8_t script_encryption_key[32];
class PlaceHolderScriptInstance : public ScriptInstance {
- Object *owner;
+ Object *owner = nullptr;
List<PropertyInfo> properties;
Map<StringName, Variant> values;
Map<StringName, Variant> constants;
- ScriptLanguage *language;
+ ScriptLanguage *language = nullptr;
Ref<Script> script;
public:
- virtual bool set(const StringName &p_name, const Variant &p_value);
- virtual bool get(const StringName &p_name, Variant &r_ret) const;
- virtual void get_property_list(List<PropertyInfo> *p_properties) const;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
-
- virtual void get_method_list(List<MethodInfo> *p_list) const;
- virtual bool has_method(const StringName &p_method) const;
- virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); }
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ virtual bool set(const StringName &p_name, const Variant &p_value) override;
+ virtual bool get(const StringName &p_name, Variant &r_ret) const override;
+ 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 void get_method_list(List<MethodInfo> *p_list) const override;
+ virtual bool has_method(const StringName &p_method) const override;
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
- virtual void notification(int p_notification) {}
+ virtual void notification(int p_notification) override {}
- virtual Ref<Script> get_script() const { return script; }
+ virtual Ref<Script> get_script() const override { return script; }
- virtual ScriptLanguage *get_language() { return language; }
+ virtual ScriptLanguage *get_language() override { return language; }
- Object *get_owner() { return owner; }
+ Object *get_owner() override { return owner; }
void update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values); //likely changed in editor
- virtual bool is_placeholder() const { return true; }
+ virtual bool is_placeholder() const override { return true; }
- virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr);
- virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr);
+ virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr) override;
+ virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr) override;
- virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const { return Vector<Multiplayer::RPCConfig>(); }
+ virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override { return Vector<Multiplayer::RPCConfig>(); }
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
~PlaceHolderScriptInstance();
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
new file mode 100644
index 0000000000..21d7685674
--- /dev/null
+++ b/core/object/script_language_extension.cpp
@@ -0,0 +1,180 @@
+/*************************************************************************/
+/* script_language_extension.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 "script_language_extension.h"
+
+void ScriptExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_editor_can_reload_from_file);
+ GDVIRTUAL_BIND(_placeholder_erased, "placeholder");
+
+ GDVIRTUAL_BIND(_can_instantiate);
+ GDVIRTUAL_BIND(_get_base_script);
+ GDVIRTUAL_BIND(_inherits_script, "script");
+
+ GDVIRTUAL_BIND(_get_instance_base_type);
+ GDVIRTUAL_BIND(_instance_create, "for_object");
+ GDVIRTUAL_BIND(_placeholder_instance_create, "for_object");
+
+ GDVIRTUAL_BIND(_instance_has, "object");
+
+ GDVIRTUAL_BIND(_has_source_code);
+ GDVIRTUAL_BIND(_get_source_code);
+
+ GDVIRTUAL_BIND(_set_source_code, "code");
+ GDVIRTUAL_BIND(_reload, "keep_state");
+
+ GDVIRTUAL_BIND(_get_documentation);
+
+ GDVIRTUAL_BIND(_has_method, "method");
+ GDVIRTUAL_BIND(_get_method_info, "method");
+
+ GDVIRTUAL_BIND(_is_tool);
+ GDVIRTUAL_BIND(_is_valid);
+ GDVIRTUAL_BIND(_get_language);
+
+ GDVIRTUAL_BIND(_has_script_signal, "signal");
+ GDVIRTUAL_BIND(_get_script_signal_list);
+
+ GDVIRTUAL_BIND(_get_property_default_value, "property");
+
+ GDVIRTUAL_BIND(_update_exports);
+ GDVIRTUAL_BIND(_get_script_method_list);
+ GDVIRTUAL_BIND(_get_script_property_list);
+
+ GDVIRTUAL_BIND(_get_member_line, "member");
+
+ GDVIRTUAL_BIND(_get_constants);
+ GDVIRTUAL_BIND(_get_members);
+ GDVIRTUAL_BIND(_is_placeholder_fallback_enabled);
+
+ GDVIRTUAL_BIND(_get_rpc_methods);
+}
+
+void ScriptLanguageExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_name);
+ GDVIRTUAL_BIND(_init);
+ GDVIRTUAL_BIND(_get_type);
+ GDVIRTUAL_BIND(_get_extension);
+ GDVIRTUAL_BIND(_execute_file, "path");
+ GDVIRTUAL_BIND(_finish);
+
+ GDVIRTUAL_BIND(_get_reserved_words);
+ GDVIRTUAL_BIND(_is_control_flow_keyword, "keyword");
+ GDVIRTUAL_BIND(_get_comment_delimiters);
+ GDVIRTUAL_BIND(_get_string_delimiters);
+ GDVIRTUAL_BIND(_make_template, "template", "class_name", "base_class_name");
+ GDVIRTUAL_BIND(_get_built_in_templates, "object");
+ GDVIRTUAL_BIND(_is_using_templates);
+ GDVIRTUAL_BIND(_validate, "script", "path", "validate_functions", "validate_errors", "validate_warnings", "validate_safe_lines");
+
+ GDVIRTUAL_BIND(_validate_path, "path");
+ GDVIRTUAL_BIND(_create_script);
+ GDVIRTUAL_BIND(_has_named_classes);
+ GDVIRTUAL_BIND(_supports_builtin_mode);
+ GDVIRTUAL_BIND(_supports_documentation);
+ GDVIRTUAL_BIND(_can_inherit_from_file);
+ GDVIRTUAL_BIND(_find_function, "class_name", "function_name");
+ GDVIRTUAL_BIND(_make_function, "class_name", "function_name", "function_args");
+ GDVIRTUAL_BIND(_open_in_external_editor, "script", "line", "column");
+ GDVIRTUAL_BIND(_overrides_external_editor);
+
+ GDVIRTUAL_BIND(_complete_code, "code", "path", "owner");
+ GDVIRTUAL_BIND(_lookup_code, "code", "symbol", "path", "owner");
+ GDVIRTUAL_BIND(_auto_indent_code, "code", "from_line", "to_line");
+
+ GDVIRTUAL_BIND(_add_global_constant, "name", "value");
+ GDVIRTUAL_BIND(_add_named_global_constant, "name", "value");
+ GDVIRTUAL_BIND(_remove_named_global_constant, "name");
+
+ GDVIRTUAL_BIND(_thread_enter);
+ GDVIRTUAL_BIND(_thread_exit);
+ GDVIRTUAL_BIND(_debug_get_error);
+ GDVIRTUAL_BIND(_debug_get_stack_level_count);
+
+ GDVIRTUAL_BIND(_debug_get_stack_level_line, "level");
+ GDVIRTUAL_BIND(_debug_get_stack_level_function, "level");
+ GDVIRTUAL_BIND(_debug_get_stack_level_locals, "level", "max_subitems", "max_depth");
+ GDVIRTUAL_BIND(_debug_get_stack_level_members, "level", "max_subitems", "max_depth");
+ GDVIRTUAL_BIND(_debug_get_stack_level_instance, "level");
+ GDVIRTUAL_BIND(_debug_get_globals, "max_subitems", "max_depth");
+ GDVIRTUAL_BIND(_debug_parse_stack_level_expression, "level", "expression", "max_subitems", "max_depth");
+
+ GDVIRTUAL_BIND(_debug_get_current_stack_info);
+
+ GDVIRTUAL_BIND(_reload_all_scripts);
+ GDVIRTUAL_BIND(_reload_tool_script, "script", "soft_reload");
+
+ GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_get_public_functions);
+ GDVIRTUAL_BIND(_get_public_constants);
+
+ GDVIRTUAL_BIND(_profiling_start);
+ GDVIRTUAL_BIND(_profiling_stop);
+
+ GDVIRTUAL_BIND(_profiling_get_accumulated_data, "info_array", "info_max");
+ GDVIRTUAL_BIND(_profiling_get_frame_data, "info_array", "info_max");
+
+ GDVIRTUAL_BIND(_alloc_instance_binding_data, "object");
+ GDVIRTUAL_BIND(_free_instance_binding_data, "data");
+
+ GDVIRTUAL_BIND(_refcount_incremented_instance_binding, "object");
+ GDVIRTUAL_BIND(_refcount_decremented_instance_binding, "object");
+
+ GDVIRTUAL_BIND(_frame);
+
+ GDVIRTUAL_BIND(_handles_global_class_type, "type");
+ GDVIRTUAL_BIND(_get_global_class_name, "path");
+
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_SCRIPT_LOCATION);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_CONSTANT);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_PROPERTY);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_METHOD);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_ENUM);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_MAX);
+
+ BIND_ENUM_CONSTANT(LOCATION_LOCAL);
+ BIND_ENUM_CONSTANT(LOCATION_PARENT_MASK);
+ BIND_ENUM_CONSTANT(LOCATION_OTHER_USER_CODE);
+ BIND_ENUM_CONSTANT(LOCATION_OTHER);
+
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_CLASS);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_FUNCTION);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_SIGNAL);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_VARIABLE);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_MEMBER);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_ENUM);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_CONSTANT);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_NODE_PATH);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_FILE_PATH);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_PLAIN_TEXT);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_MAX);
+}
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
new file mode 100644
index 0000000000..40f18ab30d
--- /dev/null
+++ b/core/object/script_language_extension.h
@@ -0,0 +1,835 @@
+/*************************************************************************/
+/* script_language_extension.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 SCRIPT_LANGUAGE_EXTENSION_H
+#define SCRIPT_LANGUAGE_EXTENSION_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"
+#include "core/variant/typed_array.h"
+
+class ScriptExtension : public Script {
+ GDCLASS(ScriptExtension, Script)
+
+protected:
+ EXBIND0R(bool, editor_can_reload_from_file)
+
+ GDVIRTUAL1(_placeholder_erased, GDNativePtr<void>)
+ virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override {
+ GDVIRTUAL_CALL(_placeholder_erased, p_placeholder);
+ }
+
+ static void _bind_methods();
+
+public:
+ EXBIND0RC(bool, can_instantiate)
+ EXBIND0RC(Ref<Script>, get_base_script)
+ EXBIND1RC(bool, inherits_script, const Ref<Script> &)
+ EXBIND0RC(StringName, get_instance_base_type)
+
+ GDVIRTUAL1RC(GDNativePtr<void>, _instance_create, Object *)
+ virtual ScriptInstance *instance_create(Object *p_this) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_instance_create, p_this, ret);
+ return reinterpret_cast<ScriptInstance *>(ret.operator void *());
+ }
+ GDVIRTUAL1RC(GDNativePtr<void>, _placeholder_instance_create, Object *)
+ PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_placeholder_instance_create, p_this, ret);
+ return reinterpret_cast<PlaceHolderScriptInstance *>(ret.operator void *());
+ }
+
+ EXBIND1RC(bool, instance_has, const Object *)
+ EXBIND0RC(bool, has_source_code)
+ EXBIND0RC(String, get_source_code)
+ EXBIND1(set_source_code, const String &)
+ EXBIND1R(Error, reload, bool)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_documentation)
+#ifdef TOOLS_ENABLED
+ virtual Vector<DocData::ClassDoc> get_documentation() const override {
+ TypedArray<Dictionary> doc;
+ GDVIRTUAL_REQUIRED_CALL(_get_documentation, doc);
+
+ Vector<DocData::ClassDoc> class_doc;
+#ifndef _MSC_VER
+#warning missing conversion from documentation to ClassDoc
+#endif
+ return class_doc;
+ }
+#endif // TOOLS_ENABLED
+
+ EXBIND1RC(bool, has_method, const StringName &)
+
+ GDVIRTUAL1RC(Dictionary, _get_method_info, const StringName &)
+ virtual MethodInfo get_method_info(const StringName &p_method) const override {
+ Dictionary mi;
+ GDVIRTUAL_REQUIRED_CALL(_get_method_info, p_method, mi);
+ return MethodInfo::from_dict(mi);
+ }
+
+ EXBIND0RC(bool, is_tool)
+ EXBIND0RC(bool, is_valid)
+
+ EXBIND0RC(ScriptLanguage *, get_language)
+ EXBIND1RC(bool, has_script_signal, const StringName &)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_script_signal_list)
+
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const override {
+ TypedArray<Dictionary> sl;
+ GDVIRTUAL_REQUIRED_CALL(_get_script_signal_list, sl);
+ for (int i = 0; i < sl.size(); i++) {
+ r_signals->push_back(MethodInfo::from_dict(sl[i]));
+ }
+ }
+
+ GDVIRTUAL1RC(bool, _has_property_default_value, const StringName &)
+ GDVIRTUAL1RC(Variant, _get_property_default_value, const StringName &)
+
+ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const override {
+ bool has_dv = false;
+ if (!GDVIRTUAL_REQUIRED_CALL(_has_property_default_value, p_property, has_dv) || !has_dv) {
+ return false;
+ }
+ Variant ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_property_default_value, p_property, ret);
+ return ret;
+ }
+
+ EXBIND0(update_exports)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_script_method_list)
+
+ virtual void get_script_method_list(List<MethodInfo> *r_methods) const override {
+ TypedArray<Dictionary> sl;
+ GDVIRTUAL_REQUIRED_CALL(_get_script_method_list, sl);
+ for (int i = 0; i < sl.size(); i++) {
+ r_methods->push_back(MethodInfo::from_dict(sl[i]));
+ }
+ }
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_script_property_list)
+
+ virtual void get_script_property_list(List<PropertyInfo> *r_propertys) const override {
+ TypedArray<Dictionary> sl;
+ GDVIRTUAL_REQUIRED_CALL(_get_script_property_list, sl);
+ for (int i = 0; i < sl.size(); i++) {
+ r_propertys->push_back(PropertyInfo::from_dict(sl[i]));
+ }
+ }
+
+ EXBIND1RC(int, get_member_line, const StringName &)
+
+ GDVIRTUAL0RC(Dictionary, _get_constants)
+
+ virtual void get_constants(Map<StringName, Variant> *p_constants) override {
+ Dictionary constants;
+ GDVIRTUAL_REQUIRED_CALL(_get_constants, constants);
+ List<Variant> keys;
+ constants.get_key_list(&keys);
+ for (const Variant &K : keys) {
+ p_constants->insert(K, constants[K]);
+ }
+ }
+ GDVIRTUAL0RC(TypedArray<StringName>, _get_members)
+ virtual void get_members(Set<StringName> *p_members) override {
+ TypedArray<StringName> members;
+ GDVIRTUAL_REQUIRED_CALL(_get_members, members);
+ for (int i = 0; i < members.size(); i++) {
+ p_members->insert(members[i]);
+ }
+ }
+
+ EXBIND0RC(bool, is_placeholder_fallback_enabled)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_rpc_methods)
+
+ virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override {
+ TypedArray<Dictionary> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_rpc_methods, ret);
+ Vector<Multiplayer::RPCConfig> rpcret;
+ for (int i = 0; i < ret.size(); i++) {
+ Dictionary d = ret[i];
+ Multiplayer::RPCConfig rpc;
+ ERR_CONTINUE(!d.has("name"));
+ rpc.name = d["name"];
+ ERR_CONTINUE(!d.has("rpc_mode"));
+ rpc.rpc_mode = Multiplayer::RPCMode(int(d["rpc_mode"]));
+ ERR_CONTINUE(!d.has("call_local"));
+ rpc.call_local = d["call_local"];
+ ERR_CONTINUE(!d.has("transfer_mode"));
+ rpc.transfer_mode = Multiplayer::TransferMode(int(d["transfer_mode"]));
+ ERR_CONTINUE(!d.has("channel"));
+ rpc.channel = d["channel"];
+ rpcret.push_back(rpc);
+ }
+ return rpcret;
+ }
+
+ ScriptExtension() {}
+};
+
+typedef ScriptLanguage::ProfilingInfo ScriptLanguageExtensionProfilingInfo;
+
+GDVIRTUAL_NATIVE_PTR(ScriptLanguageExtensionProfilingInfo)
+
+class ScriptLanguageExtension : public ScriptLanguage {
+ GDCLASS(ScriptLanguageExtension, ScriptLanguage)
+protected:
+ static void _bind_methods();
+
+public:
+ EXBIND0RC(String, get_name)
+
+ EXBIND0(init)
+ EXBIND0RC(String, get_type)
+ EXBIND0RC(String, get_extension)
+ EXBIND1R(Error, execute_file, const String &)
+ EXBIND0(finish)
+
+ /* EDITOR FUNCTIONS */
+
+ GDVIRTUAL0RC(Vector<String>, _get_reserved_words)
+
+ virtual void get_reserved_words(List<String> *p_words) const override {
+ Vector<String> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_reserved_words, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_words->push_back(ret[i]);
+ }
+ }
+ EXBIND1RC(bool, is_control_flow_keyword, String)
+
+ GDVIRTUAL0RC(Vector<String>, _get_comment_delimiters)
+
+ virtual void get_comment_delimiters(List<String> *p_words) const override {
+ Vector<String> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_comment_delimiters, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_words->push_back(ret[i]);
+ }
+ }
+
+ GDVIRTUAL0RC(Vector<String>, _get_string_delimiters)
+
+ virtual void get_string_delimiters(List<String> *p_words) const override {
+ Vector<String> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_string_delimiters, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_words->push_back(ret[i]);
+ }
+ }
+
+ EXBIND3RC(Ref<Script>, make_template, const String &, const String &, const String &)
+
+ GDVIRTUAL1RC(TypedArray<Dictionary>, _get_built_in_templates, StringName)
+
+ virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override {
+ TypedArray<Dictionary> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_built_in_templates, p_object, ret);
+ Vector<ScriptTemplate> stret;
+ for (int i = 0; i < ret.size(); i++) {
+ Dictionary d = ret[i];
+ ScriptTemplate st;
+ ERR_CONTINUE(!d.has("inherit"));
+ st.inherit = d["inherit"];
+ ERR_CONTINUE(!d.has("name"));
+ st.name = d["name"];
+ ERR_CONTINUE(!d.has("description"));
+ st.description = d["description"];
+ ERR_CONTINUE(!d.has("content"));
+ st.content = d["content"];
+ ERR_CONTINUE(!d.has("id"));
+ st.id = d["id"];
+ ERR_CONTINUE(!d.has("origin"));
+ st.origin = TemplateLocation(int(d["origin"]));
+ stret.push_back(st);
+ }
+ return stret;
+ }
+
+ EXBIND0R(bool, is_using_templates)
+
+ GDVIRTUAL6RC(Dictionary, _validate, const String &, const String &, bool, bool, bool, bool)
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_validate, p_script, p_path, r_functions != nullptr, r_errors != nullptr, r_warnings != nullptr, r_safe_lines != nullptr, ret);
+ if (!ret.has("valid")) {
+ return false;
+ }
+ if (r_functions != nullptr && ret.has("functions")) {
+ Vector<String> functions = ret["functions"];
+ for (int i = 0; i < functions.size(); i++) {
+ r_functions->push_back(functions[i]);
+ }
+ }
+ if (r_errors != nullptr && ret.has("errors")) {
+ Array errors = ret["errors"];
+ for (int i = 0; i < errors.size(); i++) {
+ Dictionary err = errors[i];
+ ERR_CONTINUE(!err.has("line"));
+ ERR_CONTINUE(!err.has("column"));
+ ERR_CONTINUE(!err.has("message"));
+
+ ScriptError serr;
+ serr.line = err["line"];
+ serr.column = err["column"];
+ serr.message = err["message"];
+
+ r_errors->push_back(serr);
+ }
+ }
+ if (r_warnings != nullptr && ret.has("warnings")) {
+ ERR_FAIL_COND_V(!ret.has("warnings"), false);
+ Array warnings = ret["warnings"];
+ for (int i = 0; i < warnings.size(); i++) {
+ Dictionary warn = warnings[i];
+ ERR_CONTINUE(!warn.has("start_line"));
+ ERR_CONTINUE(!warn.has("end_line"));
+ ERR_CONTINUE(!warn.has("leftmost_column"));
+ ERR_CONTINUE(!warn.has("rightmost_column"));
+ ERR_CONTINUE(!warn.has("code"));
+ ERR_CONTINUE(!warn.has("string_code"));
+ ERR_CONTINUE(!warn.has("message"));
+
+ Warning swarn;
+ swarn.start_line = warn["start_line"];
+ swarn.end_line = warn["end_line"];
+ swarn.leftmost_column = warn["leftmost_column"];
+ swarn.rightmost_column = warn["rightmost_column"];
+ swarn.code = warn["code"];
+ swarn.string_code = warn["string_code"];
+ swarn.message = warn["message"];
+
+ r_warnings->push_back(swarn);
+ }
+ }
+ if (r_safe_lines != nullptr && ret.has("safe_lines")) {
+ PackedInt32Array safe_lines = ret["safe_lines"];
+ for (int i = 0; i < safe_lines.size(); i++) {
+ r_safe_lines->insert(safe_lines[i]);
+ }
+ }
+ return ret["valid"];
+ }
+
+ EXBIND1RC(String, validate_path, const String &)
+ GDVIRTUAL0RC(Object *, _create_script)
+ Script *create_script() const override {
+ Object *ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_create_script, ret);
+ return Object::cast_to<Script>(ret);
+ }
+ EXBIND0RC(bool, has_named_classes)
+ EXBIND0RC(bool, supports_builtin_mode)
+ EXBIND0RC(bool, supports_documentation)
+ EXBIND0RC(bool, can_inherit_from_file)
+
+ EXBIND2RC(int, find_function, const String &, const String &)
+ EXBIND3RC(String, make_function, const String &, const String &, const PackedStringArray &)
+ EXBIND3R(Error, open_in_external_editor, const Ref<Script> &, int, int)
+ EXBIND0R(bool, overrides_external_editor)
+
+ GDVIRTUAL3RC(Dictionary, _complete_code, const String &, const String &, Object *)
+
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_complete_code, p_code, p_path, p_owner, ret);
+ if (!ret.has("result")) {
+ return ERR_UNAVAILABLE;
+ }
+
+ if (r_options != nullptr && ret.has("options")) {
+ Array options = ret["options"];
+ for (int i = 0; i < options.size(); i++) {
+ Dictionary op = options[i];
+ CodeCompletionOption option;
+ ERR_CONTINUE(!op.has("kind"));
+ option.kind = CodeCompletionKind(int(op["kind"]));
+ ERR_CONTINUE(!op.has("display"));
+ option.display = op["display"];
+ ERR_CONTINUE(!op.has("insert_text"));
+ option.insert_text = op["insert_text"];
+ ERR_CONTINUE(!op.has("font_color"));
+ option.font_color = op["font_color"];
+ ERR_CONTINUE(!op.has("icon"));
+ option.icon = op["icon"];
+ ERR_CONTINUE(!op.has("default_value"));
+ option.default_value = op["default_value"];
+ ERR_CONTINUE(!op.has("location"));
+ option.location = op["location"];
+ if (op.has("matches")) {
+ PackedInt32Array matches = op["matches"];
+ ERR_CONTINUE(matches.size() & 1);
+ for (int j = 0; j < matches.size(); j += 2) {
+ option.matches.push_back(Pair<int, int>(matches[j], matches[j + 1]));
+ }
+ }
+ r_options->push_back(option);
+ }
+ }
+
+ ERR_FAIL_COND_V(!ret.has("force"), ERR_UNAVAILABLE);
+ r_force = ret["force"];
+ ERR_FAIL_COND_V(!ret.has("call_hint"), ERR_UNAVAILABLE);
+ r_call_hint = ret["call_hint"];
+ ERR_FAIL_COND_V(!ret.has("result"), ERR_UNAVAILABLE);
+ Error result = Error(int(ret["result"]));
+
+ return result;
+ }
+
+ GDVIRTUAL4RC(Dictionary, _lookup_code, const String &, const String &, const String &, Object *)
+
+ virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_lookup_code, p_code, p_symbol, p_path, p_owner, ret);
+ if (!ret.has("result")) {
+ return ERR_UNAVAILABLE;
+ }
+
+ ERR_FAIL_COND_V(!ret.has("type"), ERR_UNAVAILABLE);
+ r_result.type = LookupResultType(int(ret["type"]));
+ ERR_FAIL_COND_V(!ret.has("script"), ERR_UNAVAILABLE);
+ r_result.script = ret["script"];
+ ERR_FAIL_COND_V(!ret.has("class_name"), ERR_UNAVAILABLE);
+ r_result.class_name = ret["class_name"];
+ ERR_FAIL_COND_V(!ret.has("class_path"), ERR_UNAVAILABLE);
+ r_result.class_path = ret["class_path"];
+ ERR_FAIL_COND_V(!ret.has("location"), ERR_UNAVAILABLE);
+ r_result.location = ret["location"];
+
+ Error result = Error(int(ret["result"]));
+
+ return result;
+ }
+
+ GDVIRTUAL3RC(String, _auto_indent_code, const String &, int, int)
+ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override {
+ String ret;
+ GDVIRTUAL_REQUIRED_CALL(_auto_indent_code, p_code, p_from_line, p_to_line, ret);
+ p_code = ret;
+ }
+ EXBIND2(add_global_constant, const StringName &, const Variant &)
+ EXBIND2(add_named_global_constant, const StringName &, const Variant &)
+ EXBIND1(remove_named_global_constant, const StringName &)
+
+ /* MULTITHREAD FUNCTIONS */
+
+ //some VMs need to be notified of thread creation/exiting to allocate a stack
+ EXBIND0(thread_enter)
+ EXBIND0(thread_exit)
+
+ EXBIND0RC(String, debug_get_error)
+ EXBIND0RC(int, debug_get_stack_level_count)
+ EXBIND1RC(int, debug_get_stack_level_line, int)
+ EXBIND1RC(String, debug_get_stack_level_function, int)
+ EXBIND1RC(String, debug_get_stack_level_source, int)
+
+ GDVIRTUAL3R(Dictionary, _debug_get_stack_level_locals, int, int, int)
+ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_stack_level_locals, p_level, p_max_subitems, p_max_depth, ret);
+ if (ret.size() == 0) {
+ return;
+ }
+ if (p_locals != nullptr && ret.has("locals")) {
+ PackedStringArray strings = ret["locals"];
+ for (int i = 0; i < strings.size(); i++) {
+ p_locals->push_back(strings[i]);
+ }
+ }
+ if (p_values != nullptr && ret.has("values")) {
+ Array values = ret["values"];
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+ }
+ GDVIRTUAL3R(Dictionary, _debug_get_stack_level_members, int, int, int)
+ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_stack_level_members, p_level, p_max_subitems, p_max_depth, ret);
+ if (ret.size() == 0) {
+ return;
+ }
+ if (p_members != nullptr && ret.has("members")) {
+ PackedStringArray strings = ret["members"];
+ for (int i = 0; i < strings.size(); i++) {
+ p_members->push_back(strings[i]);
+ }
+ }
+ if (p_values != nullptr && ret.has("values")) {
+ Array values = ret["values"];
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+ }
+ GDVIRTUAL1R(GDNativePtr<void>, _debug_get_stack_level_instance, int)
+
+ virtual ScriptInstance *debug_get_stack_level_instance(int p_level) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_stack_level_instance, p_level, ret);
+ return reinterpret_cast<ScriptInstance *>(ret.operator void *());
+ }
+ GDVIRTUAL2R(Dictionary, _debug_get_globals, int, int)
+ virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_globals, p_max_subitems, p_max_depth, ret);
+ if (ret.size() == 0) {
+ return;
+ }
+ if (p_globals != nullptr && ret.has("globals")) {
+ PackedStringArray strings = ret["globals"];
+ for (int i = 0; i < strings.size(); i++) {
+ p_globals->push_back(strings[i]);
+ }
+ }
+ if (p_values != nullptr && ret.has("values")) {
+ Array values = ret["values"];
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+ }
+
+ EXBIND4R(String, debug_parse_stack_level_expression, int, const String &, int, int)
+
+ GDVIRTUAL0R(TypedArray<Dictionary>, _debug_get_current_stack_info)
+ virtual Vector<StackInfo> debug_get_current_stack_info() override {
+ TypedArray<Dictionary> ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_current_stack_info, ret);
+ Vector<StackInfo> sret;
+ for (int i = 0; i < ret.size(); i++) {
+ StackInfo si;
+ Dictionary d = ret[i];
+ ERR_CONTINUE(!d.has("file"));
+ ERR_CONTINUE(!d.has("func"));
+ ERR_CONTINUE(!d.has("line"));
+ si.file = d["file"];
+ si.func = d["func"];
+ si.line = d["line"];
+ sret.push_back(si);
+ }
+ return sret;
+ }
+
+ EXBIND0(reload_all_scripts)
+ EXBIND2(reload_tool_script, const Ref<Script> &, bool)
+ /* LOADER FUNCTIONS */
+
+ GDVIRTUAL0RC(PackedStringArray, _get_recognized_extensions)
+
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override {
+ PackedStringArray ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_recognized_extensions, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_extensions->push_back(ret[i]);
+ }
+ }
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_public_functions)
+ virtual void get_public_functions(List<MethodInfo> *p_functions) const override {
+ TypedArray<Dictionary> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_public_functions, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ MethodInfo mi = MethodInfo::from_dict(ret[i]);
+ p_functions->push_back(mi);
+ }
+ }
+ GDVIRTUAL0RC(Dictionary, _get_public_constants)
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_public_constants, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ Dictionary d = ret[i];
+ ERR_CONTINUE(!d.has("name"));
+ ERR_CONTINUE(!d.has("value"));
+ p_constants->push_back(Pair<String, Variant>(d["name"], d["value"]));
+ }
+ }
+
+ EXBIND0(profiling_start)
+ EXBIND0(profiling_stop)
+
+ GDVIRTUAL2R(int, _profiling_get_accumulated_data, GDNativePtr<ScriptLanguageExtensionProfilingInfo>, int)
+
+ virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override {
+ int ret = 0;
+ GDVIRTUAL_REQUIRED_CALL(_profiling_get_accumulated_data, p_info_arr, p_info_max, ret);
+ return ret;
+ }
+
+ GDVIRTUAL2R(int, _profiling_get_frame_data, GDNativePtr<ScriptLanguageExtensionProfilingInfo>, int)
+
+ virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override {
+ int ret = 0;
+ GDVIRTUAL_REQUIRED_CALL(_profiling_get_accumulated_data, p_info_arr, p_info_max, ret);
+ return ret;
+ }
+
+ GDVIRTUAL1R(GDNativePtr<void>, _alloc_instance_binding_data, Object *)
+
+ virtual void *alloc_instance_binding_data(Object *p_object) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_alloc_instance_binding_data, p_object, ret);
+ return ret.operator void *();
+ }
+
+ GDVIRTUAL1(_free_instance_binding_data, GDNativePtr<void>)
+
+ virtual void free_instance_binding_data(void *p_data) override {
+ GDVIRTUAL_REQUIRED_CALL(_free_instance_binding_data, p_data);
+ }
+
+ EXBIND1(refcount_incremented_instance_binding, Object *)
+ EXBIND1R(bool, refcount_decremented_instance_binding, Object *)
+
+ EXBIND0(frame)
+
+ EXBIND1RC(bool, handles_global_class_type, const String &)
+
+ GDVIRTUAL1RC(Dictionary, _get_global_class_name, const String &)
+
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_global_class_name, p_path, ret);
+ if (!ret.has("name")) {
+ return String();
+ }
+ if (r_base_type != nullptr && ret.has("base_type")) {
+ *r_base_type = ret["base_type"];
+ }
+ if (r_icon_path != nullptr && ret.has("icon_path")) {
+ *r_icon_path = ret["icon_path"];
+ }
+ return ret["name"];
+ }
+};
+
+VARIANT_ENUM_CAST(ScriptLanguageExtension::LookupResultType)
+VARIANT_ENUM_CAST(ScriptLanguageExtension::CodeCompletionKind)
+VARIANT_ENUM_CAST(ScriptLanguageExtension::CodeCompletionLocation)
+
+class ScriptInstanceExtension : public ScriptInstance {
+public:
+ const GDNativeExtensionScriptInstanceInfo *native_info;
+ GDNativeExtensionScriptInstanceDataPtr instance = nullptr;
+
+// There should not be warnings on explicit casts.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+
+ virtual bool set(const StringName &p_name, const Variant &p_value) override {
+ if (native_info->set_func) {
+ return native_info->set_func(instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value);
+ }
+ return false;
+ }
+ virtual bool get(const StringName &p_name, Variant &r_ret) const override {
+ if (native_info->get_func) {
+ return native_info->get_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&r_ret);
+ }
+ return false;
+ }
+ virtual void get_property_list(List<PropertyInfo> *p_list) const override {
+ if (native_info->get_property_list_func) {
+ uint32_t pcount;
+ const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount);
+ for (uint32_t i = 0; i < pcount; i++) {
+ p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name));
+ }
+ if (native_info->free_property_list_func) {
+ native_info->free_property_list_func(instance, pinfo);
+ }
+ }
+ }
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override {
+ if (native_info->get_property_type_func) {
+ GDNativeBool is_valid = 0;
+ GDNativeVariantType type = native_info->get_property_type_func(instance, (const GDNativeStringNamePtr)&p_name, &is_valid);
+ if (r_is_valid) {
+ *r_is_valid = is_valid != 0;
+ }
+
+ return Variant::Type(type);
+ }
+ return Variant::NIL;
+ }
+
+ virtual Object *get_owner() override {
+ if (native_info->get_owner_func) {
+ return (Object *)native_info->get_owner_func(instance);
+ }
+ return nullptr;
+ }
+ static void _add_property_with_state(const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value, void *p_userdata) {
+ List<Pair<StringName, Variant>> *state = (List<Pair<StringName, Variant>> *)p_userdata;
+ state->push_back(Pair<StringName, Variant>(*(const StringName *)p_name, *(const Variant *)p_value));
+ }
+ virtual void get_property_state(List<Pair<StringName, Variant>> &state) override {
+ if (native_info->get_property_state_func) {
+ native_info->get_property_state_func(instance, _add_property_with_state, &state);
+ }
+ }
+
+ virtual void get_method_list(List<MethodInfo> *p_list) const override {
+ if (native_info->get_method_list_func) {
+ uint32_t mcount;
+ const GDNativeMethodInfo *minfo = native_info->get_method_list_func(instance, &mcount);
+ for (uint32_t i = 0; i < mcount; i++) {
+ MethodInfo m;
+ m.name = minfo[i].name;
+ m.flags = minfo[i].flags;
+ m.id = minfo[i].id;
+ m.return_val = PropertyInfo(Variant::Type(minfo[i].return_value.type), minfo[i].return_value.class_name, PropertyHint(minfo[i].return_value.hint), minfo[i].return_value.hint_string, minfo[i].return_value.usage, minfo[i].return_value.class_name);
+ for (uint32_t j = 0; j < minfo[i].argument_count; j++) {
+ m.arguments.push_back(PropertyInfo(Variant::Type(minfo[i].arguments[j].type), minfo[i].arguments[j].class_name, PropertyHint(minfo[i].arguments[j].hint), minfo[i].arguments[j].hint_string, minfo[i].arguments[j].usage, minfo[i].arguments[j].class_name));
+ }
+ const Variant *def_values = (const Variant *)minfo[i].default_arguments;
+ for (uint32_t j = 0; j < minfo[i].default_argument_count; j++) {
+ m.default_arguments.push_back(def_values[j]);
+ }
+ p_list->push_back(m);
+ }
+ if (native_info->free_method_list_func) {
+ native_info->free_method_list_func(instance, minfo);
+ }
+ }
+ }
+ virtual bool has_method(const StringName &p_method) const override {
+ if (native_info->has_method_func) {
+ return native_info->has_method_func(instance, (GDNativeStringNamePtr)&p_method);
+ }
+ return false;
+ }
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
+ Variant ret;
+ if (native_info->call_func) {
+ GDNativeCallError ce;
+ native_info->call_func(instance, (const GDNativeStringNamePtr)&p_method, (const GDNativeVariantPtr *)p_args, p_argcount, (GDNativeVariantPtr)&ret, &ce);
+ r_error.error = Callable::CallError::Error(ce.error);
+ r_error.argument = ce.argument;
+ r_error.expected = ce.expected;
+ }
+ return ret;
+ }
+
+ virtual void notification(int p_notification) override {
+ if (native_info->notification_func) {
+ native_info->notification_func(instance, p_notification);
+ }
+ }
+ virtual String to_string(bool *r_valid) override {
+ if (native_info->to_string_func) {
+ GDNativeBool valid;
+ String ret = native_info->to_string_func(instance, &valid);
+ if (r_valid) {
+ *r_valid = valid != 0;
+ }
+ return ret;
+ }
+ return String();
+ }
+
+ virtual void refcount_incremented() override {
+ if (native_info->refcount_incremented_func) {
+ native_info->refcount_incremented_func(instance);
+ }
+ }
+ virtual bool refcount_decremented() override {
+ if (native_info->refcount_decremented_func) {
+ return native_info->refcount_decremented_func(instance);
+ }
+ return false;
+ }
+
+ virtual Ref<Script> get_script() const override {
+ if (native_info->get_script_func) {
+ GDNativeObjectPtr script = native_info->get_script_func(instance);
+ return Ref<Script>(reinterpret_cast<Script *>(script));
+ }
+ return Ref<Script>();
+ }
+
+ virtual bool is_placeholder() const override {
+ if (native_info->is_placeholder_func) {
+ return native_info->is_placeholder_func(instance);
+ }
+ return false;
+ }
+
+ virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) override {
+ if (native_info->set_fallback_func) {
+ bool ret = native_info->set_fallback_func(instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value);
+ if (r_valid) {
+ *r_valid = ret;
+ }
+ }
+ }
+ virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid) override {
+ Variant ret;
+ if (native_info->get_fallback_func) {
+ bool valid = native_info->get_fallback_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret);
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ }
+ return ret;
+ }
+
+ virtual ScriptLanguage *get_language() override {
+ if (native_info->get_language_func) {
+ GDNativeExtensionScriptLanguagePtr lang = native_info->get_language_func(instance);
+ return reinterpret_cast<ScriptLanguage *>(lang);
+ }
+ return nullptr;
+ ;
+ }
+ virtual ~ScriptInstanceExtension() {
+ if (native_info->free_func) {
+ native_info->free_func(instance);
+ }
+ }
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+};
+
+#endif // SCRIPT_LANGUAGE_EXTENSION_H
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index f72dec8edf..d3c48853f1 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -34,6 +34,20 @@
#include "core/os/os.h"
#include "core/templates/local_vector.h"
+void UndoRedo::Operation::delete_reference() {
+ if (type != Operation::TYPE_REFERENCE) {
+ return;
+ }
+ if (ref.is_valid()) {
+ ref.unref();
+ } else {
+ Object *obj = ObjectDB::get_instance(object);
+ if (obj) {
+ memdelete(obj);
+ }
+ }
+}
+
void UndoRedo::_discard_redo() {
if (current_action == actions.size() - 1) {
return;
@@ -41,16 +55,7 @@ void UndoRedo::_discard_redo() {
for (int i = current_action + 1; i < actions.size(); i++) {
for (Operation &E : actions.write[i].do_ops) {
- if (E.type == Operation::TYPE_REFERENCE) {
- if (E.ref.is_valid()) {
- E.ref.unref();
- } else {
- Object *obj = ObjectDB::get_instance(E.object);
- if (obj) {
- memdelete(obj);
- }
- }
- }
+ E.delete_reference();
}
//ERASE do data
}
@@ -97,13 +102,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
for (unsigned int i = 0; i < to_remove.size(); i++) {
List<Operation>::Element *E = to_remove[i];
// Delete all object references
- if (E->get().type == Operation::TYPE_REFERENCE) {
- Object *obj = ObjectDB::get_instance(E->get().object);
-
- if (obj) {
- memdelete(obj);
- }
- }
+ E->get().delete_reference();
E->erase();
}
}
@@ -127,8 +126,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
force_keep_in_merge_ends = false;
}
-void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS
+void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -141,14 +139,13 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA
do_op.type = Operation::TYPE_METHOD;
do_op.name = p_method;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- do_op.args[i] = *argptr[i];
+ for (int i = 0; i < p_argcount; i++) {
+ do_op.args.push_back(*p_args[i]);
}
actions.write[current_action + 1].do_ops.push_back(do_op);
}
-void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS
+void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -168,8 +165,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_method;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- undo_op.args[i] = *argptr[i];
+ for (int i = 0; i < p_argcount; i++) {
+ undo_op.args.push_back(*p_args[i]);
}
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -186,7 +183,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
do_op.type = Operation::TYPE_PROPERTY;
do_op.name = p_property;
- do_op.args[0] = p_value;
+ do_op.args.push_back(p_value);
actions.write[current_action + 1].do_ops.push_back(do_op);
}
@@ -209,7 +206,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
undo_op.type = Operation::TYPE_PROPERTY;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_property;
- undo_op.args[0] = p_value;
+ undo_op.args.push_back(p_value);
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -270,16 +267,7 @@ void UndoRedo::_pop_history_tail() {
}
for (Operation &E : actions.write[0].undo_ops) {
- if (E.type == Operation::TYPE_REFERENCE) {
- if (E.ref.is_valid()) {
- E.ref.unref();
- } else {
- Object *obj = ObjectDB::get_instance(E.object);
- if (obj) {
- memdelete(obj);
- }
- }
- }
+ E.delete_reference();
}
actions.remove_at(0);
@@ -324,23 +312,18 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
switch (op.type) {
case Operation::TYPE_METHOD: {
+ int argc = op.args.size();
Vector<const Variant *> argptrs;
- argptrs.resize(VARIANT_ARG_MAX);
- int argc = 0;
+ argptrs.resize(argc);
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (op.args[i].get_type() == Variant::NIL) {
- break;
- }
+ for (int i = 0; i < argc; i++) {
argptrs.write[i] = &op.args[i];
- argc++;
}
- argptrs.resize(argc);
Callable::CallError ce;
- obj->call(op.name, (const Variant **)argptrs.ptr(), argc, ce);
+ obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT("Error calling method from signal '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
+ ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
}
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
@@ -351,7 +334,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
#endif
if (method_callback) {
- method_callback(method_callbck_ud, obj, op.name, VARIANT_ARGS_FROM_ARRAY(op.args));
+ method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc);
}
} break;
case Operation::TYPE_PROPERTY: {
@@ -449,7 +432,7 @@ void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback, void
void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback, void *p_ud) {
method_callback = p_method_callback;
- method_callbck_ud = p_ud;
+ method_callback_ud = p_ud;
}
void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback, void *p_ud) {
@@ -461,25 +444,25 @@ UndoRedo::~UndoRedo() {
clear_history();
}
-Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+void UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 2) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 0;
- return Variant();
+ return;
}
if (p_args[0]->get_type() != Variant::OBJECT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::OBJECT;
- return Variant();
+ return;
}
if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::STRING_NAME;
- return Variant();
+ return;
}
r_error.error = Callable::CallError::CALL_OK;
@@ -487,36 +470,28 @@ Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callabl
Object *object = *p_args[0];
StringName method = *p_args[1];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) {
- v[i] = *p_args[i + 2];
- }
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- add_do_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
- return Variant();
+ add_do_methodp(object, method, p_args + 2, p_argcount - 2);
}
-Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+void UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 2) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 0;
- return Variant();
+ return;
}
if (p_args[0]->get_type() != Variant::OBJECT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::OBJECT;
- return Variant();
+ return;
}
if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::STRING_NAME;
- return Variant();
+ return;
}
r_error.error = Callable::CallError::CALL_OK;
@@ -524,15 +499,7 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla
Object *object = *p_args[0];
StringName method = *p_args[1];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) {
- v[i] = *p_args[i + 2];
- }
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- add_undo_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
- return Variant();
+ add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
}
void UndoRedo::_bind_methods() {
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 75639f8abf..63cf3e5cbe 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -46,10 +46,10 @@ public:
};
typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name);
- Variant _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, VARIANT_ARG_DECLARE);
+ typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
private:
@@ -65,7 +65,9 @@ private:
Ref<RefCounted> ref;
ObjectID object;
StringName name;
- Variant args[VARIANT_ARG_MAX];
+ Vector<Variant> args;
+
+ void delete_reference();
};
struct Action {
@@ -90,7 +92,7 @@ private:
CommitNotifyCallback callback = nullptr;
void *callback_ud = nullptr;
- void *method_callbck_ud = nullptr;
+ void *method_callback_ud = nullptr;
void *prop_callback_ud = nullptr;
MethodNotifyCallback method_callback = nullptr;
@@ -104,8 +106,30 @@ protected:
public:
void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
- void add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
- void add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
+ void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+ void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+ template <typename... VarArgs>
+ void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_do_reference(Object *p_object);
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index 3a03c0a10b..24907d34c8 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -41,8 +41,8 @@ static const _KeyCodeText _keycodes[] = {
/* clang-format off */
{Key::ESCAPE ,"Escape"},
{Key::TAB ,"Tab"},
- {Key::BACKTAB ,"BackTab"},
- {Key::BACKSPACE ,"BackSpace"},
+ {Key::BACKTAB ,"Backtab"},
+ {Key::BACKSPACE ,"Backspace"},
{Key::ENTER ,"Enter"},
{Key::KP_ENTER ,"Kp Enter"},
{Key::INSERT ,"Insert"},
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index a21d81b2e7..3176a8a210 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -294,7 +294,7 @@ enum class Key {
enum class KeyModifierMask {
CODE_MASK = ((1 << 25) - 1), ///< Apply this mask to any keycode to remove modifiers.
- MODIFIER_MASK = (0xFF << 24), ///< Apply this mask to isolate modifiers.
+ MODIFIER_MASK = (0x7F << 24), ///< Apply this mask to isolate modifiers.
SHIFT = (1 << 25),
ALT = (1 << 26),
META = (1 << 27),
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index a6a32f0138..2bb1ea2ef4 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -38,7 +38,6 @@
class MainLoop : public Object {
GDCLASS(MainLoop, Object);
- OBJ_CATEGORY("Main Loop");
Ref<Script> initialize_script;
diff --git a/core/os/memory.h b/core/os/memory.h
index 27eaad5010..baa96ef3e9 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -186,9 +186,9 @@ void memdelete_arr(T *p_class) {
struct _GlobalNil {
int color = 1;
- _GlobalNil *right;
- _GlobalNil *left;
- _GlobalNil *parent;
+ _GlobalNil *right = nullptr;
+ _GlobalNil *left = nullptr;
+ _GlobalNil *parent = nullptr;
_GlobalNil();
};
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 9837b6e0aa..4f7095b0fc 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -80,7 +80,9 @@ void OS::print_error(const char *p_function, const char *p_file, int p_line, con
return;
}
- _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, p_type);
+ if (_logger) {
+ _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, p_type);
+ }
}
void OS::print(const char *p_format, ...) {
@@ -91,7 +93,9 @@ void OS::print(const char *p_format, ...) {
va_list argp;
va_start(argp, p_format);
- _logger->logv(p_format, argp, false);
+ if (_logger) {
+ _logger->logv(p_format, argp, false);
+ }
va_end(argp);
}
@@ -104,7 +108,9 @@ void OS::printerr(const char *p_format, ...) {
va_list argp;
va_start(argp, p_format);
- _logger->logv(p_format, argp, true);
+ if (_logger) {
+ _logger->logv(p_format, argp, true);
+ }
va_end(argp);
}
@@ -173,7 +179,7 @@ void OS::dump_memory_to_file(const char *p_file) {
//Memory::dump_static_mem_to_file(p_file);
}
-static FileAccess *_OSPRF = nullptr;
+static Ref<FileAccess> _OSPRF;
static void _OS_printres(Object *p_obj) {
Resource *res = Object::cast_to<Resource>(p_obj);
@@ -182,7 +188,7 @@ static void _OS_printres(Object *p_obj) {
}
String str = vformat("%s - %s - %s", res->to_string(), res->get_name(), res->get_path());
- if (_OSPRF) {
+ if (_OSPRF.is_valid()) {
_OSPRF->store_line(str);
} else {
print_line(str);
@@ -190,24 +196,19 @@ static void _OS_printres(Object *p_obj) {
}
void OS::print_all_resources(String p_to_file) {
- ERR_FAIL_COND(!p_to_file.is_empty() && _OSPRF);
+ 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 = nullptr;
+ _OSPRF.unref();
ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + ".");
}
}
ObjectDB::debug_objects(_OS_printres);
- if (!p_to_file.is_empty()) {
- if (_OSPRF) {
- memdelete(_OSPRF);
- }
- _OSPRF = nullptr;
- }
+ _OSPRF.unref();
}
void OS::print_resources_in_use(bool p_short) {
@@ -236,6 +237,11 @@ String OS::get_locale_language() const {
return get_locale().left(3).replace("_", "");
}
+// Embedded PCK offset.
+uint64_t OS::get_embedded_pck_offset() const {
+ return 0;
+}
+
// Helper function to ensure that a dir name/path will be valid on the OS
String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_dir_separator) const {
Vector<String> invalid_chars = String(": * ? \" < > |").split(" ");
@@ -328,17 +334,13 @@ void OS::yield() {
void OS::ensure_user_data_dir() {
String dd = get_user_data_dir();
- DirAccess *da = DirAccess::open(dd);
- if (da) {
- memdelete(da);
+ if (DirAccess::exists(dd)) {
return;
}
- da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error err = da->make_dir_recursive(dd);
ERR_FAIL_COND_MSG(err != OK, "Error attempting to create data dir: " + dd + ".");
-
- memdelete(da);
}
String OS::get_model_name() const {
@@ -554,6 +556,8 @@ OS::OS() {
}
OS::~OS() {
- memdelete(_logger);
+ if (_logger) {
+ memdelete(_logger);
+ }
singleton = nullptr;
}
diff --git a/core/os/os.h b/core/os/os.h
index 808d704b3d..5eac77d634 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -54,14 +54,11 @@ class OS {
bool _single_window = false;
String _local_clipboard;
int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure
- int _orientation;
bool _allow_hidpi = false;
bool _allow_layered = false;
bool _stdout_enabled = true;
bool _stderr_enabled = true;
- char *last_error;
-
CompositeLogger *_logger = nullptr;
bool restart_on_exit = false;
@@ -70,7 +67,7 @@ class OS {
// for the user interface we keep a record of the current display driver
// so we can retrieve the rendering drivers available
int _display_driver_id = -1;
- String _current_rendering_driver_name = "";
+ String _current_rendering_driver_name;
protected:
void _set_logger(CompositeLogger *p_logger);
@@ -140,7 +137,7 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) { return ERR_UNAVAILABLE; }
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) { return ERR_UNAVAILABLE; }
virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; }
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) { return ERR_UNAVAILABLE; }
@@ -155,6 +152,7 @@ public:
virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) { return create_process(get_executable_path(), p_arguments, r_child_id); };
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
+ virtual bool is_process_running(const ProcessID &p_pid) const = 0;
virtual void vibrate_handheld(int p_duration_ms = 500);
virtual Error shell_open(String p_uri);
@@ -266,6 +264,8 @@ public:
virtual String get_locale() const;
String get_locale_language() const;
+ virtual uint64_t get_embedded_pck_offset() const;
+
String get_safe_dir_name(const String &p_dir_name, bool p_allow_dir_separator = false) const;
virtual String get_godot_dir_name() const;
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index 190617f967..f622e2c7c5 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -149,7 +149,7 @@ void PoolAllocator::compact_up(int p_from) {
}
}
-bool PoolAllocator::find_entry_index(EntryIndicesPos *p_map_pos, Entry *p_entry) {
+bool PoolAllocator::find_entry_index(EntryIndicesPos *p_map_pos, const Entry *p_entry) {
EntryArrayPos entry_pos = entry_max;
for (int i = 0; i < entry_count; i++) {
@@ -424,7 +424,7 @@ bool PoolAllocator::is_locked(ID p_mem) const {
}
mt_lock();
- const Entry *e = ((PoolAllocator *)(this))->get_entry(p_mem);
+ const Entry *e = const_cast<PoolAllocator *>(this)->get_entry(p_mem);
if (!e) {
mt_unlock();
ERR_PRINT("!e");
diff --git a/core/os/pool_allocator.h b/core/os/pool_allocator.h
index 11a252bc54..a7a8523aa4 100644
--- a/core/os/pool_allocator.h
+++ b/core/os/pool_allocator.h
@@ -75,22 +75,22 @@ private:
typedef int EntryArrayPos;
typedef int EntryIndicesPos;
- Entry *entry_array;
- int *entry_indices;
- int entry_max;
- int entry_count;
+ Entry *entry_array = nullptr;
+ int *entry_indices = nullptr;
+ int entry_max = 0;
+ int entry_count = 0;
- uint8_t *pool;
- void *mem_ptr;
- int pool_size;
+ uint8_t *pool = nullptr;
+ void *mem_ptr = nullptr;
+ int pool_size = 0;
- int free_mem;
- int free_mem_peak;
+ int free_mem = 0;
+ int free_mem_peak = 0;
- unsigned int check_count;
- int align;
+ unsigned int check_count = 0;
+ int align = 1;
- bool needs_locking;
+ bool needs_locking = false;
inline int entry_end(const Entry &p_entry) const {
return p_entry.pos + aligned(p_entry.len);
@@ -108,7 +108,7 @@ private:
void compact_up(int p_from = 0);
bool get_free_entry(EntryArrayPos *p_pos);
bool find_hole(EntryArrayPos *p_pos, int p_for_size);
- bool find_entry_index(EntryIndicesPos *p_map_pos, Entry *p_entry);
+ bool find_entry_index(EntryIndicesPos *p_map_pos, const Entry *p_entry);
Entry *get_entry(ID p_mem);
const Entry *get_entry(ID p_mem) const;
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index f80e8f4bb3..c8072b7280 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "platform_config.h"
#ifndef PLATFORM_THREAD_OVERRIDE // See details in thread.h
#include "thread.h"
diff --git a/core/os/thread.h b/core/os/thread.h
index f4e46059ad..3382dd81f9 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "platform_config.h"
// Define PLATFORM_THREAD_OVERRIDE in your platform's `platform_config.h`
// to use a custom Thread implementation defined in `platform/[your_platform]/platform_thread.h`
// Overriding the platform implementation is required in some proprietary platforms
diff --git a/core/os/time.cpp b/core/os/time.cpp
index 5eae94279a..a30e2a906b 100644
--- a/core/os/time.cpp
+++ b/core/os/time.cpp
@@ -95,16 +95,21 @@ VARIANT_ENUM_CAST(Time::Weekday);
day = day_number_copy + 1; \
}
-#define VALIDATE_YMDHMS \
- ERR_FAIL_COND_V_MSG(month == 0, 0, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \
- ERR_FAIL_COND_V_MSG(month > 12, 0, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \
- ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); \
- ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); \
- ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \
- /* Do this check after month is tested as valid. */ \
- ERR_FAIL_COND_V_MSG(day == 0, 0, "Invalid day value of: " + itos(month) + ", days are 1-indexed and cannot be 0."); \
- uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \
- ERR_FAIL_COND_V_MSG(day > days_in_this_month, 0, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + ".");
+#define VALIDATE_YMDHMS(ret) \
+ ERR_FAIL_COND_V_MSG(month == 0, ret, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \
+ ERR_FAIL_COND_V_MSG(month < 0, ret, "Invalid month value of: " + itos(month) + "."); \
+ ERR_FAIL_COND_V_MSG(month > 12, ret, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \
+ ERR_FAIL_COND_V_MSG(hour > 23, ret, "Invalid hour value of: " + itos(hour) + "."); \
+ ERR_FAIL_COND_V_MSG(hour < 0, ret, "Invalid hour value of: " + itos(hour) + "."); \
+ ERR_FAIL_COND_V_MSG(minute > 59, ret, "Invalid minute value of: " + itos(minute) + "."); \
+ ERR_FAIL_COND_V_MSG(minute < 0, ret, "Invalid minute value of: " + itos(minute) + "."); \
+ ERR_FAIL_COND_V_MSG(second > 59, ret, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \
+ ERR_FAIL_COND_V_MSG(second < 0, ret, "Invalid second value of: " + itos(second) + "."); \
+ ERR_FAIL_COND_V_MSG(day == 0, ret, "Invalid day value of: " + itos(day) + ", days are 1-indexed and cannot be 0."); \
+ ERR_FAIL_COND_V_MSG(day < 0, ret, "Invalid day value of: " + itos(day) + "."); \
+ /* Do this check after month is tested as valid. */ \
+ uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \
+ ERR_FAIL_COND_V_MSG(day > days_in_this_month, ret, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + ".");
#define YMD_TO_DAY_NUMBER \
/* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \
@@ -124,61 +129,65 @@ VARIANT_ENUM_CAST(Time::Weekday);
} \
}
-#define PARSE_ISO8601_STRING \
- int64_t year = UNIX_EPOCH_YEAR_AD; \
- Month month = MONTH_JANUARY; \
- uint8_t day = 1; \
- uint8_t hour = 0; \
- uint8_t minute = 0; \
- uint8_t second = 0; \
- { \
- bool has_date = false, has_time = false; \
- String date, time; \
- if (p_datetime.find_char('T') > 0) { \
- has_date = has_time = true; \
- PackedStringArray array = p_datetime.split("T"); \
- date = array[0]; \
- time = array[1]; \
- } else if (p_datetime.find_char(' ') > 0) { \
- has_date = has_time = true; \
- PackedStringArray array = p_datetime.split(" "); \
- date = array[0]; \
- time = array[1]; \
- } else if (p_datetime.find_char('-', 1) > 0) { \
- has_date = true; \
- date = p_datetime; \
- } else if (p_datetime.find_char(':') > 0) { \
- has_time = true; \
- time = p_datetime; \
- } \
- /* Set the variables from the contents of the string. */ \
- if (has_date) { \
- PackedInt32Array array = date.split_ints("-", false); \
- year = array[0]; \
- month = (Month)array[1]; \
- day = array[2]; \
- /* Handle negative years. */ \
- if (p_datetime.find_char('-') == 0) { \
- year *= -1; \
- } \
- } \
- if (has_time) { \
- PackedInt32Array array = time.split_ints(":", false); \
- hour = array[0]; \
- minute = array[1]; \
- second = array[2]; \
- } \
+#define PARSE_ISO8601_STRING(ret) \
+ int64_t year = UNIX_EPOCH_YEAR_AD; \
+ Month month = MONTH_JANUARY; \
+ int day = 1; \
+ int hour = 0; \
+ int minute = 0; \
+ int second = 0; \
+ { \
+ bool has_date = false, has_time = false; \
+ String date, time; \
+ if (p_datetime.find_char('T') > 0) { \
+ has_date = has_time = true; \
+ PackedStringArray array = p_datetime.split("T"); \
+ ERR_FAIL_COND_V_MSG(array.size() < 2, ret, "Invalid ISO 8601 date/time string."); \
+ date = array[0]; \
+ time = array[1]; \
+ } else if (p_datetime.find_char(' ') > 0) { \
+ has_date = has_time = true; \
+ PackedStringArray array = p_datetime.split(" "); \
+ ERR_FAIL_COND_V_MSG(array.size() < 2, ret, "Invalid ISO 8601 date/time string."); \
+ date = array[0]; \
+ time = array[1]; \
+ } else if (p_datetime.find_char('-', 1) > 0) { \
+ has_date = true; \
+ date = p_datetime; \
+ } else if (p_datetime.find_char(':') > 0) { \
+ has_time = true; \
+ time = p_datetime; \
+ } \
+ /* Set the variables from the contents of the string. */ \
+ if (has_date) { \
+ PackedInt32Array array = date.split_ints("-", false); \
+ ERR_FAIL_COND_V_MSG(array.size() < 3, ret, "Invalid ISO 8601 date string."); \
+ year = array[0]; \
+ month = (Month)array[1]; \
+ day = array[2]; \
+ /* Handle negative years. */ \
+ if (p_datetime.find_char('-') == 0) { \
+ year *= -1; \
+ } \
+ } \
+ if (has_time) { \
+ PackedInt32Array array = time.split_ints(":", false); \
+ ERR_FAIL_COND_V_MSG(array.size() < 3, ret, "Invalid ISO 8601 time string."); \
+ hour = array[0]; \
+ minute = array[1]; \
+ second = array[2]; \
+ } \
}
#define EXTRACT_FROM_DICTIONARY \
/* Get all time values from the dictionary. If it doesn't exist, set the */ \
/* values to the default values for Unix epoch (1970-01-01 00:00:00). */ \
int64_t year = p_datetime.has(YEAR_KEY) ? int64_t(p_datetime[YEAR_KEY]) : UNIX_EPOCH_YEAR_AD; \
- Month month = Month((p_datetime.has(MONTH_KEY)) ? uint8_t(p_datetime[MONTH_KEY]) : 1); \
- uint8_t day = p_datetime.has(DAY_KEY) ? uint8_t(p_datetime[DAY_KEY]) : 1; \
- uint8_t hour = p_datetime.has(HOUR_KEY) ? uint8_t(p_datetime[HOUR_KEY]) : 0; \
- uint8_t minute = p_datetime.has(MINUTE_KEY) ? uint8_t(p_datetime[MINUTE_KEY]) : 0; \
- uint8_t second = p_datetime.has(SECOND_KEY) ? uint8_t(p_datetime[SECOND_KEY]) : 0;
+ Month month = Month((p_datetime.has(MONTH_KEY)) ? int(p_datetime[MONTH_KEY]) : 1); \
+ int day = p_datetime.has(DAY_KEY) ? int(p_datetime[DAY_KEY]) : 1; \
+ int hour = p_datetime.has(HOUR_KEY) ? int(p_datetime[HOUR_KEY]) : 0; \
+ int minute = p_datetime.has(MINUTE_KEY) ? int(p_datetime[MINUTE_KEY]) : 0; \
+ int second = p_datetime.has(SECOND_KEY) ? int(p_datetime[SECOND_KEY]) : 0;
Time *Time::singleton = nullptr;
@@ -252,8 +261,8 @@ String Time::get_time_string_from_unix_time(int64_t p_unix_time_val) const {
return vformat("%02d:%02d:%02d", hour, minute, second);
}
-Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday) const {
- PARSE_ISO8601_STRING
+Dictionary Time::get_datetime_dict_from_datetime_string(String p_datetime, bool p_weekday) const {
+ PARSE_ISO8601_STRING(Dictionary())
Dictionary dict;
dict[YEAR_KEY] = year;
dict[MONTH_KEY] = (uint8_t)month;
@@ -270,9 +279,10 @@ Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday
return dict;
}
-String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space) const {
+String Time::get_datetime_string_from_datetime_dict(const Dictionary p_datetime, bool p_use_space) const {
ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), "", "Invalid datetime Dictionary: Dictionary is empty.");
EXTRACT_FROM_DICTIONARY
+ VALIDATE_YMDHMS("")
// vformat only supports up to 6 arguments, so we need to split this up into 2 parts.
String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day);
if (p_use_space) {
@@ -283,21 +293,36 @@ String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_spa
return timestamp;
}
-int64_t Time::get_unix_time_from_datetime_dict(Dictionary p_datetime) const {
+int64_t Time::get_unix_time_from_datetime_dict(const Dictionary p_datetime) const {
ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty");
EXTRACT_FROM_DICTIONARY
- VALIDATE_YMDHMS
+ VALIDATE_YMDHMS(0)
YMD_TO_DAY_NUMBER
return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second;
}
int64_t Time::get_unix_time_from_datetime_string(String p_datetime) const {
- PARSE_ISO8601_STRING
- VALIDATE_YMDHMS
+ PARSE_ISO8601_STRING(-1)
+ VALIDATE_YMDHMS(0)
YMD_TO_DAY_NUMBER
return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second;
}
+String Time::get_offset_string_from_offset_minutes(int64_t p_offset_minutes) const {
+ String sign;
+ if (p_offset_minutes < 0) {
+ sign = "-";
+ p_offset_minutes = -p_offset_minutes;
+ } else {
+ sign = "+";
+ }
+ // These two lines can be optimized to one instruction on x86 and others.
+ // Note that % is acceptable here only because we ensure it's positive.
+ int64_t offset_hours = p_offset_minutes / 60;
+ int64_t offset_minutes = p_offset_minutes % 60;
+ return vformat("%s%02d:%02d", sign, offset_hours, offset_minutes);
+}
+
Dictionary Time::get_datetime_dict_from_system(bool p_utc) const {
OS::Date date = OS::get_singleton()->get_date(p_utc);
OS::Time time = OS::get_singleton()->get_time(p_utc);
@@ -385,10 +410,11 @@ void Time::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_datetime_string_from_unix_time", "unix_time_val", "use_space"), &Time::get_datetime_string_from_unix_time, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_date_string_from_unix_time", "unix_time_val"), &Time::get_date_string_from_unix_time);
ClassDB::bind_method(D_METHOD("get_time_string_from_unix_time", "unix_time_val"), &Time::get_time_string_from_unix_time);
- ClassDB::bind_method(D_METHOD("get_datetime_dict_from_string", "datetime", "weekday"), &Time::get_datetime_dict_from_string);
- ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict);
+ ClassDB::bind_method(D_METHOD("get_datetime_dict_from_datetime_string", "datetime", "weekday"), &Time::get_datetime_dict_from_datetime_string);
+ ClassDB::bind_method(D_METHOD("get_datetime_string_from_datetime_dict", "datetime", "use_space"), &Time::get_datetime_string_from_datetime_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string);
+ ClassDB::bind_method(D_METHOD("get_offset_string_from_offset_minutes", "offset_minutes"), &Time::get_offset_string_from_offset_minutes);
ClassDB::bind_method(D_METHOD("get_datetime_dict_from_system", "utc"), &Time::get_datetime_dict_from_system, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_date_dict_from_system", "utc"), &Time::get_date_dict_from_system, DEFVAL(false));
diff --git a/core/os/time.h b/core/os/time.h
index 3f00ba1478..4b4ce3526a 100644
--- a/core/os/time.h
+++ b/core/os/time.h
@@ -51,7 +51,7 @@ class Time : public Object {
public:
static Time *get_singleton();
- enum Month : uint8_t {
+ enum Month {
/// Start at 1 to follow Windows SYSTEMTIME structure
/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
MONTH_JANUARY = 1,
@@ -85,10 +85,11 @@ public:
String get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space = false) const;
String get_date_string_from_unix_time(int64_t p_unix_time_val) const;
String get_time_string_from_unix_time(int64_t p_unix_time_val) const;
- Dictionary get_datetime_dict_from_string(String p_datetime, bool p_weekday = true) const;
- String get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space = false) const;
- int64_t get_unix_time_from_datetime_dict(Dictionary p_datetime) const;
+ Dictionary get_datetime_dict_from_datetime_string(String p_datetime, bool p_weekday = true) const;
+ String get_datetime_string_from_datetime_dict(const Dictionary p_datetime, bool p_use_space = false) const;
+ int64_t get_unix_time_from_datetime_dict(const Dictionary p_datetime) const;
int64_t get_unix_time_from_datetime_string(String p_datetime) const;
+ String get_offset_string_from_offset_minutes(int64_t p_offset_minutes) const;
// Methods that get information from OS.
Dictionary get_datetime_dict_from_system(bool p_utc = false) const;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index a4b6a589f3..e60d325f74 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -49,6 +49,7 @@
#include "core/io/image_loader.h"
#include "core/io/json.h"
#include "core/io/marshalls.h"
+#include "core/io/missing_resource.h"
#include "core/io/packed_data_container.h"
#include "core/io/packet_peer.h"
#include "core/io/packet_peer_dtls.h"
@@ -71,6 +72,7 @@
#include "core/multiplayer/multiplayer_api.h"
#include "core/multiplayer/multiplayer_peer.h"
#include "core/object/class_db.h"
+#include "core/object/script_language_extension.h"
#include "core/object/undo_redo.h"
#include "core/os/main_loop.h"
#include "core/os/time.h"
@@ -108,6 +110,8 @@ extern void unregister_global_constants();
static ResourceUID *resource_uid = nullptr;
+static bool _is_core_extensions_registered = false;
+
void register_core_types() {
//consistency check
static_assert(sizeof(Callable) <= 16);
@@ -139,20 +143,25 @@ void register_core_types() {
GDREGISTER_CLASS(Object);
- GDREGISTER_VIRTUAL_CLASS(Script);
+ GDREGISTER_ABSTRACT_CLASS(Script);
+ GDREGISTER_ABSTRACT_CLASS(ScriptLanguage);
+
+ GDREGISTER_VIRTUAL_CLASS(ScriptExtension);
+ GDREGISTER_VIRTUAL_CLASS(ScriptLanguageExtension);
GDREGISTER_CLASS(RefCounted);
GDREGISTER_CLASS(WeakRef);
GDREGISTER_CLASS(Resource);
+ GDREGISTER_VIRTUAL_CLASS(MissingResource);
GDREGISTER_CLASS(Image);
GDREGISTER_CLASS(Shortcut);
- GDREGISTER_VIRTUAL_CLASS(InputEvent);
- GDREGISTER_VIRTUAL_CLASS(InputEventWithModifiers);
- GDREGISTER_VIRTUAL_CLASS(InputEventFromWindow);
+ GDREGISTER_ABSTRACT_CLASS(InputEvent);
+ GDREGISTER_ABSTRACT_CLASS(InputEventWithModifiers);
+ GDREGISTER_ABSTRACT_CLASS(InputEventFromWindow);
GDREGISTER_CLASS(InputEventKey);
GDREGISTER_CLASS(InputEventShortcut);
- GDREGISTER_VIRTUAL_CLASS(InputEventMouse);
+ GDREGISTER_ABSTRACT_CLASS(InputEventMouse);
GDREGISTER_CLASS(InputEventMouseButton);
GDREGISTER_CLASS(InputEventMouseMotion);
GDREGISTER_CLASS(InputEventJoypadButton);
@@ -160,21 +169,21 @@ void register_core_types() {
GDREGISTER_CLASS(InputEventScreenDrag);
GDREGISTER_CLASS(InputEventScreenTouch);
GDREGISTER_CLASS(InputEventAction);
- GDREGISTER_VIRTUAL_CLASS(InputEventGesture);
+ GDREGISTER_ABSTRACT_CLASS(InputEventGesture);
GDREGISTER_CLASS(InputEventMagnifyGesture);
GDREGISTER_CLASS(InputEventPanGesture);
GDREGISTER_CLASS(InputEventMIDI);
// Network
- GDREGISTER_VIRTUAL_CLASS(IP);
+ GDREGISTER_ABSTRACT_CLASS(IP);
- GDREGISTER_VIRTUAL_CLASS(StreamPeer);
+ GDREGISTER_ABSTRACT_CLASS(StreamPeer);
GDREGISTER_CLASS(StreamPeerExtension);
GDREGISTER_CLASS(StreamPeerBuffer);
GDREGISTER_CLASS(StreamPeerTCP);
GDREGISTER_CLASS(TCPServer);
- GDREGISTER_VIRTUAL_CLASS(PacketPeer);
+ GDREGISTER_ABSTRACT_CLASS(PacketPeer);
GDREGISTER_CLASS(PacketPeerExtension);
GDREGISTER_CLASS(PacketPeerStream);
GDREGISTER_CLASS(PacketPeerUDP);
@@ -198,7 +207,7 @@ void register_core_types() {
resource_format_loader_crypto.instantiate();
ResourceLoader::add_resource_format_loader(resource_format_loader_crypto);
- GDREGISTER_VIRTUAL_CLASS(MultiplayerPeer);
+ GDREGISTER_ABSTRACT_CLASS(MultiplayerPeer);
GDREGISTER_CLASS(MultiplayerPeerExtension);
GDREGISTER_CLASS(MultiplayerAPI);
GDREGISTER_CLASS(MainLoop);
@@ -224,19 +233,19 @@ void register_core_types() {
GDREGISTER_CLASS(PCKPacker);
GDREGISTER_CLASS(PackedDataContainer);
- GDREGISTER_VIRTUAL_CLASS(PackedDataContainerRef);
- GDREGISTER_CLASS(AStar);
+ GDREGISTER_ABSTRACT_CLASS(PackedDataContainerRef);
+ GDREGISTER_CLASS(AStar3D);
GDREGISTER_CLASS(AStar2D);
GDREGISTER_CLASS(EncodedObjectAsID);
GDREGISTER_CLASS(RandomNumberGenerator);
- GDREGISTER_VIRTUAL_CLASS(ResourceImporter);
+ GDREGISTER_ABSTRACT_CLASS(ResourceImporter);
GDREGISTER_CLASS(NativeExtension);
- GDREGISTER_VIRTUAL_CLASS(NativeExtensionManager);
+ GDREGISTER_ABSTRACT_CLASS(NativeExtensionManager);
- GDREGISTER_VIRTUAL_CLASS(ResourceUID);
+ GDREGISTER_ABSTRACT_CLASS(ResourceUID);
GDREGISTER_CLASS(EngineProfiler);
@@ -259,6 +268,9 @@ void register_core_types() {
_classdb = memnew(core_bind::special::ClassDB);
_marshalls = memnew(core_bind::Marshalls);
_engine_debugger = memnew(core_bind::EngineDebugger);
+
+ 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");
}
void register_core_settings() {
@@ -274,7 +286,7 @@ void register_core_settings() {
void register_core_singletons() {
GDREGISTER_CLASS(ProjectSettings);
- GDREGISTER_VIRTUAL_CLASS(IP);
+ GDREGISTER_ABSTRACT_CLASS(IP);
GDREGISTER_CLASS(core_bind::Geometry2D);
GDREGISTER_CLASS(core_bind::Geometry3D);
GDREGISTER_CLASS(core_bind::ResourceLoader);
@@ -284,7 +296,7 @@ void register_core_singletons() {
GDREGISTER_CLASS(core_bind::special::ClassDB);
GDREGISTER_CLASS(core_bind::Marshalls);
GDREGISTER_CLASS(TranslationServer);
- GDREGISTER_VIRTUAL_CLASS(Input);
+ GDREGISTER_ABSTRACT_CLASS(Input);
GDREGISTER_CLASS(InputMap);
GDREGISTER_CLASS(Expression);
GDREGISTER_CLASS(core_bind::EngineDebugger);
@@ -314,11 +326,16 @@ void register_core_extensions() {
NativeExtension::initialize_native_extensions();
native_extension_manager->load_extensions();
native_extension_manager->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+ _is_core_extensions_registered = true;
}
-void unregister_core_types() {
- native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+void unregister_core_extensions() {
+ if (_is_core_extensions_registered) {
+ native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+ }
+}
+void unregister_core_types() {
memdelete(native_extension_manager);
memdelete(resource_uid);
diff --git a/core/register_core_types.h b/core/register_core_types.h
index 0fd4e73c40..dfb2d8ac80 100644
--- a/core/register_core_types.h
+++ b/core/register_core_types.h
@@ -36,5 +36,6 @@ void register_core_settings();
void register_core_extensions();
void register_core_singletons();
void unregister_core_types();
+void unregister_core_extensions();
#endif // REGISTER_CORE_TYPES_H
diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp
index 07b58f2418..93429744fc 100644
--- a/core/string/optimized_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -37,9 +37,9 @@ extern "C" {
}
struct CompressedString {
- int orig_len;
+ int orig_len = 0;
CharString compressed;
- int offset;
+ int offset = 0;
};
void OptimizedTranslation::generate(const Ref<Translation> &p_from) {
diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp
index 97e119bcf6..919c9e08e3 100644
--- a/core/string/print_string.cpp
+++ b/core/string/print_string.cpp
@@ -45,7 +45,7 @@ void add_print_handler(PrintHandlerList *p_handler) {
_global_unlock();
}
-void remove_print_handler(PrintHandlerList *p_handler) {
+void remove_print_handler(const PrintHandlerList *p_handler) {
_global_lock();
PrintHandlerList *prev = nullptr;
diff --git a/core/string/print_string.h b/core/string/print_string.h
index 669d2ea316..f7d0f25030 100644
--- a/core/string/print_string.h
+++ b/core/string/print_string.h
@@ -54,13 +54,21 @@ String stringify_variants(Variant p_var, Args... p_args) {
}
void add_print_handler(PrintHandlerList *p_handler);
-void remove_print_handler(PrintHandlerList *p_handler);
+void remove_print_handler(const PrintHandlerList *p_handler);
extern bool _print_line_enabled;
extern bool _print_error_enabled;
extern void __print_line(String p_string);
extern void print_error(String p_string);
extern void print_verbose(String p_string);
-#define print_line(...) __print_line(stringify_variants(__VA_ARGS__))
+
+inline void print_line(Variant v) {
+ __print_line(stringify_variants(v));
+}
+
+template <typename... Args>
+void print_line(Variant p_var, Args... p_args) {
+ __print_line(stringify_variants(p_var, p_args...));
+}
#endif // PRINT_STRING_H
diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp
index 11674629fc..9c4fc4e1b7 100644
--- a/core/string/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -73,11 +73,23 @@ void StringName::cleanup() {
d = d->next;
}
}
- print_line("\nStringName Reference Ranking:\n");
+
+ print_line("\nStringName reference ranking (from most to least referenced):\n");
+
data.sort_custom<DebugSortReferences>();
- for (int i = 0; i < MIN(100, data.size()); i++) {
+ int unreferenced_stringnames = 0;
+ int rarely_referenced_stringnames = 0;
+ for (int i = 0; i < data.size(); i++) {
print_line(itos(i + 1) + ": " + data[i]->get_name() + " - " + itos(data[i]->debug_references));
+ if (data[i]->debug_references == 0) {
+ unreferenced_stringnames += 1;
+ } else if (data[i]->debug_references < 5) {
+ rarely_referenced_stringnames += 1;
+ }
}
+
+ print_line(vformat("\nOut of %d StringNames, %d StringNames were never referenced during this run (0 times) (%.2f%%).", data.size(), unreferenced_stringnames, unreferenced_stringnames / float(data.size()) * 100));
+ print_line(vformat("Out of %d StringNames, %d StringNames were rarely referenced during this run (1-4 times) (%.2f%%).", data.size(), rarely_referenced_stringnames, rarely_referenced_stringnames / float(data.size()) * 100));
}
#endif
int lost_strings = 0;
@@ -235,6 +247,7 @@ StringName::StringName(const char *p_name, bool p_static) {
_data->cname = nullptr;
_data->next = _table[idx];
_data->prev = nullptr;
+
#ifdef DEBUG_ENABLED
if (unlikely(debug_stringname)) {
// Keep in memory, force static.
diff --git a/core/string/string_name.h b/core/string/string_name.h
index 6f08d32981..ff4c41af94 100644
--- a/core/string/string_name.h
+++ b/core/string/string_name.h
@@ -35,6 +35,8 @@
#include "core/string/ustring.h"
#include "core/templates/safe_refcount.h"
+#define UNIQUE_NODE_PREFIX "%"
+
class Main;
struct StaticCString {
@@ -70,7 +72,7 @@ class StringName {
_Data *_data = nullptr;
union _HashUnion {
- _Data *ptr;
+ _Data *ptr = nullptr;
uint32_t hash;
};
@@ -100,6 +102,17 @@ public:
bool operator==(const String &p_name) const;
bool operator==(const char *p_name) const;
bool operator!=(const String &p_name) const;
+
+ _FORCE_INLINE_ bool is_node_unique_name() const {
+ if (!_data) {
+ return false;
+ }
+ if (_data->cname != nullptr) {
+ return (char32_t)_data->cname[0] == (char32_t)UNIQUE_NODE_PREFIX[0];
+ } else {
+ return (char32_t)_data->name[0] == (char32_t)UNIQUE_NODE_PREFIX[0];
+ }
+ }
_FORCE_INLINE_ bool operator<(const StringName &p_name) const {
return _data < p_name._data;
}
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 811ae95e9f..d6d361b5f1 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -685,8 +685,12 @@ Ref<Translation> TranslationServer::get_tool_translation() const {
String TranslationServer::get_tool_locale() {
#ifdef TOOLS_ENABLED
- if (TranslationServer::get_singleton()->get_tool_translation().is_valid() && (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint())) {
- return tool_translation->get_locale();
+ if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) {
+ if (TranslationServer::get_singleton()->get_tool_translation().is_valid()) {
+ return tool_translation->get_locale();
+ } else {
+ return "en";
+ }
} else {
#else
{
@@ -887,7 +891,7 @@ String TranslationServer::wrap_with_fakebidi_characters(String &p_message) const
return res;
}
-String TranslationServer::add_padding(String &p_message, int p_length) const {
+String TranslationServer::add_padding(const String &p_message, int p_length) const {
String res;
String prefix = pseudolocalization_prefix;
String suffix;
@@ -917,7 +921,7 @@ const char32_t *TranslationServer::get_accented_version(char32_t p_character) co
}
bool TranslationServer::is_placeholder(String &p_message, int p_index) const {
- return p_message[p_index] == '%' && p_index < p_message.size() - 1 &&
+ return p_index < p_message.size() - 1 && p_message[p_index] == '%' &&
(p_message[p_index + 1] == 's' || p_message[p_index + 1] == 'c' || p_message[p_index + 1] == 'd' ||
p_message[p_index + 1] == 'o' || p_message[p_index + 1] == 'x' || p_message[p_index + 1] == 'X' || p_message[p_index + 1] == 'f');
}
diff --git a/core/string/translation.h b/core/string/translation.h
index 947ca4c6d8..ded6ed5925 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -96,7 +96,7 @@ class TranslationServer : public Object {
String double_vowels(String &p_message) const;
String replace_with_accented_string(String &p_message) const;
String wrap_with_fakebidi_characters(String &p_message) const;
- String add_padding(String &p_message, int p_length) const;
+ String add_padding(const String &p_message, int p_length) const;
const char32_t *get_accented_version(char32_t p_character) const;
bool is_placeholder(String &p_message, int p_index) const;
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index 1c991ee12d..3f94e064ec 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -35,7 +35,7 @@
#ifdef DEBUG_TRANSLATION_PO
void TranslationPO::print_translation_map() {
Error err;
- FileAccess *file = FileAccess::open("translation_map_print_test.txt", FileAccess::WRITE, &err);
+ Ref<FileAccess> file = FileAccess::open("translation_map_print_test.txt", FileAccess::WRITE, &err);
if (err != OK) {
ERR_PRINT("Failed to open translation_map_print_test.txt");
return;
@@ -62,7 +62,6 @@ void TranslationPO::print_translation_map() {
file->store_line("");
}
}
- file->close();
}
#endif
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index c4edc8c086..5d998d22d4 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -35,6 +35,7 @@
#include "core/math/math_funcs.h"
#include "core/os/memory.h"
#include "core/string/print_string.h"
+#include "core/string/string_name.h"
#include "core/string/translation.h"
#include "core/string/ucaps.h"
#include "core/variant/variant.h"
@@ -103,9 +104,12 @@ bool Char16String::operator<(const Char16String &p_right) const {
}
Char16String &Char16String::operator+=(char16_t p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
- set(length() - 1, p_char);
+ const int lhs_len = length();
+ resize(lhs_len + 2);
+
+ char16_t *dst = ptrw();
+ dst[lhs_len] = p_char;
+ dst[lhs_len + 1] = 0;
return *this;
}
@@ -158,9 +162,12 @@ bool CharString::operator<(const CharString &p_right) const {
}
CharString &CharString::operator+=(char p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
- set(length() - 1, p_char);
+ const int lhs_len = length();
+ resize(lhs_len + 2);
+
+ char *dst = ptrw();
+ dst[lhs_len] = p_char;
+ dst[lhs_len + 1] = 0;
return *this;
}
@@ -304,11 +311,7 @@ void String::copy_from(const char *p_cstr) {
return;
}
- int len = 0;
- const char *ptr = p_cstr;
- while (*(ptr++) != 0) {
- len++;
- }
+ const size_t len = strlen(p_cstr);
if (len == 0) {
resize(0);
@@ -319,7 +322,7 @@ void String::copy_from(const char *p_cstr) {
char32_t *dst = this->ptrw();
- for (int i = 0; i < len + 1; i++) {
+ for (size_t i = 0; i <= len; i++) {
dst[i] = p_cstr[i];
}
}
@@ -374,13 +377,14 @@ void String::copy_from(const wchar_t *p_cstr, const int p_clip_to) {
void String::copy_from(const char32_t &p_char) {
resize(2);
+ char32_t *dst = ptrw();
if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
- set(0, 0xfffd);
+ dst[0] = 0xfffd;
} else {
- set(0, p_char);
+ dst[0] = p_char;
}
- set(1, 0);
+ dst[1] = 0;
}
void String::copy_from(const char32_t *p_cstr) {
@@ -429,9 +433,8 @@ void String::copy_from(const char32_t *p_cstr, const int p_clip_to) {
// p_length <= p_char strlen
void String::copy_from_unchecked(const char32_t *p_char, const int p_length) {
resize(p_length + 1);
- set(p_length, 0);
-
char32_t *dst = ptrw();
+ dst[p_length] = 0;
for (int i = 0; i < p_length; i++) {
if ((p_char[i] >= 0xd800 && p_char[i] <= 0xdfff) || (p_char[i] > 0x10ffff)) {
@@ -461,6 +464,12 @@ String String::operator+(const String &p_str) const {
return res;
}
+String String::operator+(char32_t p_char) const {
+ String res = *this;
+ res += p_char;
+ return res;
+}
+
String operator+(const char *p_chr, const String &p_str) {
String tmp = p_chr;
tmp += p_str;
@@ -484,27 +493,23 @@ String operator+(char32_t p_chr, const String &p_str) {
}
String &String::operator+=(const String &p_str) {
- if (is_empty()) {
+ const int lhs_len = length();
+ if (lhs_len == 0) {
*this = p_str;
return *this;
}
- if (p_str.is_empty()) {
+ const int rhs_len = p_str.length();
+ if (rhs_len == 0) {
return *this;
}
- int from = length();
-
- resize(length() + p_str.size());
+ resize(lhs_len + rhs_len + 1);
const char32_t *src = p_str.get_data();
- char32_t *dst = ptrw();
+ char32_t *dst = ptrw() + lhs_len;
- set(length(), 0);
-
- for (int i = 0; i < p_str.length(); i++) {
- dst[from + i] = src[i];
- }
+ memcpy(dst, src, (rhs_len + 1) * sizeof(char32_t));
return *this;
}
@@ -514,22 +519,15 @@ String &String::operator+=(const char *p_str) {
return *this;
}
- int src_len = 0;
- const char *ptr = p_str;
- while (*(ptr++) != 0) {
- src_len++;
- }
-
- int from = length();
+ const int lhs_len = length();
+ const size_t rhs_len = strlen(p_str);
- resize(from + src_len + 1);
+ resize(lhs_len + rhs_len + 1);
- char32_t *dst = ptrw();
-
- set(length(), 0);
+ char32_t *dst = ptrw() + lhs_len;
- for (int i = 0; i < src_len; i++) {
- dst[from + i] = p_str[i];
+ for (size_t i = 0; i <= rhs_len; i++) {
+ dst[i] = p_str[i];
}
return *this;
@@ -552,14 +550,16 @@ String &String::operator+=(const char32_t *p_str) {
}
String &String::operator+=(char32_t p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
+ const int lhs_len = length();
+ resize(lhs_len + 2);
+ char32_t *dst = ptrw();
if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
- set(length() - 1, 0xfffd);
+ dst[lhs_len] = 0xfffd;
} else {
- set(length() - 1, p_char);
+ dst[lhs_len] = p_char;
}
+ dst[lhs_len + 1] = 0;
return *this;
}
@@ -4124,15 +4124,11 @@ String String::path_to(const String &p_path) const {
dst += "/";
}
- String base;
-
if (src.begins_with("res://") && dst.begins_with("res://")) {
- base = "res:/";
src = src.replace("res://", "/");
dst = dst.replace("res://", "/");
} else if (src.begins_with("user://") && dst.begins_with("user://")) {
- base = "user:/";
src = src.replace("user://", "/");
dst = dst.replace("user://", "/");
@@ -4147,7 +4143,6 @@ String String::path_to(const String &p_path) const {
return p_path; //impossible to do this
}
- base = src_begin;
src = src.substr(src_begin.length(), src.length());
dst = dst.substr(dst_begin.length(), dst.length());
}
@@ -4358,7 +4353,7 @@ String String::property_name_encode() const {
}
// Changes made to the set of invalid characters must also be reflected in the String documentation.
-const String String::invalid_node_name_characters = ". : @ / \"";
+const String String::invalid_node_name_characters = ". : @ / \" " UNIQUE_NODE_PREFIX;
String String::validate_node_name() const {
Vector<String> chars = String::invalid_node_name_characters.split(" ");
@@ -4432,7 +4427,7 @@ String String::sprintf(const Array &values, bool *error) const {
int min_chars = 0;
int min_decimals = 0;
bool in_decimals = false;
- bool pad_with_zeroes = false;
+ bool pad_with_zeros = false;
bool left_justified = false;
bool show_sign = false;
@@ -4485,7 +4480,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding.
int pad_chars_count = (value < 0 || show_sign) ? min_chars - 1 : min_chars;
- String pad_char = pad_with_zeroes ? String("0") : String(" ");
+ String pad_char = pad_with_zeros ? String("0") : String(" ");
if (left_justified) {
str = str.rpad(pad_chars_count, pad_char);
} else {
@@ -4493,10 +4488,13 @@ String String::sprintf(const Array &values, bool *error) const {
}
// Sign.
- if (show_sign && value >= 0) {
- str = str.insert(pad_with_zeroes ? 0 : str.length() - number_len, "+");
- } else if (value < 0) {
- str = str.insert(pad_with_zeroes ? 0 : str.length() - number_len, "-");
+ if (show_sign || value < 0) {
+ String sign_char = value < 0 ? "-" : "+";
+ if (left_justified) {
+ str = str.insert(0, sign_char);
+ } else {
+ str = str.insert(pad_with_zeros ? 0 : str.length() - number_len, sign_char);
+ }
}
formatted += str;
@@ -4525,13 +4523,9 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding. Leave room for sign later if required.
int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars;
- String pad_char = pad_with_zeroes ? String("0") : String(" ");
+ String pad_char = pad_with_zeros ? String("0") : String(" ");
if (left_justified) {
- if (pad_with_zeroes) {
- return "left justification cannot be used with zeros as the padding";
- } else {
- str = str.rpad(pad_chars_count, pad_char);
- }
+ str = str.rpad(pad_chars_count, pad_char);
} else {
str = str.lpad(pad_chars_count, pad_char);
}
@@ -4542,7 +4536,7 @@ String String::sprintf(const Array &values, bool *error) const {
if (left_justified) {
str = str.insert(0, sign_char);
} else {
- str = str.insert(pad_with_zeroes ? 0 : str.length() - initial_len, sign_char);
+ str = str.insert(pad_with_zeros ? 0 : str.length() - initial_len, sign_char);
}
}
@@ -4631,7 +4625,11 @@ String String::sprintf(const Array &values, bool *error) const {
min_decimals += n;
} else {
if (c == '0' && min_chars == 0) {
- pad_with_zeroes = true;
+ if (left_justified) {
+ WARN_PRINT("'0' flag ignored with '-' flag in string format");
+ } else {
+ pad_with_zeros = true;
+ }
} else {
min_chars *= 10;
min_chars += n;
@@ -4680,7 +4678,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Back to defaults:
min_chars = 0;
min_decimals = 6;
- pad_with_zeroes = false;
+ pad_with_zeros = false;
left_justified = false;
show_sign = false;
in_decimals = false;
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 1d302b65a7..48f2e45105 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -225,6 +225,7 @@ public:
bool operator==(const String &p_str) const;
bool operator!=(const String &p_str) const;
String operator+(const String &p_str) const;
+ String operator+(char32_t p_char) const;
String &operator+=(const String &);
String &operator+=(char32_t p_char);
@@ -522,10 +523,6 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St
#define TTRGET(m_value) TTR(m_value)
#else
-#define TTR(m_value) String()
-#define TTRN(m_value) String()
-#define DTR(m_value) String()
-#define DTRN(m_value) String()
#define TTRC(m_value) (m_value)
#define TTRGET(m_value) (m_value)
#endif
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index 1ecb81c2a2..7d3e31b5bc 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -215,7 +215,7 @@
T *instance; \
M method; \
SEMIC_SEP_LIST(PARAM_DECL, N); \
- virtual void call() { \
+ virtual void call() override { \
(instance->*method)(COMMA_SEP_LIST(ARG, N)); \
} \
};
@@ -227,7 +227,7 @@
T *instance; \
M method; \
SEMIC_SEP_LIST(PARAM_DECL, N); \
- virtual void call() { \
+ virtual void call() override { \
*ret = (instance->*method)(COMMA_SEP_LIST(ARG, N)); \
} \
};
@@ -238,7 +238,7 @@
T *instance; \
M method; \
SEMIC_SEP_LIST(PARAM_DECL, N); \
- virtual void call() { \
+ virtual void call() override { \
(instance->*method)(COMMA_SEP_LIST(ARG, N)); \
} \
};
@@ -311,9 +311,9 @@ class CommandQueueMT {
};
struct SyncCommand : public CommandBase {
- SyncSemaphore *sync_sem;
+ SyncSemaphore *sync_sem = nullptr;
- virtual void post() {
+ virtual void post() override {
sync_sem->sem.post();
}
};
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index 326616b607..f1ac32928f 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -86,13 +86,6 @@ private:
return reinterpret_cast<uint32_t *>(_ptr) - 1;
}
- _FORCE_INLINE_ T *_get_data() const {
- if (!_ptr) {
- return nullptr;
- }
- return reinterpret_cast<T *>(_ptr);
- }
-
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
return next_power_of_2(p_elements * sizeof(T));
}
@@ -128,11 +121,11 @@ public:
_FORCE_INLINE_ T *ptrw() {
_copy_on_write();
- return (T *)_get_data();
+ return _ptr;
}
_FORCE_INLINE_ const T *ptr() const {
- return _get_data();
+ return _ptr;
}
_FORCE_INLINE_ int size() const {
@@ -150,19 +143,19 @@ public:
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
ERR_FAIL_INDEX(p_index, size());
_copy_on_write();
- _get_data()[p_index] = p_elem;
+ _ptr[p_index] = p_elem;
}
_FORCE_INLINE_ T &get_m(int p_index) {
CRASH_BAD_INDEX(p_index, size());
_copy_on_write();
- return _get_data()[p_index];
+ return _ptr[p_index];
}
_FORCE_INLINE_ const T &get(int p_index) const {
CRASH_BAD_INDEX(p_index, size());
- return _get_data()[p_index];
+ return _ptr[p_index];
}
Error resize(int p_size);
@@ -249,7 +242,7 @@ uint32_t CowData<T>::_copy_on_write() {
} else {
for (uint32_t i = 0; i < current_size; i++) {
- memnew_placement(&_data[i], T(_get_data()[i]));
+ memnew_placement(&_data[i], T(_ptr[i]));
}
}
@@ -308,10 +301,8 @@ Error CowData<T>::resize(int p_size) {
// construct the newly created elements
if (!__has_trivial_constructor(T)) {
- T *elems = _get_data();
-
for (int i = *_get_size(); i < p_size; i++) {
- memnew_placement(&elems[i], T);
+ memnew_placement(&_ptr[i], T);
}
}
@@ -321,7 +312,7 @@ Error CowData<T>::resize(int p_size) {
if (!__has_trivial_destructor(T)) {
// deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) {
- T *t = &_get_data()[i];
+ T *t = &_ptr[i];
t->~T();
}
}
diff --git a/core/templates/map.h b/core/templates/map.h
index f228640a1e..c54da1dc03 100644
--- a/core/templates/map.h
+++ b/core/templates/map.h
@@ -178,7 +178,7 @@ public:
private:
struct _Data {
Element *_root = nullptr;
- Element *_nil;
+ Element *_nil = nullptr;
int size_cache = 0;
_FORCE_INLINE_ _Data() {
@@ -344,7 +344,7 @@ private:
void _insert_rb_fix(Element *p_new_node) {
Element *node = p_new_node;
Element *nparent = node->parent;
- Element *ngrand_parent;
+ Element *ngrand_parent = nullptr;
while (nparent->color == RED) {
ngrand_parent = nparent->parent;
@@ -500,7 +500,7 @@ private:
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
- Element *sibling;
+ Element *sibling = nullptr;
if (rp == rp->parent->left) {
rp->parent->left = node;
sibling = rp->parent->right;
diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h
index c91d27ebe1..25c21d1802 100644
--- a/core/templates/oa_hash_map.h
+++ b/core/templates/oa_hash_map.h
@@ -145,7 +145,7 @@ private:
uint32_t old_capacity = capacity;
// Capacity can't be 0.
- capacity = MAX(1, p_new_capacity);
+ capacity = MAX(1u, p_new_capacity);
TKey *old_keys = keys;
TValue *old_values = values;
@@ -246,13 +246,17 @@ public:
return false;
}
- /**
- * returns true if the value was found, false otherwise.
- *
- * if r_data is not nullptr then the value will be written to the object
- * it points to.
- */
- TValue *lookup_ptr(const TKey &p_key) const {
+ const TValue *lookup_ptr(const TKey &p_key) const {
+ uint32_t pos = 0;
+ bool exists = _lookup_pos(p_key, pos);
+
+ if (exists) {
+ return &values[pos];
+ }
+ return nullptr;
+ }
+
+ TValue *lookup_ptr(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
@@ -306,7 +310,7 @@ public:
bool valid;
const TKey *key;
- TValue *value;
+ TValue *value = nullptr;
private:
uint32_t pos;
@@ -367,7 +371,7 @@ public:
OAHashMap(uint32_t p_initial_capacity = 64) {
// Capacity can't be 0.
- capacity = MAX(1, p_initial_capacity);
+ capacity = MAX(1u, p_initial_capacity);
keys = static_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
values = static_cast<TValue *>(Memory::alloc_static(sizeof(TValue) * capacity));
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
index 5bc723787f..b9067e2edd 100644
--- a/core/templates/paged_allocator.h
+++ b/core/templates/paged_allocator.h
@@ -86,10 +86,10 @@ public:
}
p_mem->~T();
available_pool[allocs_available >> page_shift][allocs_available & page_mask] = p_mem;
+ allocs_available++;
if (thread_safe) {
spin_lock.unlock();
}
- allocs_available++;
}
void reset(bool p_allow_unfreed = false) {
diff --git a/core/templates/pooled_list.h b/core/templates/pooled_list.h
index 360fda81f8..f13156b292 100644
--- a/core/templates/pooled_list.h
+++ b/core/templates/pooled_list.h
@@ -28,16 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef POOLED_LIST_H
-#define POOLED_LIST_H
-
-#include "core/templates/local_vector.h"
+#pragma once
// Simple template to provide a pool with O(1) allocate and free.
// The freelist could alternatively be a linked list placed within the unused elements
// to use less memory, however a separate freelist is probably more cache friendly.
-//
-// NOTE: Take great care when using this with non POD types. The construction and destruction
+
+// NOTE : Take great care when using this with non POD types. The construction and destruction
// is done in the LocalVector, NOT as part of the pool. So requesting a new item does not guarantee
// a constructor is run, and free does not guarantee a destructor.
// You should generally handle clearing
@@ -45,33 +42,60 @@
// This is by design for fastest use in the BVH. If you want a more general pool
// that does call constructors / destructors on request / free, this should probably be
// a separate template.
-template <class T, bool force_trivial = false>
+
+// The zero_on_first_request feature is optional and is useful for e.g. pools of handles,
+// which may use a ref count which we want to be initialized to zero the first time a handle is created,
+// but left alone on subsequent allocations (as will typically be incremented).
+
+// Note that there is no function to compact the pool - this would
+// invalidate any existing pool IDs held externally.
+// Compaction can be done but would rely on a more complex method
+// of preferentially giving out lower IDs in the freelist first.
+
+#include "core/templates/local_vector.h"
+
+template <class T, class U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
class PooledList {
- LocalVector<T, uint32_t, force_trivial> list;
- LocalVector<uint32_t, uint32_t, true> freelist;
+ LocalVector<T, U, force_trivial> list;
+ LocalVector<U, U, true> freelist;
// not all list members are necessarily used
- int _used_size;
+ U _used_size;
public:
PooledList() {
_used_size = 0;
}
- int estimate_memory_use() const {
- return (list.size() * sizeof(T)) + (freelist.size() * sizeof(uint32_t));
+ // Use with care, in most cases you should make sure to
+ // free all elements first (i.e. _used_size would be zero),
+ // although it could also be used without this as an optimization
+ // in some cases.
+ void clear() {
+ list.clear();
+ freelist.clear();
+ _used_size = 0;
+ }
+
+ uint64_t estimate_memory_use() const {
+ return ((uint64_t)list.size() * sizeof(T)) + ((uint64_t)freelist.size() * sizeof(U));
}
- const T &operator[](uint32_t p_index) const {
+ const T &operator[](U p_index) const {
return list[p_index];
}
- T &operator[](uint32_t p_index) {
+ T &operator[](U p_index) {
return list[p_index];
}
- int size() const { return _used_size; }
+ // To be explicit in a pool there is a distinction
+ // between the number of elements that are currently
+ // in use, and the number of elements that have been reserved.
+ // Using size() would be vague.
+ U used_size() const { return _used_size; }
+ U reserved_size() const { return list.size(); }
- T *request(uint32_t &r_id) {
+ T *request(U &r_id) {
_used_size++;
if (freelist.size()) {
@@ -79,19 +103,106 @@ public:
int new_size = freelist.size() - 1;
r_id = freelist[new_size];
freelist.resize(new_size);
+
return &list[r_id];
}
r_id = list.size();
list.resize(r_id + 1);
+
+ static_assert((!zero_on_first_request) || (__is_pod(T)), "zero_on_first_request requires trivial type");
+ if (zero_on_first_request && __is_pod(T)) {
+ list[r_id] = {};
+ }
+
return &list[r_id];
}
- void free(const uint32_t &p_id) {
+ void free(const U &p_id) {
// should not be on free list already
- CRASH_COND(p_id >= list.size());
+ ERR_FAIL_UNSIGNED_INDEX(p_id, list.size());
freelist.push_back(p_id);
+ ERR_FAIL_COND_MSG(!_used_size, "_used_size has become out of sync, have you double freed an item?");
_used_size--;
}
};
-#endif // POOLED_LIST_H
+// a pooled list which automatically keeps a list of the active members
+template <class T, class U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
+class TrackedPooledList {
+public:
+ U pool_used_size() const { return _pool.used_size(); }
+ U pool_reserved_size() const { return _pool.reserved_size(); }
+ U active_size() const { return _active_list.size(); }
+
+ // use with care, see the earlier notes in the PooledList clear()
+ void clear() {
+ _pool.clear();
+ _active_list.clear();
+ _active_map.clear();
+ }
+
+ U get_active_id(U p_index) const {
+ return _active_list[p_index];
+ }
+
+ const T &get_active(U p_index) const {
+ return _pool[get_active_id(p_index)];
+ }
+
+ T &get_active(U p_index) {
+ return _pool[get_active_id(p_index)];
+ }
+
+ const T &operator[](U p_index) const {
+ return _pool[p_index];
+ }
+ T &operator[](U p_index) {
+ return _pool[p_index];
+ }
+
+ T *request(U &r_id) {
+ T *item = _pool.request(r_id);
+
+ // add to the active list
+ U active_list_id = _active_list.size();
+ _active_list.push_back(r_id);
+
+ // expand the active map (this should be in sync with the pool list
+ if (_pool.used_size() > _active_map.size()) {
+ _active_map.resize(_pool.used_size());
+ }
+
+ // store in the active map
+ _active_map[r_id] = active_list_id;
+
+ return item;
+ }
+
+ void free(const U &p_id) {
+ _pool.free(p_id);
+
+ // remove from the active list.
+ U list_id = _active_map[p_id];
+
+ // zero the _active map to detect bugs (only in debug?)
+ _active_map[p_id] = -1;
+
+ _active_list.remove_unordered(list_id);
+
+ // keep the replacement in sync with the correct list Id
+ if (list_id < _active_list.size()) {
+ // which pool id has been replaced in the active list
+ U replacement_id = _active_list[list_id];
+
+ // keep that replacements map up to date with the new position
+ _active_map[replacement_id] = list_id;
+ }
+ }
+
+ const LocalVector<U, U> &get_active_list() const { return _active_list; }
+
+private:
+ PooledList<T, U, force_trivial, zero_on_first_request> _pool;
+ LocalVector<U, U> _active_map;
+ LocalVector<U, U> _active_list;
+};
diff --git a/core/templates/safe_list.h b/core/templates/safe_list.h
index 53fc3fe5f9..e850f3bd5e 100644
--- a/core/templates/safe_list.h
+++ b/core/templates/safe_list.h
@@ -75,8 +75,8 @@ public:
class Iterator {
friend class SafeList;
- SafeListNode *cursor;
- SafeList *list;
+ SafeListNode *cursor = nullptr;
+ SafeList *list = nullptr;
Iterator(SafeListNode *p_cursor, SafeList *p_list) :
cursor(p_cursor), list(p_list) {
@@ -203,7 +203,7 @@ public:
}
// Calling this will cause zero to many deallocations.
- void maybe_cleanup() {
+ bool maybe_cleanup() {
SafeListNode *cursor = nullptr;
SafeListNode *new_graveyard_head = nullptr;
do {
@@ -212,7 +212,7 @@ public:
if (active_iterator_count.load() != 0) {
// It's not safe to clean up with an active iterator, because that iterator
// could be pointing to an element that we want to delete.
- return;
+ return false;
}
// Any iterator created after this point will never point to a deleted node.
// Swap it out with the current graveyard head.
@@ -225,6 +225,17 @@ public:
tmp->deletion_fn(tmp->val);
memdelete_allocator<SafeListNode, A>(tmp);
}
+ return true;
+ }
+
+ ~SafeList() {
+#ifdef DEBUG_ENABLED
+ if (!maybe_cleanup()) {
+ ERR_PRINT("There are still iterators around when destructing a SafeList. Memory will be leaked. This is a bug.");
+ }
+#else
+ maybe_cleanup();
+#endif
}
};
@@ -253,8 +264,8 @@ public:
class Iterator {
friend class SafeList;
- SafeListNode *cursor;
- SafeList *list;
+ SafeListNode *cursor = nullptr;
+ SafeList *list = nullptr;
public:
Iterator(SafeListNode *p_cursor, SafeList *p_list) :
@@ -353,11 +364,11 @@ public:
}
// Calling this will cause zero to many deallocations.
- void maybe_cleanup() {
+ bool maybe_cleanup() {
SafeListNode *cursor = graveyard_head;
if (active_iterator_count != 0) {
// It's not safe to clean up with an active iterator, because that iterator could be pointing to an element that we want to delete.
- return;
+ return false;
}
graveyard_head = nullptr;
// Our graveyard list is now unreachable by any active iterators, detached from the main graveyard head and ready for deletion.
@@ -367,6 +378,17 @@ public:
tmp->deletion_fn(tmp->val);
memdelete_allocator<SafeListNode, A>(tmp);
}
+ return true;
+ }
+
+ ~SafeList() {
+#ifdef DEBUG_ENABLED
+ if (!maybe_cleanup()) {
+ ERR_PRINT("There are still iterators around when destructing a SafeList. Memory will be leaked. This is a bug.");
+ }
+#else
+ maybe_cleanup();
+#endif
}
};
diff --git a/core/templates/self_list.h b/core/templates/self_list.h
index 7f2236fa3a..719b5f2e63 100644
--- a/core/templates/self_list.h
+++ b/core/templates/self_list.h
@@ -108,7 +108,7 @@ public:
private:
List *_root = nullptr;
- T *_self;
+ T *_self = nullptr;
SelfList<T> *_next = nullptr;
SelfList<T> *_prev = nullptr;
diff --git a/core/templates/set.h b/core/templates/set.h
index cdc6e8447d..a8a0a77712 100644
--- a/core/templates/set.h
+++ b/core/templates/set.h
@@ -328,7 +328,7 @@ private:
void _insert_rb_fix(Element *p_new_node) {
Element *node = p_new_node;
Element *nparent = node->parent;
- Element *ngrand_parent;
+ Element *ngrand_parent = nullptr;
while (nparent->color == RED) {
ngrand_parent = nparent->parent;
@@ -482,7 +482,7 @@ private:
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
- Element *sibling;
+ Element *sibling = nullptr;
if (rp == rp->parent->left) {
rp->parent->left = node;
sibling = rp->parent->right;
diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h
index 957af44f48..b0cebf04f1 100644
--- a/core/templates/thread_work_pool.h
+++ b/core/templates/thread_work_pool.h
@@ -52,7 +52,7 @@ class ThreadWorkPool {
C *instance;
M method;
U userdata;
- virtual void work() {
+ virtual void work() override {
while (true) {
uint32_t work_index = index->fetch_add(1, std::memory_order_relaxed);
if (work_index >= max_elements) {
@@ -68,7 +68,7 @@ class ThreadWorkPool {
Semaphore start;
Semaphore completed;
std::atomic<bool> exit;
- BaseWork *work;
+ BaseWork *work = nullptr;
};
ThreadData *threads = nullptr;
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 0877e04e01..d87e76139b 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -97,24 +97,29 @@ public:
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
- template <class C>
- void sort_custom() {
+ void sort() {
+ sort_custom<_DefaultComparator<T>>();
+ }
+
+ template <class Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, class... Args>
+ void sort_custom(Args &&...args) {
int len = _cowdata.size();
if (len == 0) {
return;
}
T *data = ptrw();
- SortArray<T, C> sorter;
+ SortArray<T, Comparator, Validate> sorter{ args... };
sorter.sort(data, len);
}
- void sort() {
- sort_custom<_DefaultComparator<T>>();
+ int bsearch(const T &p_value, bool p_before) {
+ return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
}
- int bsearch(const T &p_value, bool p_before) {
- SearchArray<T> search;
+ template <class Comparator, class Value, class... Args>
+ int bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
+ SearchArray<T, Comparator> search{ args... };
return search.bisect(ptrw(), size(), p_value, p_before);
}
diff --git a/core/typedefs.h b/core/typedefs.h
index 5929b5123b..510b39177c 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -89,34 +89,43 @@
#undef ERROR // override (really stupid) wingdi.h standard definition
#undef DELETE // override (another really stupid) winnt.h standard definition
#undef MessageBox // override winuser.h standard definition
-#undef MIN // override standard definition
-#undef MAX // override standard definition
-#undef CLAMP // override standard definition
#undef Error
#undef OK
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
+// Make room for our constexpr's below by overriding potential system-specific macros.
+#undef ABS
+#undef SIGN
+#undef MIN
+#undef MAX
+#undef CLAMP
+
// Generic ABS function, for math uses please use Math::abs.
-#ifndef ABS
-#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
-#endif
+template <typename T>
+constexpr T ABS(T m_v) {
+ return m_v < 0 ? -m_v : m_v;
+}
-#ifndef SIGN
-#define SIGN(m_v) (((m_v) == 0) ? (0.0) : (((m_v) < 0) ? (-1.0) : (+1.0)))
-#endif
+template <typename T>
+constexpr const T SIGN(const T m_v) {
+ return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
+}
-#ifndef MIN
-#define MIN(m_a, m_b) (((m_a) < (m_b)) ? (m_a) : (m_b))
-#endif
+template <typename T, typename T2>
+constexpr auto MIN(const T m_a, const T2 m_b) {
+ return m_a < m_b ? m_a : m_b;
+}
-#ifndef MAX
-#define MAX(m_a, m_b) (((m_a) > (m_b)) ? (m_a) : (m_b))
-#endif
+template <typename T, typename T2>
+constexpr auto MAX(const T m_a, const T2 m_b) {
+ return m_a > m_b ? m_a : m_b;
+}
-#ifndef CLAMP
-#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
-#endif
+template <typename T, typename T2, typename T3>
+constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
+ return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
+}
// Generic swap template.
#ifndef SWAP
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 1b39558dff..afc4acadf9 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -484,24 +484,8 @@ void Array::sort() {
_p->array.sort_custom<_ArrayVariantSort>();
}
-struct _ArrayVariantSortCustom {
- Callable func;
-
- _FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
- const Variant *args[2] = { &p_l, &p_r };
- Callable::CallError err;
- Variant res;
- func.call(args, 2, res, err);
- ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false,
- "Error calling sorting method: " + Variant::get_callable_error_text(func, args, 1, err));
- return res;
- }
-};
-
-void Array::sort_custom(Callable p_callable) {
- SortArray<Variant, _ArrayVariantSortCustom, true> avs;
- avs.compare.func = p_callable;
- avs.sort(_p->array.ptrw(), _p->array.size());
+void Array::sort_custom(const Callable &p_callable) {
+ _p->array.sort_custom<CallableComparator, true>(p_callable);
}
void Array::shuffle() {
@@ -524,13 +508,10 @@ int Array::bsearch(const Variant &p_value, bool p_before) {
return avs.bisect(_p->array.ptrw(), _p->array.size(), p_value, p_before);
}
-int Array::bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before) {
+int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1);
- SearchArray<Variant, _ArrayVariantSortCustom> avs;
- avs.compare.func = p_callable;
-
- return avs.bisect(_p->array.ptrw(), _p->array.size(), p_value, p_before);
+ return _p->array.bsearch_custom<CallableComparator>(p_value, p_before, p_callable);
}
void Array::reverse() {
diff --git a/core/variant/array.h b/core/variant/array.h
index 72bed5932c..ab5f7cd50f 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -82,10 +82,10 @@ public:
Variant back() const;
void sort();
- void sort_custom(Callable p_callable);
+ void sort_custom(const Callable &p_callable);
void shuffle();
int bsearch(const Variant &p_value, bool p_before = true);
- int bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before = true);
+ int bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before = true);
void reverse();
int find(const Variant &p_value, int p_from = 0) const;
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index b6fdb4d902..22a13b0fab 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -100,6 +100,10 @@ struct VariantCaster<const T &> {
_FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
*(int64_t *)p_ptr = (int64_t)p_val; \
} \
+ }; \
+ template <> \
+ struct ZeroInitializer<m_enum> { \
+ static void initialize(m_enum &value) { value = (m_enum)0; } \
};
// Object enum casts must go here
@@ -182,7 +186,7 @@ struct VariantCasterAndValidate {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
- !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
@@ -197,7 +201,7 @@ struct VariantCasterAndValidate<T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
- !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
@@ -212,7 +216,7 @@ struct VariantCasterAndValidate<const T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
- !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ !VariantObjectClassChecker<T>::check(*p_args[p_arg_idx])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 27792ce111..516b8f2d51 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -37,7 +37,7 @@
#include "core/object/script_language.h"
void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const {
- MessageQueue::get_singleton()->push_callable(*this, p_arguments, p_argcount);
+ MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount);
}
void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const {
@@ -59,7 +59,7 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu
return;
}
#endif
- r_return_value = obj->call(method, p_arguments, p_argcount, r_call_error);
+ r_return_value = obj->callp(method, p_arguments, p_argcount, r_call_error);
}
}
@@ -379,7 +379,7 @@ Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
return ERR_INVALID_DATA;
}
- return obj->emit_signal(name, p_arguments, p_argcount);
+ return obj->emit_signalp(name, p_arguments, p_argcount);
}
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
@@ -429,3 +429,13 @@ Signal::Signal(ObjectID p_object, const StringName &p_name) {
object = p_object;
name = p_name;
}
+
+bool CallableComparator::operator()(const Variant &p_l, const Variant &p_r) const {
+ const Variant *args[2] = { &p_l, &p_r };
+ Callable::CallError err;
+ Variant res;
+ func.call(args, 2, res, err);
+ ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false,
+ "Error calling compare method: " + Variant::get_callable_error_text(func, args, 1, err));
+ return res;
+}
diff --git a/core/variant/callable.h b/core/variant/callable.h
index c61870f194..6a760958d6 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -170,4 +170,10 @@ public:
Signal() {}
};
+struct CallableComparator {
+ const Callable &func;
+
+ bool operator()(const Variant &p_l, const Variant &p_r) const;
+};
+
#endif // CALLABLE_H
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index 797e8afede..1a400b4360 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -40,8 +40,8 @@ String CallableCustomBind::get_as_text() const {
}
bool CallableCustomBind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) {
- const CallableCustomBind *a = (const CallableCustomBind *)p_a;
- const CallableCustomBind *b = (const CallableCustomBind *)p_b;
+ const CallableCustomBind *a = static_cast<const CallableCustomBind *>(p_a);
+ const CallableCustomBind *b = static_cast<const CallableCustomBind *>(p_b);
if (!(a->callable != b->callable)) {
return false;
@@ -55,8 +55,8 @@ bool CallableCustomBind::_equal_func(const CallableCustom *p_a, const CallableCu
}
bool CallableCustomBind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) {
- const CallableCustomBind *a = (const CallableCustomBind *)p_a;
- const CallableCustomBind *b = (const CallableCustomBind *)p_b;
+ const CallableCustomBind *a = static_cast<const CallableCustomBind *>(p_a);
+ const CallableCustomBind *b = static_cast<const CallableCustomBind *>(p_b);
if (a->callable < b->callable) {
return true;
@@ -117,8 +117,8 @@ String CallableCustomUnbind::get_as_text() const {
}
bool CallableCustomUnbind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) {
- const CallableCustomUnbind *a = (const CallableCustomUnbind *)p_a;
- const CallableCustomUnbind *b = (const CallableCustomUnbind *)p_b;
+ const CallableCustomUnbind *a = static_cast<const CallableCustomUnbind *>(p_a);
+ const CallableCustomUnbind *b = static_cast<const CallableCustomUnbind *>(p_b);
if (!(a->callable != b->callable)) {
return false;
@@ -132,8 +132,8 @@ bool CallableCustomUnbind::_equal_func(const CallableCustom *p_a, const Callable
}
bool CallableCustomUnbind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) {
- const CallableCustomUnbind *a = (const CallableCustomUnbind *)p_a;
- const CallableCustomUnbind *b = (const CallableCustomUnbind *)p_b;
+ const CallableCustomUnbind *a = static_cast<const CallableCustomUnbind *>(p_a);
+ const CallableCustomUnbind *b = static_cast<const CallableCustomUnbind *>(p_b);
if (a->callable < b->callable) {
return true;
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
index 4f79a29629..a5c830e109 100644
--- a/core/variant/callable_bind.h
+++ b/core/variant/callable_bind.h
@@ -43,14 +43,14 @@ class CallableCustomBind : public CallableCustom {
public:
//for every type that inherits, these must always be the same for this type
- virtual uint32_t hash() const;
- virtual String get_as_text() const;
- virtual CompareEqualFunc get_compare_equal_func() const;
- virtual CompareLessFunc get_compare_less_func() const;
- virtual StringName get_method() const;
- virtual ObjectID get_object() const; //must always be able to provide an object
- virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const;
- virtual const Callable *get_base_comparator() const;
+ virtual uint32_t hash() const override;
+ virtual String get_as_text() const override;
+ virtual CompareEqualFunc get_compare_equal_func() const override;
+ virtual CompareLessFunc get_compare_less_func() const override;
+ virtual StringName get_method() const override;
+ virtual ObjectID get_object() const override; //must always be able to provide an object
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+ virtual const Callable *get_base_comparator() const override;
Callable get_callable() { return callable; }
Vector<Variant> get_binds() { return binds; }
@@ -68,14 +68,14 @@ class CallableCustomUnbind : public CallableCustom {
public:
//for every type that inherits, these must always be the same for this type
- virtual uint32_t hash() const;
- virtual String get_as_text() const;
- virtual CompareEqualFunc get_compare_equal_func() const;
- virtual CompareLessFunc get_compare_less_func() const;
- virtual StringName get_method() const;
- virtual ObjectID get_object() const; //must always be able to provide an object
- virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const;
- virtual const Callable *get_base_comparator() const;
+ virtual uint32_t hash() const override;
+ virtual String get_as_text() const override;
+ virtual CompareEqualFunc get_compare_equal_func() const override;
+ virtual CompareLessFunc get_compare_less_func() const override;
+ virtual StringName get_method() const override;
+ virtual ObjectID get_object() const override; //must always be able to provide an object
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+ virtual const Callable *get_base_comparator() const override;
Callable get_callable() { return callable; }
int get_unbinds() { return argcount; }
diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h
index 8e9fbbc0a4..ed68e0f6c9 100644
--- a/core/variant/native_ptr.h
+++ b/core/variant/native_ptr.h
@@ -124,6 +124,7 @@ struct PtrToArg<GDNativePtr<T>> {
}
};
+GDVIRTUAL_NATIVE_PTR(void)
GDVIRTUAL_NATIVE_PTR(AudioFrame)
GDVIRTUAL_NATIVE_PTR(bool)
GDVIRTUAL_NATIVE_PTR(char)
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index ee050cff4f..bacd0d19ce 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -281,4 +281,38 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) {
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
+template <typename T>
+struct ZeroInitializer {
+ static void initialize(T &value) {} //no initialization by default
+};
+
+template <>
+struct ZeroInitializer<bool> {
+ static void initialize(bool &value) { value = false; }
+};
+
+template <typename T>
+struct ZeroInitializer<T *> {
+ static void initialize(T *&value) { value = nullptr; }
+};
+
+#define ZERO_INITIALIZER_NUMBER(m_type) \
+ template <> \
+ struct ZeroInitializer<m_type> { \
+ static void initialize(m_type &value) { value = 0; } \
+ };
+
+ZERO_INITIALIZER_NUMBER(uint8_t)
+ZERO_INITIALIZER_NUMBER(int8_t)
+ZERO_INITIALIZER_NUMBER(uint16_t)
+ZERO_INITIALIZER_NUMBER(int16_t)
+ZERO_INITIALIZER_NUMBER(uint32_t)
+ZERO_INITIALIZER_NUMBER(int32_t)
+ZERO_INITIALIZER_NUMBER(uint64_t)
+ZERO_INITIALIZER_NUMBER(int64_t)
+ZERO_INITIALIZER_NUMBER(char16_t)
+ZERO_INITIALIZER_NUMBER(char32_t)
+ZERO_INITIALIZER_NUMBER(float)
+ZERO_INITIALIZER_NUMBER(double)
+
#endif // TYPE_INFO_H
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 3d11ed6303..e69bd88413 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -184,7 +184,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
if (p_type_from == p_type_to) {
return true;
}
- if (p_type_to == NIL && p_type_from != NIL) { //nil can convert to anything
+ if (p_type_to == NIL) { //nil can convert to anything
return true;
}
@@ -490,7 +490,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
if (p_type_from == p_type_to) {
return true;
}
- if (p_type_to == NIL && p_type_from != NIL) { //nil can convert to anything
+ if (p_type_to == NIL) { //nil can convert to anything
return true;
}
@@ -1620,6 +1620,27 @@ Variant::operator String() const {
return stringify(0);
}
+String stringify_variant_clean(const Variant p_variant, int recursion_count) {
+ String s = p_variant.stringify(recursion_count);
+
+ // Wrap strings in quotes to avoid ambiguity.
+ switch (p_variant.get_type()) {
+ case Variant::STRING: {
+ s = s.c_escape().quote();
+ } break;
+ case Variant::STRING_NAME: {
+ s = "&" + s.c_escape().quote();
+ } break;
+ case Variant::NODE_PATH: {
+ s = "^" + s.c_escape().quote();
+ } break;
+ default: {
+ } break;
+ }
+
+ return s;
+}
+
template <class T>
String stringify_vector(const T &vec, int recursion_count) {
String str("[");
@@ -1627,7 +1648,8 @@ String stringify_vector(const T &vec, int recursion_count) {
if (i > 0) {
str += ", ";
}
- str = str + Variant(vec[i]).stringify(recursion_count);
+
+ str += stringify_variant_clean(vec[i], recursion_count);
}
str += "]";
return str;
@@ -1691,8 +1713,8 @@ String Variant::stringify(int recursion_count) const {
recursion_count++;
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
_VariantStrPair sp;
- sp.key = E->get().stringify(recursion_count);
- sp.value = d[E->get()].stringify(recursion_count);
+ sp.key = stringify_variant_clean(E->get(), recursion_count);
+ sp.value = stringify_variant_clean(d[E->get()], recursion_count);
pairs.push_back(sp);
}
@@ -1741,8 +1763,7 @@ String Variant::stringify(int recursion_count) const {
return "[...]";
}
- String str = stringify_vector(arr, recursion_count);
- return str;
+ return stringify_vector(arr, recursion_count);
} break;
case OBJECT: {
@@ -1908,12 +1929,12 @@ Variant::operator Transform3D() const {
} else if (type == TRANSFORM2D) {
const Transform2D &t = *_data._transform2d;
Transform3D m;
- m.basis.elements[0][0] = t.elements[0][0];
- m.basis.elements[1][0] = t.elements[0][1];
- m.basis.elements[0][1] = t.elements[1][0];
- m.basis.elements[1][1] = t.elements[1][1];
- m.origin[0] = t.elements[2][0];
- m.origin[1] = t.elements[2][1];
+ m.basis.rows[0][0] = t.columns[0][0];
+ m.basis.rows[1][0] = t.columns[0][1];
+ m.basis.rows[0][1] = t.columns[1][0];
+ m.basis.rows[1][1] = t.columns[1][1];
+ m.origin[0] = t.columns[2][0];
+ m.origin[1] = t.columns[2][1];
return m;
} else {
return Transform3D();
@@ -1926,12 +1947,12 @@ Variant::operator Transform2D() const {
} else if (type == TRANSFORM3D) {
const Transform3D &t = *_data._transform3d;
Transform2D m;
- m.elements[0][0] = t.basis.elements[0][0];
- m.elements[0][1] = t.basis.elements[1][0];
- m.elements[1][0] = t.basis.elements[0][1];
- m.elements[1][1] = t.basis.elements[1][1];
- m.elements[2][0] = t.origin[0];
- m.elements[2][1] = t.origin[1];
+ m.columns[0][0] = t.basis.rows[0][0];
+ m.columns[0][1] = t.basis.rows[1][0];
+ m.columns[1][0] = t.basis.rows[0][1];
+ m.columns[1][1] = t.basis.rows[1][1];
+ m.columns[2][0] = t.origin[0];
+ m.columns[2][1] = t.origin[1];
return m;
} else {
return Transform2D();
@@ -1972,7 +1993,7 @@ Variant::operator ::RID() const {
}
#endif
Callable::CallError ce;
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::RID) {
return ret;
}
@@ -2790,7 +2811,7 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
uint32_t hash = 5831;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- hash = hash_djb2_one_float(_data._transform2d->elements[i][j], hash);
+ hash = hash_djb2_one_float(_data._transform2d->columns[i][j], hash);
}
}
@@ -2834,7 +2855,7 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
uint32_t hash = 5831;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- hash = hash_djb2_one_float(_data._basis->elements[i][j], hash);
+ hash = hash_djb2_one_float(_data._basis->rows[i][j], hash);
}
}
@@ -2845,7 +2866,7 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
uint32_t hash = 5831;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- hash = hash_djb2_one_float(_data._transform3d->basis.elements[i][j], hash);
+ hash = hash_djb2_one_float(_data._transform3d->basis.rows[i][j], hash);
}
hash = hash_djb2_one_float(_data._transform3d->origin[i], hash);
}
@@ -3112,7 +3133,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
Transform2D *r = p_variant._data._transform2d;
for (int i = 0; i < 3; i++) {
- if (!(hash_compare_vector2(l->elements[i], r->elements[i]))) {
+ if (!(hash_compare_vector2(l->columns[i], r->columns[i]))) {
return false;
}
}
@@ -3162,7 +3183,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
const Basis *r = p_variant._data._basis;
for (int i = 0; i < 3; i++) {
- if (!(hash_compare_vector3(l->elements[i], r->elements[i]))) {
+ if (!(hash_compare_vector3(l->rows[i], r->rows[i]))) {
return false;
}
}
@@ -3175,7 +3196,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
const Transform3D *r = p_variant._data._transform3d;
for (int i = 0; i < 3; i++) {
- if (!(hash_compare_vector3(l->basis.elements[i], r->basis.elements[i]))) {
+ if (!(hash_compare_vector3(l->basis.rows[i], r->basis.rows[i]))) {
return false;
}
}
@@ -3309,21 +3330,7 @@ bool Variant::is_shared() const {
return false;
}
-Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
-
- Variant ret;
- call(p_method, argptr, argc, ret, error);
-
+void Variant::_variant_call_error(const String &p_method, Callable::CallError &error) {
switch (error.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
String err = "Invalid type for argument #" + itos(error.argument) + ", expected '" + Variant::get_type_name(Variant::Type(error.expected)) + "'.";
@@ -3341,8 +3348,6 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
default: {
}
}
-
- return ret;
}
void Variant::construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct, void *p_construct_ud) {
@@ -3357,27 +3362,7 @@ String Variant::get_construct_string() const {
}
String Variant::get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
- String err_text;
-
- if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
- int errorarg = ce.argument;
- if (p_argptrs) {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
- } else {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
- }
- } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
- } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
- } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
- err_text = "Method not found.";
- } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
- err_text = "Instance is null";
- } else if (ce.error == Callable::CallError::CALL_OK) {
- return "Call OK";
- }
- return "'" + String(p_method) + "': " + err_text;
+ return get_call_error_text(nullptr, p_method, p_argptrs, p_argcount, ce);
}
String Variant::get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
@@ -3402,37 +3387,20 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
return "Call OK";
}
- String class_name = p_base->get_class();
- Ref<Resource> script = p_base->get_script();
- if (script.is_valid() && script->get_path().is_resource_file()) {
- class_name += "(" + script->get_path().get_file() + ")";
+ String base_text;
+ if (p_base) {
+ base_text = p_base->get_class();
+ Ref<Resource> script = p_base->get_script();
+ if (script.is_valid() && script->get_path().is_resource_file()) {
+ base_text += "(" + script->get_path().get_file() + ")";
+ }
+ base_text += "::";
}
- return "'" + class_name + "::" + String(p_method) + "': " + err_text;
+ return "'" + base_text + String(p_method) + "': " + err_text;
}
String Variant::get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
- String err_text;
-
- if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
- int errorarg = ce.argument;
- if (p_argptrs) {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
- } else {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
- }
- } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
- } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
- } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
- err_text = "Method not found.";
- } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
- err_text = "Instance is null";
- } else if (ce.error == Callable::CallError::CALL_OK) {
- return "Call OK";
- }
-
- return String(p_callable) + " : " + err_text;
+ return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, p_argcount, ce);
}
String vformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 836a67d942..475bf7158d 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -282,6 +282,14 @@ private:
static void _register_variant_utility_functions();
static void _unregister_variant_utility_functions();
+ void _variant_call_error(const String &p_method, Callable::CallError &error);
+
+ // Avoid accidental conversion. If you reached this point, it's because you most likely forgot to dereference
+ // a Variant pointer (so add * like this: *variant_pointer).
+
+ Variant(const Variant *) {}
+ Variant(const Variant **) {}
+
public:
_FORCE_INLINE_ Type get_type() const {
return type;
@@ -503,6 +511,7 @@ public:
Variant recursive_duplicate(bool p_deep, int recursion_count) const;
static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
+ static void sub(const Variant &a, const Variant &b, Variant &r_dst);
/* Built-In Methods */
@@ -527,8 +536,23 @@ public:
static int get_builtin_method_count(Variant::Type p_type);
static uint32_t get_builtin_method_hash(Variant::Type p_type, const StringName &p_method);
- void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
- Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant());
+ void callp(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ Variant ret;
+ callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), ret, cerr);
+ if (cerr.error != Callable::CallError::CALL_OK) {
+ _variant_call_error(p_method, cerr);
+ }
+ return ret;
+ }
static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index a5e89eec80..f4b2af5a94 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -949,20 +949,20 @@ struct _VariantCall {
_VariantCall::ConstantData *_VariantCall::constant_data = nullptr;
struct VariantBuiltInMethodInfo {
- void (*call)(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error);
- Variant::ValidatedBuiltInMethod validated_call;
- Variant::PTRBuiltInMethod ptrcall;
+ void (*call)(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) = nullptr;
+ Variant::ValidatedBuiltInMethod validated_call = nullptr;
+ Variant::PTRBuiltInMethod ptrcall = nullptr;
Vector<Variant> default_arguments;
Vector<String> argument_names;
- bool is_const;
- bool is_static;
- bool has_return_type;
- bool is_vararg;
+ bool is_const = false;
+ bool is_static = false;
+ bool has_return_type = false;
+ bool is_vararg = false;
Variant::Type return_type;
- int argument_count;
- Variant::Type (*get_argument_type)(int p_arg);
+ int argument_count = 0;
+ Variant::Type (*get_argument_type)(int p_arg) = nullptr;
};
typedef OAHashMap<StringName, VariantBuiltInMethodInfo> BuiltinMethodMap;
@@ -1003,7 +1003,7 @@ static void register_builtin_method(const Vector<String> &p_argnames, const Vect
builtin_method_names[T::get_base_type()].push_back(name);
}
-void Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+void Variant::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
if (type == Variant::OBJECT) {
//call object
Object *obj = _get_obj().obj;
@@ -1018,7 +1018,7 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg
}
#endif
- r_ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error);
+ r_ret = _get_obj().obj->callp(p_method, p_args, p_argcount, r_error);
//else if (type==Variant::METHOD) {
} else {
@@ -1239,10 +1239,10 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const {
void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) {
ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
- _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
+ const _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
#ifdef DEBUG_ENABLED
- for (List<StringName>::Element *E = cd.value_ordered.front(); E; E = E->next()) {
+ for (const List<StringName>::Element *E = cd.value_ordered.front(); E; E = E->next()) {
p_constants->push_back(E->get());
#else
for (const KeyValue<StringName, int> &E : cd.value) {
@@ -1251,7 +1251,7 @@ void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_c
}
#ifdef DEBUG_ENABLED
- for (List<StringName>::Element *E = cd.variant_value_ordered.front(); E; E = E->next()) {
+ for (const List<StringName>::Element *E = cd.variant_value_ordered.front(); E; E = E->next()) {
p_constants->push_back(E->get());
#else
for (const KeyValue<StringName, Variant> &E : cd.variant_value) {
@@ -1467,6 +1467,8 @@ static void _register_variant_builtin_methods() {
bind_static_method(String, num_scientific, sarray("number"), varray());
bind_static_method(String, num, sarray("number", "decimals"), varray(-1));
+ bind_static_method(String, num_int64, sarray("number", "base", "capitalize_hex"), varray(10, false));
+ bind_static_method(String, num_uint64, sarray("number", "base", "capitalize_hex"), varray(10, false));
bind_static_method(String, chr, sarray("char"), varray());
bind_static_method(String, humanize_size, sarray("size"), varray());
@@ -1493,7 +1495,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, max_axis_index, sarray(), varray());
bind_method(Vector2, min_axis_index, sarray(), varray());
bind_method(Vector2, move_toward, sarray("to", "delta"), varray());
- bind_method(Vector2, rotated, sarray("phi"), varray());
+ bind_method(Vector2, rotated, sarray("angle"), varray());
bind_method(Vector2, orthogonal, sarray(), varray());
bind_method(Vector2, floor, sarray(), varray());
bind_method(Vector2, ceil, sarray(), varray());
@@ -1573,7 +1575,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, inverse, sarray(), varray());
bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
- bind_method(Vector3, rotated, sarray("by_axis", "phi"), varray());
+ bind_method(Vector3, rotated, sarray("axis", "angle"), varray());
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());
@@ -1626,6 +1628,8 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, is_normalized, sarray(), varray());
bind_method(Quaternion, is_equal_approx, sarray("to"), varray());
bind_method(Quaternion, inverse, sarray(), varray());
+ bind_method(Quaternion, log, sarray(), varray());
+ bind_method(Quaternion, exp, sarray(), varray());
bind_method(Quaternion, angle_to, sarray("to"), varray());
bind_method(Quaternion, dot, sarray("with"), varray());
bind_method(Quaternion, slerp, sarray("to", "weight"), varray());
@@ -1652,6 +1656,8 @@ static void _register_variant_builtin_methods() {
bind_method(Color, darkened, sarray("amount"), varray());
bind_method(Color, blend, sarray("over"), varray());
bind_method(Color, get_luminance, sarray(), varray());
+ bind_method(Color, srgb_to_linear, sarray(), varray());
+ bind_method(Color, linear_to_srgb, sarray(), varray());
bind_method(Color, is_equal_approx, sarray("to"), varray());
@@ -1724,7 +1730,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, get_scale, sarray(), varray());
bind_method(Transform2D, get_skew, sarray(), varray());
bind_method(Transform2D, orthonormalized, sarray(), varray());
- bind_method(Transform2D, rotated, sarray("phi"), varray());
+ bind_method(Transform2D, rotated, sarray("angle"), varray());
bind_method(Transform2D, scaled, sarray("scale"), varray());
bind_method(Transform2D, translated, sarray("offset"), varray());
bind_method(Transform2D, basis_xform, sarray("v"), varray());
@@ -1742,7 +1748,7 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, transposed, sarray(), varray());
bind_method(Basis, orthonormalized, sarray(), varray());
bind_method(Basis, determinant, sarray(), varray());
- bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "phi"), varray());
+ bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "angle"), varray());
bind_method(Basis, scaled, sarray("scale"), varray());
bind_method(Basis, get_scale, sarray(), varray());
bind_method(Basis, get_euler, sarray("order"), varray(Basis::EULER_ORDER_YXZ));
@@ -1789,7 +1795,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, inverse, sarray(), varray());
bind_method(Transform3D, affine_inverse, sarray(), varray());
bind_method(Transform3D, orthonormalized, sarray(), varray());
- bind_method(Transform3D, rotated, sarray("axis", "phi"), varray());
+ bind_method(Transform3D, rotated, sarray("axis", "angle"), varray());
bind_method(Transform3D, scaled, sarray("scale"), varray());
bind_method(Transform3D, translated, sarray("offset"), varray());
bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 351f4ae253..78d5433d8c 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -31,11 +31,11 @@
#include "variant_construct.h"
struct VariantConstructData {
- void (*construct)(Variant &r_base, const Variant **p_args, Callable::CallError &r_error);
- Variant::ValidatedConstructor validated_construct;
- Variant::PTRConstructor ptr_construct;
- Variant::Type (*get_argument_type)(int);
- int argument_count;
+ void (*construct)(Variant &r_base, const Variant **p_args, Callable::CallError &r_error) = nullptr;
+ Variant::ValidatedConstructor validated_construct = nullptr;
+ Variant::PTRConstructor ptr_construct = nullptr;
+ Variant::Type (*get_argument_type)(int) = nullptr;
+ int argument_count = 0;
Vector<String> arg_names;
};
@@ -140,7 +140,7 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Basis>>(sarray());
add_constructor<VariantConstructor<Basis, Basis>>(sarray("from"));
add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from"));
- add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi"));
+ add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "angle"));
add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis"));
add_constructor<VariantConstructNoArgs<Transform3D>>(sarray());
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index 6027cb027e..ce2e9af04f 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -543,14 +543,12 @@ public:
class VariantConstructNoArgsObject {
public:
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
- VariantInternal::clear(&r_ret);
- VariantInternal::object_assign_null(&r_ret);
+ r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr.
r_error.error = Callable::CallError::CALL_OK;
}
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
- VariantInternal::clear(r_ret);
- VariantInternal::object_assign_null(r_ret);
+ *r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr.
}
static void ptr_construct(void *base, const void **p_args) {
PtrConstruct<Object *>::construct(nullptr, base);
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index cd1ae9f41f..35e0319aa3 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -177,6 +177,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT);
register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING);
register_op<OperatorEvaluatorAdd<String, char32_t, String>>(Variant::OP_ADD, Variant::INT, Variant::STRING);
+ register_op<OperatorEvaluatorAdd<String, String, char32_t>>(Variant::OP_ADD, Variant::STRING, Variant::INT);
register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2);
register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3);
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index e889a1bb40..259ca8a60d 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -162,6 +162,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
return OK;
}
if (ch == '\n') {
+ line++;
break;
}
}
@@ -344,7 +345,6 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
if (string_name) {
r_token.type = TK_STRING_NAME;
r_token.value = StringName(str);
- string_name = false; //reset
} else {
r_token.type = TK_STRING;
r_token.value = str;
@@ -807,7 +807,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
return ERR_PARSE_ERROR;
}
- REF ref = REF(Object::cast_to<RefCounted>(obj));
+ Ref<RefCounted> ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj));
get_token(p_stream, token, line, r_err_str);
if (token.type != TK_COMMA) {
@@ -888,7 +888,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
}
if (p_res_parser && id == "Resource" && p_res_parser->func) {
- RES res;
+ Ref<Resource> res;
Error err = p_res_parser->func(p_res_parser->userdata, p_stream, res, line, r_err_str);
if (err) {
return err;
@@ -896,7 +896,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = res;
} else if (p_res_parser && id == "ExtResource" && p_res_parser->ext_func) {
- RES res;
+ Ref<Resource> res;
Error err = p_res_parser->ext_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
if (err) {
return err;
@@ -904,7 +904,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = res;
} else if (p_res_parser && id == "SubResource" && p_res_parser->sub_func) {
- RES res;
+ Ref<Resource> res;
Error err = p_res_parser->sub_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
if (err) {
return err;
@@ -915,7 +915,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
get_token(p_stream, token, line, r_err_str);
if (token.type == TK_STRING) {
String path = token.value;
- RES res = ResourceLoader::load(path);
+ Ref<Resource> res = ResourceLoader::load(path);
if (res.is_null()) {
r_err_str = "Can't load resource at path: '" + path + "'.";
return ERR_PARSE_ERROR;
@@ -1402,6 +1402,7 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
return ERR_FILE_EOF;
}
if (ch == '\n') {
+ line++;
break;
}
}
@@ -1556,7 +1557,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
- s += rtos_fix(m3.elements[i][j]);
+ s += rtos_fix(m3.columns[i][j]);
}
}
@@ -1571,7 +1572,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
- s += rtos_fix(m3.elements[i][j]);
+ s += rtos_fix(m3.rows[i][j]);
}
}
@@ -1587,7 +1588,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
- s += rtos_fix(m3.elements[i][j]);
+ s += rtos_fix(m3.rows[i][j]);
}
}
@@ -1625,7 +1626,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
break; // don't save it
}
- RES res = p_variant;
+ Ref<Resource> res = p_variant;
if (res.is_valid()) {
//is resource
String res_text;
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
index e5585076c2..70ca8d8cb5 100644
--- a/core/variant/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -49,11 +49,11 @@ public:
};
struct StreamFile : public Stream {
- FileAccess *f = nullptr;
+ Ref<FileAccess> f;
- virtual char32_t get_char();
- virtual bool is_utf8() const;
- virtual bool is_eof() const;
+ virtual char32_t get_char() override;
+ virtual bool is_utf8() const override;
+ virtual bool is_eof() const override;
StreamFile() {}
};
@@ -62,9 +62,9 @@ public:
String s;
int pos = 0;
- virtual char32_t get_char();
- virtual bool is_utf8() const;
- virtual bool is_eof() const;
+ virtual char32_t get_char() override;
+ virtual bool is_utf8() const override;
+ virtual bool is_eof() const override;
StreamString() {}
};
@@ -138,7 +138,7 @@ public:
class VariantWriter {
public:
typedef Error (*StoreStringFunc)(void *ud, const String &p_string);
- typedef String (*EncodeResourceFunc)(void *ud, const RES &p_resource);
+ typedef String (*EncodeResourceFunc)(void *ud, const Ref<Resource> &p_resource);
static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int recursion_count = 0);
static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr);
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index fa8d26a72b..6023e4d129 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -789,8 +789,8 @@ INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3)
INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quaternion, double, real_t, 4)
INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4)
-INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .elements, 3)
-INDEXED_SETGET_STRUCT_BULTIN_FUNC(Basis, Vector3, set_axis, get_axis, 3)
+INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .columns, 3)
+INDEXED_SETGET_STRUCT_BULTIN_FUNC(Basis, Vector3, set_column, get_column, 3)
INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedByteArray, int64_t, uint8_t)
INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt32Array, int64_t, int32_t)
@@ -805,16 +805,16 @@ INDEXED_SETGET_STRUCT_TYPED(PackedColorArray, Color)
INDEXED_SETGET_STRUCT_DICT(Dictionary)
struct VariantIndexedSetterGetterInfo {
- void (*setter)(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob);
- void (*getter)(const Variant *base, int64_t index, Variant *value, bool *oob);
+ void (*setter)(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) = nullptr;
+ void (*getter)(const Variant *base, int64_t index, Variant *value, bool *oob) = nullptr;
- Variant::ValidatedIndexedSetter validated_setter;
- Variant::ValidatedIndexedGetter validated_getter;
+ Variant::ValidatedIndexedSetter validated_setter = nullptr;
+ Variant::ValidatedIndexedGetter validated_getter = nullptr;
- Variant::PTRIndexedSetter ptr_setter;
- Variant::PTRIndexedGetter ptr_getter;
+ Variant::PTRIndexedSetter ptr_setter = nullptr;
+ Variant::PTRIndexedGetter ptr_getter = nullptr;
- uint64_t (*get_indexed_size)(const Variant *base);
+ uint64_t (*get_indexed_size)(const Variant *base) = nullptr;
Variant::Type index_type;
@@ -1018,13 +1018,13 @@ struct VariantKeyedSetGetObject {
};
struct VariantKeyedSetterGetterInfo {
- Variant::ValidatedKeyedSetter validated_setter;
- Variant::ValidatedKeyedGetter validated_getter;
- Variant::ValidatedKeyedChecker validated_checker;
+ Variant::ValidatedKeyedSetter validated_setter = nullptr;
+ Variant::ValidatedKeyedGetter validated_getter = nullptr;
+ Variant::ValidatedKeyedChecker validated_checker = nullptr;
- Variant::PTRKeyedSetter ptr_setter;
- Variant::PTRKeyedGetter ptr_getter;
- Variant::PTRKeyedChecker ptr_checker;
+ Variant::PTRKeyedSetter ptr_setter = nullptr;
+ Variant::PTRKeyedGetter ptr_getter = nullptr;
+ Variant::PTRKeyedChecker ptr_checker = nullptr;
bool valid = false;
};
@@ -1277,7 +1277,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
ref.push_back(r_iter);
Variant vref = ref;
const Variant *refp[] = { &vref };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce);
if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
valid = false;
@@ -1504,7 +1504,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const {
ref.push_back(r_iter);
Variant vref = ref;
const Variant *refp[] = { &vref };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce);
if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
valid = false;
@@ -1686,7 +1686,7 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
Callable::CallError ce;
ce.error = Callable::CallError::CALL_OK;
const Variant *refp[] = { &r_iter };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce);
+ Variant ret = _get_obj().obj->callp(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_valid = false;
@@ -1868,6 +1868,110 @@ Variant Variant::recursive_duplicate(bool p_deep, int recursion_count) const {
}
}
+void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) {
+ if (a.type != b.type) {
+ return;
+ }
+
+ switch (a.type) {
+ case NIL: {
+ r_dst = Variant();
+ }
+ return;
+ case INT: {
+ int64_t va = a._data._int;
+ int64_t vb = b._data._int;
+ r_dst = int(va - vb);
+ }
+ return;
+ case FLOAT: {
+ double ra = a._data._float;
+ double rb = b._data._float;
+ r_dst = ra - rb;
+ }
+ return;
+ case VECTOR2: {
+ r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) - *reinterpret_cast<const Vector2 *>(b._data._mem);
+ }
+ return;
+ case VECTOR2I: {
+ int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
+ r_dst = Vector2i(int32_t(vax - vbx), int32_t(vay - vby));
+ }
+ return;
+ case RECT2: {
+ const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
+ const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
+ r_dst = Rect2(ra->position - rb->position, ra->size - rb->size);
+ }
+ return;
+ case RECT2I: {
+ const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
+ const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
+
+ int32_t vax = ra->position.x;
+ int32_t vay = ra->position.y;
+ int32_t vbx = ra->size.x;
+ int32_t vby = ra->size.y;
+ int32_t vcx = rb->position.x;
+ int32_t vcy = rb->position.y;
+ int32_t vdx = rb->size.x;
+ int32_t vdy = rb->size.y;
+
+ r_dst = Rect2i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy));
+ }
+ return;
+ case VECTOR3: {
+ r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) - *reinterpret_cast<const Vector3 *>(b._data._mem);
+ }
+ return;
+ case VECTOR3I: {
+ int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
+ int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
+ int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
+ r_dst = Vector3i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz));
+ }
+ return;
+ case AABB: {
+ const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
+ const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
+ r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size);
+ }
+ return;
+ case QUATERNION: {
+ Quaternion empty_rot;
+ const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
+ const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
+ r_dst = (*qb).inverse() * *qa;
+ }
+ return;
+ case COLOR: {
+ const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
+ const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
+ float new_r = ca->r - cb->r;
+ float new_g = ca->g - cb->g;
+ float new_b = ca->b - cb->b;
+ float new_a = ca->a - cb->a;
+ new_r = new_r > 1.0 ? 1.0 : new_r;
+ new_g = new_g > 1.0 ? 1.0 : new_g;
+ new_b = new_b > 1.0 ? 1.0 : new_b;
+ new_a = new_a > 1.0 ? 1.0 : new_a;
+ r_dst = Color(new_r, new_g, new_b, new_a);
+ }
+ return;
+ default: {
+ r_dst = a;
+ }
+ return;
+ }
+}
+
void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) {
if (a.type != b.type) {
if (a.is_num() && b.is_num()) {
diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h
index 28277fa5d0..3b95f0531b 100644
--- a/core/variant/variant_setget.h
+++ b/core/variant/variant_setget.h
@@ -293,9 +293,9 @@ SETGET_STRUCT(AABB, Vector3, position)
SETGET_STRUCT(AABB, Vector3, size)
SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end)
-SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, elements[0])
-SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, elements[1])
-SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, elements[2])
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, columns[0])
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, columns[1])
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, columns[2])
SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x)
SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y)
@@ -308,9 +308,9 @@ SETGET_NUMBER_STRUCT(Quaternion, double, y)
SETGET_NUMBER_STRUCT(Quaternion, double, z)
SETGET_NUMBER_STRUCT(Quaternion, double, w)
-SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0)
-SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1)
-SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2)
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_column, get_column, 0)
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_column, get_column, 1)
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_column, get_column, 2)
SETGET_STRUCT(Transform3D, Basis, basis)
SETGET_STRUCT(Transform3D, Vector3, origin)
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index e83c71098d..66badce268 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -219,10 +219,6 @@ struct VariantUtilityFunctions {
return Math::step_decimals(step);
}
- static inline int range_step_decimals(float step) {
- return Math::range_step_decimals(step);
- }
-
static inline double snapped(double value, double step) {
return Math::snapped(value, step);
}
@@ -439,7 +435,7 @@ struct VariantUtilityFunctions {
r_error.error = Callable::CallError::CALL_OK;
if (obj.is_ref_counted()) {
Ref<WeakRef> wref = memnew(WeakRef);
- REF r = obj;
+ Ref<RefCounted> r = obj;
if (r.is_valid()) {
wref->set_ref(r);
}
@@ -474,20 +470,20 @@ struct VariantUtilityFunctions {
r_error.argument = 1;
return String();
}
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
if (i == 0) {
- str = os;
+ s = os;
} else {
- str += os;
+ s += os;
}
}
r_error.error = Callable::CallError::CALL_OK;
- return str;
+ return s;
}
static inline String error_string(Error error) {
@@ -499,98 +495,98 @@ struct VariantUtilityFunctions {
}
static inline void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
if (i == 0) {
- str = os;
+ s = os;
} else {
- str += os;
+ s += os;
}
}
- print_line(str);
+ print_line(s);
r_error.error = Callable::CallError::CALL_OK;
}
static inline void print_verbose(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
if (OS::get_singleton()->is_stdout_verbose()) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
if (i == 0) {
- str = os;
+ s = os;
} else {
- str += os;
+ s += os;
}
}
// No need to use `print_verbose()` as this call already only happens
// when verbose mode is enabled. This avoids performing string argument concatenation
// when not needed.
- print_line(str);
+ print_line(s);
}
r_error.error = Callable::CallError::CALL_OK;
}
static inline void printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
if (i == 0) {
- str = os;
+ s = os;
} else {
- str += os;
+ s += os;
}
}
- print_error(str);
+ print_error(s);
r_error.error = Callable::CallError::CALL_OK;
}
static inline void printt(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
if (i) {
- str += "\t";
+ s += "\t";
}
- str += p_args[i]->operator String();
+ s += p_args[i]->operator String();
}
- print_line(str);
+ print_line(s);
r_error.error = Callable::CallError::CALL_OK;
}
static inline void prints(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
if (i) {
- str += " ";
+ s += " ";
}
- str += p_args[i]->operator String();
+ s += p_args[i]->operator String();
}
- print_line(str);
+ print_line(s);
r_error.error = Callable::CallError::CALL_OK;
}
static inline void printraw(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
if (i == 0) {
- str = os;
+ s = os;
} else {
- str += os;
+ s += os;
}
}
- OS::get_singleton()->print("%s", str.utf8().get_data());
+ OS::get_singleton()->print("%s", s.utf8().get_data());
r_error.error = Callable::CallError::CALL_OK;
}
@@ -599,18 +595,18 @@ struct VariantUtilityFunctions {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 1;
}
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
if (i == 0) {
- str = os;
+ s = os;
} else {
- str += os;
+ s += os;
}
}
- ERR_PRINT(str);
+ ERR_PRINT(s);
r_error.error = Callable::CallError::CALL_OK;
}
@@ -619,18 +615,18 @@ struct VariantUtilityFunctions {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 1;
}
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
if (i == 0) {
- str = os;
+ s = os;
} else {
- str += os;
+ s += os;
}
}
- WARN_PRINT(str);
+ WARN_PRINT(s);
r_error.error = Callable::CallError::CALL_OK;
}
@@ -1114,14 +1110,14 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) {
register_utility_function<Func_##m_func>(#m_func, m_args)
struct VariantUtilityFunctionInfo {
- void (*call_utility)(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant::ValidatedUtilityFunction validated_call_utility;
- Variant::PTRUtilityFunction ptr_call_utility;
+ void (*call_utility)(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = nullptr;
+ Variant::ValidatedUtilityFunction validated_call_utility = nullptr;
+ Variant::PTRUtilityFunction ptr_call_utility = nullptr;
Vector<String> argnames;
- bool is_vararg;
- bool returns_value;
- int argcount;
- Variant::Type (*get_arg_type)(int);
+ bool is_vararg = false;
+ bool returns_value = false;
+ int argcount = 0;
+ Variant::Type (*get_arg_type)(int) = nullptr;
Variant::Type return_type;
Variant::UtilityFunctionType type;
};
@@ -1204,7 +1200,6 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(range_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);