diff options
Diffstat (limited to 'core')
103 files changed, 2896 insertions, 2737 deletions
diff --git a/core/SCsub b/core/SCsub index 1379e9df9b..df3e7a547a 100644 --- a/core/SCsub +++ b/core/SCsub @@ -129,6 +129,9 @@ if env["builtin_zstd"]: "decompress/zstd_decompress_block.c", "decompress/zstd_decompress.c", ] + if env["platform"] in ["android", "iphone", "linuxbsd", "osx"]: + # Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h + thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S") thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources] env_thirdparty.Prepend(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"]) diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index ff5ff83bf8..7145e628c1 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -41,7 +41,6 @@ #include "core/os/keyboard.h" #include "core/variant/variant_parser.h" #include "core/version.h" - #include "modules/modules_enabled.gen.h" // For mono. const String ProjectSettings::PROJECT_DATA_DIR_NAME_SUFFIX = "godot"; @@ -205,6 +204,11 @@ void ProjectSettings::set_as_basic(const String &p_name, bool p_basic) { props[p_name].basic = p_basic; } +void ProjectSettings::set_as_internal(const String &p_name, bool p_internal) { + ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + props[p_name].internal = p_internal; +} + void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) { ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); #ifdef DEBUG_METHODS_ENABLED @@ -344,7 +348,7 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const { vc.name = E.key; vc.order = v->order; vc.type = v->variant.get_type(); - if (vc.name.begins_with("input/") || vc.name.begins_with("import/") || vc.name.begins_with("export/") || vc.name.begins_with("/remap") || vc.name.begins_with("/locale") || vc.name.begins_with("/autoload")) { + if (v->internal || vc.name.begins_with("input/") || vc.name.begins_with("importer_defaults/") || vc.name.begins_with("import/") || vc.name.begins_with("autoload/") || vc.name.begins_with("editor_plugins/") || vc.name.begins_with("shader_globals/")) { vc.flags = PROPERTY_USAGE_STORAGE; } else { vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE; @@ -890,7 +894,7 @@ Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other par Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) { ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Project settings save path cannot be empty."); - PackedStringArray project_features = has_setting("application/config/features") ? (PackedStringArray)get_setting("application/config/features") : PackedStringArray(); + PackedStringArray project_features = get_setting("application/config/features"); // If there is no feature list currently present, force one to generate. if (project_features.is_empty()) { project_features = ProjectSettings::get_required_features(); @@ -994,7 +998,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust } } -Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs, bool p_basic) { +Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs, bool p_basic, bool p_internal) { Variant ret; if (!ProjectSettings::get_singleton()->has_setting(p_var)) { ProjectSettings::get_singleton()->set(p_var, p_default); @@ -1006,6 +1010,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar ProjectSettings::get_singleton()->set_as_basic(p_var, p_basic); ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed); ProjectSettings::get_singleton()->set_ignore_value_in_docs(p_var, p_ignore_value_in_docs); + ProjectSettings::get_singleton()->set_as_internal(p_var, p_internal); return ret; } @@ -1151,7 +1156,7 @@ void ProjectSettings::_add_builtin_input_map() { action["events"] = events; String action_name = "input/" + E.key; - GLOBAL_DEF(action_name, action); + GLOBAL_DEF_INTERNAL(action_name, action); input_presets.push_back(action_name); } } @@ -1194,6 +1199,10 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres"); custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"); + GLOBAL_DEF_RST("audio/general/2d_panning_strength", 1.0f); + custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01"); + GLOBAL_DEF_RST("audio/general/3d_panning_strength", 1.0f); + custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01"); PackedStringArray extensions = PackedStringArray(); extensions.push_back("gd"); @@ -1235,6 +1244,11 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("compression/formats/gzip/compression_level", Compression::gzip_level); custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"); + + // These properties will not show up in the dialog nor in the documentation. If you want to exclude whole groups, see _get_property_list() method. + GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray()); + GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray()); + GLOBAL_DEF_INTERNAL("internationalization/locale/translations", PackedStringArray()); } ProjectSettings::~ProjectSettings() { diff --git a/core/config/project_settings.h b/core/config/project_settings.h index d9b1a9b81b..c3992a4db2 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -62,6 +62,7 @@ protected: int order = 0; bool persist = false; bool basic = false; + bool internal = false; Variant variant; Variant initial; bool hide_from_editor = false; @@ -141,6 +142,7 @@ public: void set_initial_value(const String &p_name, const Variant &p_value); void set_as_basic(const String &p_name, bool p_basic); + void set_as_internal(const String &p_name, bool p_internal); void set_restart_if_changed(const String &p_name, bool p_restart); void set_ignore_value_in_docs(const String &p_name, bool p_ignore); bool get_ignore_value_in_docs(const String &p_name) const; @@ -191,8 +193,8 @@ public: ~ProjectSettings(); }; -//not a macro any longer -Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false); +// Not a macro any longer. +Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false); #define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value) #define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true) #define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true) @@ -204,4 +206,6 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar #define GLOBAL_DEF_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true, true) #define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true) +#define GLOBAL_DEF_INTERNAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, false, true) + #endif // PROJECT_SETTINGS_H diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 194c7fdefd..26ecd41353 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -83,6 +83,14 @@ Vector<String> ResourceLoader::get_recognized_extensions_for_type(const String & return ret; } +void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) { + ::ResourceLoader::add_resource_format_loader(p_format_loader, p_at_front); +} + +void ResourceLoader::remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader) { + ::ResourceLoader::remove_resource_format_loader(p_format_loader); +} + void ResourceLoader::set_abort_on_missing_resources(bool p_abort) { ::ResourceLoader::set_abort_on_missing_resources(p_abort); } @@ -119,6 +127,8 @@ void ResourceLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "cache_mode"), &ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE)); ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &ResourceLoader::get_recognized_extensions_for_type); + ClassDB::bind_method(D_METHOD("add_resource_format_loader", "format_loader", "at_front"), &ResourceLoader::add_resource_format_loader, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("remove_resource_format_loader", "format_loader"), &ResourceLoader::remove_resource_format_loader); ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &ResourceLoader::set_abort_on_missing_resources); ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &ResourceLoader::get_dependencies); ClassDB::bind_method(D_METHOD("has_cached", "path"), &ResourceLoader::has_cached); @@ -137,7 +147,7 @@ void ResourceLoader::_bind_methods() { ////// ResourceSaver ////// -Error ResourceSaver::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { +Error ResourceSaver::save(const String &p_path, const Ref<Resource> &p_resource, BitField<SaverFlags> 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); } @@ -153,20 +163,30 @@ Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_r return ret; } +void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) { + ::ResourceSaver::add_resource_format_saver(p_format_saver, p_at_front); +} + +void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) { + ::ResourceSaver::remove_resource_format_saver(p_format_saver); +} + ResourceSaver *ResourceSaver::singleton = nullptr; void ResourceSaver::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("add_resource_format_saver", "format_saver", "at_front"), &ResourceSaver::add_resource_format_saver, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("remove_resource_format_saver", "format_saver"), &ResourceSaver::remove_resource_format_saver); - BIND_ENUM_CONSTANT(FLAG_NONE); - BIND_ENUM_CONSTANT(FLAG_RELATIVE_PATHS); - BIND_ENUM_CONSTANT(FLAG_BUNDLE_RESOURCES); - BIND_ENUM_CONSTANT(FLAG_CHANGE_PATH); - BIND_ENUM_CONSTANT(FLAG_OMIT_EDITOR_PROPERTIES); - BIND_ENUM_CONSTANT(FLAG_SAVE_BIG_ENDIAN); - BIND_ENUM_CONSTANT(FLAG_COMPRESS); - BIND_ENUM_CONSTANT(FLAG_REPLACE_SUBRESOURCE_PATHS); + BIND_BITFIELD_FLAG(FLAG_NONE); + BIND_BITFIELD_FLAG(FLAG_RELATIVE_PATHS); + BIND_BITFIELD_FLAG(FLAG_BUNDLE_RESOURCES); + BIND_BITFIELD_FLAG(FLAG_CHANGE_PATH); + BIND_BITFIELD_FLAG(FLAG_OMIT_EDITOR_PROPERTIES); + BIND_BITFIELD_FLAG(FLAG_SAVE_BIG_ENDIAN); + BIND_BITFIELD_FLAG(FLAG_COMPRESS); + BIND_BITFIELD_FLAG(FLAG_REPLACE_SUBRESOURCE_PATHS); } ////// OS ////// @@ -1820,60 +1840,26 @@ void Thread::_start_func(void *ud) { ERR_FAIL_MSG(vformat("Could not call function '%s' on previously freed instance to start thread %s.", t->target_callable.get_method(), t->get_id())); } - Callable::CallError ce; - const Variant *arg[1] = { &t->userdata }; - int argc = 0; - if (arg[0]->get_type() != Variant::NIL) { - // Just pass to the target function whatever came as user data - argc = 1; - } else { - // There are two cases of null user data: - // a) The target function has zero parameters and the caller is just honoring that. - // b) The target function has at least one parameter with no default and the caller is - // leveraging the fact that user data defaults to null in Thread.start(). - // We care about the case of more than one parameter because, even if a thread - // function can have one at most, out mindset here is to do our best with the - // only/first one and let the call handle any other error conditions, like too - // much arguments. - // We must check if we are in case b). - int target_param_count = 0; - int target_default_arg_count = 0; - Ref<Script> script = target_instance->get_script(); - if (script.is_valid()) { - MethodInfo mi = script->get_method_info(t->target_callable.get_method()); - target_param_count = mi.arguments.size(); - target_default_arg_count = mi.default_arguments.size(); - } else { - MethodBind *method = ClassDB::get_method(target_instance->get_class_name(), t->target_callable.get_method()); - if (method) { - target_param_count = method->get_argument_count(); - target_default_arg_count = method->get_default_argument_count(); - } - } - if (target_param_count >= 1 && target_default_arg_count < target_param_count) { - argc = 1; - } - } + String func_name = t->target_callable.is_custom() ? t->target_callable.get_custom()->get_as_text() : String(t->target_callable.get_method()); + ::Thread::set_name(func_name); - ::Thread::set_name(t->target_callable.get_method()); - - t->target_callable.call(arg, argc, t->ret, ce); + Callable::CallError ce; + t->target_callable.call(nullptr, 0, t->ret, ce); if (ce.error != Callable::CallError::CALL_OK) { t->running.clear(); - ERR_FAIL_MSG("Could not call function '" + t->target_callable.get_method().operator String() + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, arg, argc, ce) + "."); + ERR_FAIL_MSG("Could not call function '" + func_name + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce) + "."); } t->running.clear(); } -Error Thread::start(const Callable &p_callable, const Variant &p_userdata, Priority p_priority) { +Error Thread::start(const Callable &p_callable, Priority p_priority) { ERR_FAIL_COND_V_MSG(is_started(), ERR_ALREADY_IN_USE, "Thread already started."); ERR_FAIL_COND_V(!p_callable.is_valid(), ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER); ret = Variant(); target_callable = p_callable; - userdata = p_userdata; running.set(); Ref<Thread> *ud = memnew(Ref<Thread>(this)); @@ -1902,13 +1888,12 @@ Variant Thread::wait_to_finish() { thread.wait_to_finish(); Variant r = ret; target_callable = Callable(); - userdata = Variant(); return r; } void Thread::_bind_methods() { - ClassDB::bind_method(D_METHOD("start", "callable", "userdata", "priority"), &Thread::start, DEFVAL(Variant()), DEFVAL(PRIORITY_NORMAL)); + ClassDB::bind_method(D_METHOD("start", "callable", "priority"), &Thread::start, DEFVAL(PRIORITY_NORMAL)); ClassDB::bind_method(D_METHOD("get_id"), &Thread::get_id); ClassDB::bind_method(D_METHOD("is_started"), &Thread::is_started); ClassDB::bind_method(D_METHOD("is_alive"), &Thread::is_alive); @@ -2076,9 +2061,9 @@ bool ClassDB::has_integer_constant(const StringName &p_class, const StringName & return success; } -int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name) const { +int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name) const { bool found; - int c = ::ClassDB::get_integer_constant(p_class, p_name, &found); + int64_t c = ::ClassDB::get_integer_constant(p_class, p_name, &found); ERR_FAIL_COND_V(!found, 0); return c; } diff --git a/core/core_bind.h b/core/core_bind.h index e4d15d5c9d..c116ac4986 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -77,6 +77,8 @@ public: 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 add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front); + void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader); void set_abort_on_missing_resources(bool p_abort); PackedStringArray get_dependencies(const String &p_path); bool has_cached(const String &p_path); @@ -107,8 +109,10 @@ public: static ResourceSaver *get_singleton() { return singleton; } - Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags); + Error save(const String &p_path, const Ref<Resource> &p_resource, BitField<SaverFlags> p_flags); Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource); + void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front); + void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver); ResourceSaver() { singleton = this; } }; @@ -551,7 +555,6 @@ class Thread : public RefCounted { protected: Variant ret; - Variant userdata; SafeFlag running; Callable target_callable; ::Thread thread; @@ -566,7 +569,7 @@ public: PRIORITY_MAX }; - Error start(const Callable &p_callable, const Variant &p_userdata = Variant(), Priority p_priority = PRIORITY_NORMAL); + Error start(const Callable &p_callable, Priority p_priority = PRIORITY_NORMAL); String get_id() const; bool is_started() const; bool is_alive() const; @@ -604,7 +607,7 @@ 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; + int64_t get_integer_constant(const StringName &p_class, const StringName &p_name) 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; @@ -716,7 +719,7 @@ public: VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus); VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode); -VARIANT_ENUM_CAST(core_bind::ResourceSaver::SaverFlags); +VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags); VARIANT_ENUM_CAST(core_bind::OS::VideoDriver); VARIANT_ENUM_CAST(core_bind::OS::Weekday); diff --git a/core/core_constants.cpp b/core/core_constants.cpp index a53929a3af..1753efad60 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -42,19 +42,19 @@ struct _CoreConstant { bool ignore_value_in_docs = false; #endif const char *name = nullptr; - int value = 0; + int64_t value = 0; _CoreConstant() {} #ifdef DEBUG_METHODS_ENABLED - _CoreConstant(const StringName &p_enum_name, const char *p_name, int p_value, bool p_ignore_value_in_docs = false) : + _CoreConstant(const StringName &p_enum_name, const char *p_name, int64_t p_value, bool p_ignore_value_in_docs = false) : enum_name(p_enum_name), ignore_value_in_docs(p_ignore_value_in_docs), name(p_name), value(p_value) { } #else - _CoreConstant(const char *p_name, int p_value) : + _CoreConstant(const char *p_name, int64_t p_value) : name(p_name), value(p_value) { } @@ -73,13 +73,13 @@ static Vector<_CoreConstant> _global_constants; // This just binds enum classes as if they were regular enum constants. #define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \ - _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member), #m_prefix "_" #m_member, (int)m_enum::m_member)); + _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member), #m_prefix "_" #m_member, (int64_t)m_enum::m_member)); #define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \ - _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_enum::m_member, #m_name), #m_name, (int)m_enum::m_member)); + _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_enum::m_member, #m_name), #m_name, (int64_t)m_enum::m_member)); #define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \ - _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member), #m_prefix "_" #m_member, (int)m_enum::m_member, true)); + _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_enum::m_member, #m_prefix "_" #m_member), #m_prefix "_" #m_member, (int64_t)m_enum::m_member, true)); #define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \ _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant)); @@ -103,13 +103,13 @@ static Vector<_CoreConstant> _global_constants; // This just binds enum classes as if they were regular enum constants. #define BIND_CORE_ENUM_CLASS_CONSTANT(m_enum, m_prefix, m_member) \ - _global_constants.push_back(_CoreConstant(#m_prefix "_" #m_member, (int)m_enum::m_member)); + _global_constants.push_back(_CoreConstant(#m_prefix "_" #m_member, (int64_t)m_enum::m_member)); #define BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(m_enum, m_name, m_member) \ - _global_constants.push_back(_CoreConstant(#m_name, (int)m_enum::m_member)); + _global_constants.push_back(_CoreConstant(#m_name, (int64_t)m_enum::m_member)); #define BIND_CORE_ENUM_CLASS_CONSTANT_NO_VAL(m_enum, m_prefix, m_member) \ - _global_constants.push_back(_CoreConstant(#m_prefix "_" #m_member, (int)m_enum::m_member)); + _global_constants.push_back(_CoreConstant(#m_prefix "_" #m_member, (int64_t)m_enum::m_member)); #define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \ _global_constants.push_back(_CoreConstant(m_custom_name, m_constant)); @@ -213,6 +213,25 @@ void register_global_constants() { BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F14); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F15); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F16); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F17); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F18); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F19); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F20); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F21); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F22); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F23); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F24); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F25); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F26); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F27); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F28); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F29); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F30); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F31); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F32); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F33); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F34); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, F35); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_MULTIPLY); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_DIVIDE); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_SUBTRACT); @@ -551,8 +570,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING); - BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LENGTH); - BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LINK); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FLAGS); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_RENDER); @@ -568,6 +586,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY); @@ -587,25 +606,26 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_TOO_BIG); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_VALID_TYPES); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_SAVE_FILE); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_SAVE_FILE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID); 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_NODE_TYPE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_STORAGE); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR); - BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NETWORK); - BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR_HELPER); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CHECKABLE); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CHECKED); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_GROUP); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SUBGROUP); + BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CLASS_IS_BITFIELD); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE); @@ -633,11 +653,9 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_NORMAL); BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_EDITOR); - BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_NOSCRIPT); BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_CONST); - BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_REVERSE); BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_VIRTUAL); - BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_FROM_SCRIPT); + BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_VARARG); BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_STATIC); BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_OBJECT_CORE); BIND_CORE_ENUM_CONSTANT(METHOD_FLAGS_DEFAULT); @@ -645,7 +663,7 @@ void register_global_constants() { // rpc BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_DISABLED", Multiplayer::RPC_MODE_DISABLED); BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_ANY_PEER", Multiplayer::RPC_MODE_ANY_PEER); - BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_AUTH", Multiplayer::RPC_MODE_AUTHORITY); + BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_AUTHORITY", Multiplayer::RPC_MODE_AUTHORITY); BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_UNRELIABLE", Multiplayer::TRANSFER_MODE_UNRELIABLE); BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_UNRELIABLE_ORDERED", Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED); @@ -751,6 +769,6 @@ const char *CoreConstants::get_global_constant_name(int p_idx) { return _global_constants[p_idx].name; } -int CoreConstants::get_global_constant_value(int p_idx) { +int64_t CoreConstants::get_global_constant_value(int p_idx) { return _global_constants[p_idx].value; } diff --git a/core/core_constants.h b/core/core_constants.h index 9302c23959..d5b3b156b2 100644 --- a/core/core_constants.h +++ b/core/core_constants.h @@ -39,7 +39,7 @@ public: static StringName get_global_constant_enum(int p_idx); static bool get_ignore_value_in_docs(int p_idx); static const char *get_global_constant_name(int p_idx); - static int get_global_constant_value(int p_idx); + static int64_t get_global_constant_value(int p_idx); }; #endif // GLOBAL_CONSTANTS_H diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp index 06e08081e9..58d239ccb9 100644 --- a/core/debugger/local_debugger.cpp +++ b/core/debugger/local_debugger.cpp @@ -31,7 +31,7 @@ #include "local_debugger.h" #include "core/debugger/script_debugger.h" -#include "scene/main/scene_tree.h" +#include "core/os/os.h" struct LocalDebugger::ScriptsProfiler { struct ProfileInfoSort { @@ -273,7 +273,10 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { script_debugger->set_depth(-1); script_debugger->set_lines_left(-1); - SceneTree::get_singleton()->quit(); + MainLoop *main_loop = OS::get_singleton()->get_main_loop(); + if (main_loop->get_class() == "SceneTree") { + main_loop->call("quit"); + } break; } else if (line.begins_with("delete")) { if (line.get_slice_count(" ") <= 1) { diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 5ee4e2c368..c73e2eb3fb 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -208,7 +208,7 @@ void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char * rd->script_debugger->send_error(String::utf8(p_func), String::utf8(p_file), p_line, String::utf8(p_err), String::utf8(p_descr), p_editor_notify, p_type, si); } -void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error) { +void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich) { RemoteDebugger *rd = static_cast<RemoteDebugger *>(p_this); if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive prints during flush. @@ -237,7 +237,13 @@ void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p OutputString output_string; output_string.message = s; - output_string.type = p_error ? MESSAGE_TYPE_ERROR : MESSAGE_TYPE_LOG; + if (p_error) { + output_string.type = MESSAGE_TYPE_ERROR; + } else if (p_rich) { + output_string.type = MESSAGE_TYPE_LOG_RICH; + } else { + output_string.type = MESSAGE_TYPE_LOG; + } rd->output_strings.push_back(output_string); if (overflowed) { @@ -291,6 +297,14 @@ void RemoteDebugger::flush_output() { } strings.push_back(output_string.message); types.push_back(MESSAGE_TYPE_ERROR); + } else if (output_string.type == MESSAGE_TYPE_LOG_RICH) { + if (!joined_log_strings.is_empty()) { + strings.push_back(String("\n").join(joined_log_strings)); + types.push_back(MESSAGE_TYPE_LOG_RICH); + joined_log_strings.clear(); + } + strings.push_back(output_string.message); + types.push_back(MESSAGE_TYPE_LOG_RICH); } else { joined_log_strings.push_back(output_string.message); } diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h index fdb312ae68..fe4bbe86ea 100644 --- a/core/debugger/remote_debugger.h +++ b/core/debugger/remote_debugger.h @@ -44,6 +44,7 @@ public: enum MessageType { MESSAGE_TYPE_LOG, MESSAGE_TYPE_ERROR, + MESSAGE_TYPE_LOG_RICH, }; private: @@ -82,7 +83,7 @@ private: Thread::ID flush_thread = 0; PrintHandlerList phl; - static void _print_handler(void *p_this, const String &p_string, bool p_error); + static void _print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich); ErrorHandlerList eh; static void _err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type); diff --git a/core/doc_data.cpp b/core/doc_data.cpp index 1e72ad1090..89e7a8dc71 100644 --- a/core/doc_data.cpp +++ b/core/doc_data.cpp @@ -38,7 +38,7 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper } else { p_method.return_type += "*"; } - } else if (p_retinfo.type == Variant::INT && p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + } else if (p_retinfo.type == Variant::INT && p_retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { p_method.return_enum = p_retinfo.class_name; if (p_method.return_enum.begins_with("_")) { //proxy class p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length()); @@ -69,7 +69,7 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const } else { p_argument.type += "*"; } - } else if (p_arginfo.type == Variant::INT && p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + } else if (p_arginfo.type == Variant::INT && p_arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { p_argument.enumeration = p_arginfo.class_name; if (p_argument.enumeration.begins_with("_")) { //proxy class p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length()); diff --git a/core/doc_data.h b/core/doc_data.h index af20b717d7..1d8d2483e0 100644 --- a/core/doc_data.h +++ b/core/doc_data.h @@ -103,6 +103,7 @@ public: String value; bool is_value_valid = false; String enumeration; + bool is_bitfield = false; String description; bool operator<(const ConstantDoc &p_const) const { return name < p_const.name; @@ -111,6 +112,7 @@ public: struct EnumDoc { String name = "@unnamed_enum"; + bool is_bitfield = false; String description; Vector<DocData::ConstantDoc> values; }; @@ -163,6 +165,7 @@ public: Vector<ConstantDoc> constants; HashMap<String, String> enums; Vector<PropertyDoc> properties; + Vector<MethodDoc> annotations; Vector<ThemeItemDoc> theme_properties; bool is_script_doc = false; String script_path; diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp index 8add4b9a3a..f71a642b23 100644 --- a/core/error/error_macros.cpp +++ b/core/error/error_macros.cpp @@ -83,7 +83,13 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co // Main error printing function. void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) { - OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, p_editor_notify, (Logger::ErrorType)p_type); + if (OS::get_singleton()) { + OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, p_editor_notify, (Logger::ErrorType)p_type); + } else { + // Fallback if errors happen before OS init or after it's destroyed. + const char *err_details = (p_message && *p_message) ? p_message : p_error; + fprintf(stderr, "ERROR: %s\n at: %s (%s:%i)\n", err_details, p_function, p_file, p_line); + } _global_lock(); ErrorHandlerList *l = error_handler_list; diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 9e8addf8aa..ecdb1e26dc 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -46,9 +46,12 @@ static String get_type_name(const PropertyInfo &p_info) { return p_info.hint_string + "*"; } } - if (p_info.type == Variant::INT && (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM)) { + if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM))) { return String("enum::") + String(p_info.class_name); } + if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_BITFIELD))) { + return String("bitfield::") + String(p_info.class_name); + } if (p_info.class_name != StringName()) { return p_info.class_name; } @@ -334,14 +337,14 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { { // Global enums and constants. Array constants; - HashMap<String, List<Pair<String, int>>> enum_list; + HashMap<String, List<Pair<String, int64_t>>> enum_list; for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { - int value = CoreConstants::get_global_constant_value(i); + int64_t value = CoreConstants::get_global_constant_value(i); String enum_name = CoreConstants::get_global_constant_enum(i); String name = CoreConstants::get_global_constant_name(i); if (!enum_name.is_empty()) { - enum_list[enum_name].push_back(Pair<String, int>(name, value)); + enum_list[enum_name].push_back(Pair<String, int64_t>(name, value)); } else { Dictionary d; d["name"] = name; @@ -353,11 +356,11 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { api_dump["global_constants"] = constants; Array enums; - for (const KeyValue<String, List<Pair<String, int>>> &E : enum_list) { + for (const KeyValue<String, List<Pair<String, int64_t>>> &E : enum_list) { Dictionary d1; d1["name"] = E.key; Array values; - for (const Pair<String, int> &F : E.value) { + for (const Pair<String, int64_t> &F : E.value) { Dictionary d2; d2["name"] = F.first; d2["value"] = F.second; @@ -474,6 +477,38 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { } } { + //enums + Array enums; + + List<StringName> enum_names; + Variant::get_enums_for_type(type, &enum_names); + for (const StringName &enum_name : enum_names) { + Dictionary enum_dict; + enum_dict["name"] = String(enum_name); + + List<StringName> enumeration_names; + Variant::get_enumerations_for_enum(type, enum_name, &enumeration_names); + + Array values; + + for (const StringName &enumeration : enumeration_names) { + Dictionary values_dict; + values_dict["name"] = String(enumeration); + values_dict["value"] = Variant::get_enum_value(type, enum_name, enumeration); + values.push_back(values_dict); + } + + if (values.size()) { + enum_dict["values"] = values; + } + enums.push_back(enum_dict); + } + + if (enums.size()) { + d["enums"] = enums; + } + } + { //operators Array operators; @@ -633,6 +668,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { for (const StringName &F : enum_list) { Dictionary d2; d2["name"] = String(F); + d2["is_bitfield"] = ClassDB::is_enum_bitfield(class_name, F); Array values; List<StringName> enum_constant_list; diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp index a1d54f9c6d..58103e3af3 100644 --- a/core/extension/gdnative_interface.cpp +++ b/core/extension/gdnative_interface.cpp @@ -230,6 +230,16 @@ static void gdnative_variant_iter_get(const GDNativeVariantPtr p_self, GDNativeV } /// Variant functions. +static GDNativeInt gdnative_variant_hash(const GDNativeVariantPtr p_self) { + const Variant *self = (const Variant *)p_self; + return self->hash(); +} + +static GDNativeInt gdnative_variant_recursive_hash(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count) { + const Variant *self = (const Variant *)p_self; + return self->recursive_hash(p_recursion_count); +} + static GDNativeBool gdnative_variant_hash_compare(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other) { const Variant *self = (const Variant *)p_self; const Variant *other = (const Variant *)p_other; @@ -944,6 +954,8 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) { gdni.variant_iter_init = gdnative_variant_iter_init; gdni.variant_iter_next = gdnative_variant_iter_next; gdni.variant_iter_get = gdnative_variant_iter_get; + gdni.variant_hash = gdnative_variant_hash; + gdni.variant_recursive_hash = gdnative_variant_recursive_hash; gdni.variant_hash_compare = gdnative_variant_hash_compare; gdni.variant_booleanize = gdnative_variant_booleanize; gdni.variant_sub = gdnative_variant_sub; diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h index 98976b29f6..f106b805e7 100644 --- a/core/extension/gdnative_interface.h +++ b/core/extension/gdnative_interface.h @@ -153,7 +153,7 @@ typedef enum { GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */ GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */ GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL, - + GDNATIVE_CALL_ERROR_METHOD_NOT_CONST, /* used for const call */ } GDNativeCallErrorType; typedef struct { @@ -252,13 +252,10 @@ typedef void *GDNativeExtensionClassLibraryPtr; typedef enum { GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL = 1, GDNATIVE_EXTENSION_METHOD_FLAG_EDITOR = 2, - GDNATIVE_EXTENSION_METHOD_FLAG_NOSCRIPT = 4, - GDNATIVE_EXTENSION_METHOD_FLAG_CONST = 8, - GDNATIVE_EXTENSION_METHOD_FLAG_REVERSE = 16, /* used for events */ - GDNATIVE_EXTENSION_METHOD_FLAG_VIRTUAL = 32, - GDNATIVE_EXTENSION_METHOD_FLAG_FROM_SCRIPT = 64, - GDNATIVE_EXTENSION_METHOD_FLAG_VARARG = 128, - GDNATIVE_EXTENSION_METHOD_FLAG_STATIC = 256, + GDNATIVE_EXTENSION_METHOD_FLAG_CONST = 4, + GDNATIVE_EXTENSION_METHOD_FLAG_VIRTUAL = 8, + GDNATIVE_EXTENSION_METHOD_FLAG_VARARG = 16, + GDNATIVE_EXTENSION_METHOD_FLAG_STATIC = 32, GDNATIVE_EXTENSION_METHOD_FLAGS_DEFAULT = GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL, } GDNativeExtensionClassMethodFlags; @@ -413,6 +410,8 @@ typedef struct { GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid); GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid); void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid); + GDNativeInt (*variant_hash)(const GDNativeVariantPtr p_self); + GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count); 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); @@ -538,7 +537,7 @@ typedef struct { void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs); void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info); - void (*classdb_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); + void (*classdb_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, GDNativeBool p_is_bitfield); void (*classdb_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); void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix); 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); diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp index 5738b42049..b69859b441 100644 --- a/core/extension/native_extension.cpp +++ b/core/extension/native_extension.cpp @@ -55,14 +55,7 @@ protected: virtual PropertyInfo _gen_argument_type_info(int p_arg) const override { GDNativePropertyInfo pinfo; get_argument_info_func(method_userdata, p_arg, &pinfo); - PropertyInfo ret; - ret.type = Variant::Type(pinfo.type); - ret.name = pinfo.name; - ret.class_name = pinfo.class_name; - ret.hint = PropertyHint(pinfo.hint); - ret.usage = pinfo.usage; - ret.class_name = pinfo.class_name; - return ret; + return PropertyInfo(pinfo); } public: @@ -189,7 +182,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) { +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, GDNativeBool p_is_bitfield) { NativeExtension *self = static_cast<NativeExtension *>(p_library); StringName class_name = p_class_name; @@ -197,23 +190,18 @@ void NativeExtension::_register_extension_class_integer_constant(const GDNativeE //Extension *extension = &self->extension_classes[class_name]; - ClassDB::bind_integer_constant(class_name, p_enum_name, p_constant_name, p_constant_value); + ClassDB::bind_integer_constant(class_name, p_enum_name, p_constant_name, p_constant_value, p_is_bitfield); } 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 = 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 + "'."); + String property_name = p_info->name; + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'."); //Extension *extension = &self->extension_classes[class_name]; - PropertyInfo pinfo; - pinfo.type = Variant::Type(p_info->type); - pinfo.name = p_info->name; - pinfo.class_name = p_info->class_name; - pinfo.hint = PropertyHint(p_info->hint); - pinfo.hint_string = p_info->hint_string; - pinfo.usage = p_info->usage; + PropertyInfo pinfo(*p_info); ClassDB::add_property(class_name, pinfo, p_setter, p_getter); } @@ -245,13 +233,7 @@ void NativeExtension::_register_extension_class_signal(const GDNativeExtensionCl MethodInfo s; s.name = p_signal_name; for (int i = 0; i < p_argument_count; i++) { - PropertyInfo arg; - arg.type = Variant::Type(p_argument_info[i].type); - arg.name = p_argument_info[i].name; - arg.class_name = p_argument_info[i].class_name; - arg.hint = PropertyHint(p_argument_info[i].hint); - arg.hint_string = p_argument_info[i].hint_string; - arg.usage = p_argument_info[i].usage; + PropertyInfo arg(p_argument_info[i]); s.arguments.push_back(arg); } ClassDB::add_signal(class_name, s); @@ -281,6 +263,7 @@ void NativeExtension::_get_library_path(const GDNativeExtensionClassLibraryPtr p 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, &library_path); if (err != OK) { + ERR_PRINT("GDExtension dynamic library not found: " + p_path); return err; } @@ -289,15 +272,20 @@ Error NativeExtension::open_library(const String &p_path, const String &p_entry_ err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false); if (err != OK) { + ERR_PRINT("GDExtension entry point '" + p_entry_symbol + "' not found in library " + p_path); OS::get_singleton()->close_dynamic_library(library); return err; } GDNativeInitializationFunction initialization_function = (GDNativeInitializationFunction)entry_funcptr; - initialization_function(&gdnative_interface, this, &initialization); - level_initialized = -1; - return OK; + if (initialization_function(&gdnative_interface, this, &initialization)) { + level_initialized = -1; + return OK; + } else { + ERR_PRINT("GDExtension initialization function '" + p_entry_symbol + "' returned an error."); + return FAILED; + } } void NativeExtension::close_library() { @@ -384,6 +372,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St } if (err != OK) { + ERR_PRINT("Error loading GDExtension config file: " + p_path); return Ref<Resource>(); } @@ -391,6 +380,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St if (r_error) { *r_error = ERR_INVALID_DATA; } + ERR_PRINT("GDExtension config file must contain 'configuration.entry_symbol' key: " + p_path); return Ref<Resource>(); } @@ -423,6 +413,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St if (r_error) { *r_error = ERR_FILE_NOT_FOUND; } + ERR_PRINT("No GDExtension library found for current architecture; in config file " + p_path); return Ref<Resource>(); } @@ -440,6 +431,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St } if (err != OK) { + // Errors already logged in open_library() return Ref<Resource>(); } diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h index 8f106f753d..ca50f78621 100644 --- a/core/extension/native_extension.h +++ b/core/extension/native_extension.h @@ -49,7 +49,7 @@ class NativeExtension : public Resource { static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs); static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info); - static void _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); + static void _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, GDNativeBool p_is_bitfield); static void _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); static void _register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix); 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); diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt index 5a71bcbef3..d751f6c9b8 100644 --- a/core/input/gamecontrollerdb.txt +++ b/core/input/gamecontrollerdb.txt @@ -2,6 +2,7 @@ # Source: https://github.com/gabomdq/SDL_GameControllerDB # Windows +03000000300f00000a01000000000000,3 In 1 Conversion 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:a3,righty:a2,start:b8,x:b3,y:b0,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, @@ -31,6 +32,7 @@ 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, +030000003512000012ab000000000000,8BitDo NES30,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: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, @@ -47,10 +49,11 @@ 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, -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, -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, +03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, @@ -63,21 +66,12 @@ 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, 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, +03000000c82d00001890000000000000,8BitDo Zero 2,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, 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, -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,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 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, @@ -85,6 +79,13 @@ 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, +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, 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, @@ -93,10 +94,8 @@ 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, +03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, -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, @@ -121,7 +120,10 @@ 030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, 03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, +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, 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, @@ -135,7 +137,6 @@ 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 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, 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, @@ -158,25 +159,21 @@ 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, 030000006e0500001020000000000000,Elecom U4113S,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, 030000006e0500000720000000000000,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:Windows, +030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows, 03000000120c0000f61c000000000000,Elite,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, 03000000430b00000300000000000000,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:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 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 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, 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, -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,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, @@ -184,15 +181,14 @@ 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, +030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,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, 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, +03000000790000004618000000000000,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: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,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, @@ -217,41 +213,40 @@ 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 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, +030000007d0400000840000000000000,Gravis Destroyer Tilt,+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, +030000007d0400000540000000000000,Gravis Eliminator 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:Windows, +03000000280400000140000000000000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,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,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, +030000000d0f00004900000000000000,Hatsune Miku Sho 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, 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, 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, +030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 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, +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, +030000000d0f0000a500000000000000,Hori Miku Project Diva X HD 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:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000a600000000000000,Hori Miku Project Diva X HD 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, 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, @@ -289,27 +284,33 @@ 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,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, -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, +03000000790000004e95000000000000,Hyperkin N64 Controller 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, +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, 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 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, -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, +03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,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, +03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,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, 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,+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, +03000000250900000017000000000000,Joypad 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, 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 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 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, @@ -331,6 +332,7 @@ 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, 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, +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, 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, 03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,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, @@ -340,41 +342,44 @@ 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, +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, 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, 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, +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, 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, +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, 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,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 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 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, +0300000025090000e803000000000000,Mayflash Wii Classic Adapter,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, +03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000000790000000018000000000000,Mayflash Wii U 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, +03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-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,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 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, @@ -388,6 +393,7 @@ 03000000c62400001b89000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000efbe0000edfe000000000000,Monect Virtual 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, 03000000250900006688000000000000,MP-8866 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:Windows, +03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows, 03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows, 030000006b140000010c000000000000,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:Windows, 030000006b1400001106000000000000,Nacon Revolution 3 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:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -398,9 +404,8 @@ 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, -03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows, +03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, 03000000790000004518000000000000,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:Windows, 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, @@ -434,6 +439,7 @@ 03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +0300000062060000d570000000000000,PowerA PS3 Contoller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 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, @@ -494,6 +500,7 @@ 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, 03000000300f00000011000000000000,Qanba Arcade Stick 1008,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:b10,x:b0,y:b3,platform:Windows, 03000000300f00001611000000000000,Qanba Arcade Stick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,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, 03000000222c00000020000000000000,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,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000300f00001211000000000000,Qanba 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, 03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, @@ -502,6 +509,7 @@ 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, +03000000ff1100004733000000000000,Ramox FPS 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,righttrigger:b7,start:b9,x:b3,y:b0,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, @@ -509,11 +517,12 @@ 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, +030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,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, +030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,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, +030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,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, @@ -529,12 +538,14 @@ 03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000632500008005000000010000,Redgear,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,guide:b12,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, +03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows, 03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, 03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, 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, +0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,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, @@ -576,25 +587,25 @@ 03000000411200004550000000000000,Sanwa Micro Grip Pro,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:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows, 03000000c01100004150000000000000,Sanwa Micro Grip Pro,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, 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, +03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-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 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,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, +0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-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, +03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,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, +03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,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, +0300000003040000c197000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,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, +03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,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, @@ -608,18 +619,20 @@ 03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,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:b3,y:b4,platform:Windows, 03000000110100003114000000000000,SteelSeries Stratus Duo,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,SteelSeries Stratus Duo,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, +03000000381000003114000000000000,SteelSeries Stratus Duo,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, 03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows, 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 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, +030000001f08000001e4000000000000,Super Famicom 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, 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, +03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,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, +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, 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, +03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows, 03000000d814000001a0000000000000,TE Kitty,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, 03000000fa1900000706000000000000,Team 5,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, 03000000b50700001203000000000000,Techmobility X6-38V,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, @@ -631,12 +644,14 @@ 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, +030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,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 PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows, +03000000571d00002000000000000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,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, @@ -644,6 +659,7 @@ 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 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, +03000000151900005678000000000000,Uniplay U6,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b10,x:b3,y:b4,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 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, @@ -664,7 +680,7 @@ 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, +030000007e0500003003000000000000,Wii U 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, 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, @@ -683,6 +699,7 @@ 03000000ad1b00008e02000000000000,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:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c62400000053000000000000,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:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c6240000fdfa000000000000,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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,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, 030000005e040000a102000000000000,Xbox 360 Wireless Receiver,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, 030000005e0400000a0b000000000000,Xbox Adaptive 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, 03000000120c00000a88000000000000,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:a2,righty:a4,start:b6,x:b2,y:b3,platform:Windows, @@ -716,17 +733,19 @@ 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, +030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,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 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 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,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 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, +03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X, 03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X, -03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,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,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X, 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, @@ -741,8 +760,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 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, @@ -750,14 +769,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, 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, +03000000c82d00001890000001000000,8BitDo Zero 2,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, 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, 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, +03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, -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, @@ -768,8 +786,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, -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, +030000006f0e00008401000003010000,Faceoff Premiere Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle3:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Mac OS X, 03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, @@ -777,22 +794,28 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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 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, +030000007d0400000540000001010000,Gravis Eliminator 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, +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 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, +030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X, 030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 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, 030000000d0f0000ee00000000010000,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:Mac OS X, 030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X, -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, +03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X, +03000000830500006020000000000000,iBuffalo Gamepad,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,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, +03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,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 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, @@ -810,14 +833,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,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 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, +0300000025090000e803000000000000,Mayflash Wii Classic Adapter,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, +03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X, +03000000790000000018000000000000,Mayflash Wii U 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, +03000000790000000018000000010000,Mayflash Wii U 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,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, @@ -835,18 +859,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,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, +030000004c0500006802000072050000,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, 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, +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, 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, +03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (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, 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 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, @@ -857,6 +883,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000000d0f0000c100000072050000,Retro Bit Sega Genesis 6B Controller,a:b2,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b8,rightshoulder:b6,righttrigger:b7,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X, 03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000830500006020000000010000,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:Mac OS X, @@ -864,31 +892,37 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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 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, +03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X, +03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,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,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, +03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 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,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, 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, +03000000110100002014000000000000,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, 03000000110100002014000001000000,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, 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, +03000000381000003014000000000000,SteelSeries Stratus Duo,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, +03000000381000003114000000000000,SteelSeries Stratus Duo,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, 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, +030000000d0f0000f600000000010000,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: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, 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, +03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,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, +03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005f140000c501000000020000,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: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 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, @@ -912,6 +946,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +030000005e040000130b000013050000,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, 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, @@ -926,7 +961,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 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, @@ -943,9 +978,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, -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, +03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, 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, @@ -955,9 +990,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,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, +05000000a00500003232000001000000,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, 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, +03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, 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, 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, @@ -971,7 +1006,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, -03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, 03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, 05000000050b00000045000031000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, 05000000050b00000045000040000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, @@ -986,8 +1021,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, @@ -1005,12 +1038,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,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, +030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,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, @@ -1025,23 +1058,23 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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 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, +030000007d0400000540000000010000,Gravis Eliminator 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:Linux, +03000000280400000140000000010000,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: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 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 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, +03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,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 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, +030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 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, @@ -1049,6 +1082,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux, 030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 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, +030000000d0f00001100000011010000,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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,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, 030000000d0f00006b00000011010000,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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1062,10 +1096,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,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,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, +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, +03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,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, @@ -1109,28 +1146,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, 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 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, +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, 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, -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, +0300000025090000e803000001010000,Mayflash Wii Classic Adapter,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, +03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, +03000000b50700001203000010010000,Mega World Logic 3 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:a3,righty:a2,start:b9,x:b0,y:b1,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 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, +030000005e0400000700000000010000,Microsoft SideWinder Gamepad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,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, 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, +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, 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, @@ -1147,14 +1185,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,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, +030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 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, 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, +03000000853200000706000012010000,Nacon GC-100,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, 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, 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, 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, @@ -1189,6 +1228,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,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 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, @@ -1203,12 +1243,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, 03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, 03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, 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, @@ -1240,9 +1282,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,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, 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, +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, 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, +03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (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, +03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (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, 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, +03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (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, +03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (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, 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, @@ -1286,16 +1334,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, +030000001f08000001e4000010010000,SFC 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, 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,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, @@ -1303,23 +1348,25 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,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: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:b16,paddle2:b15,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:a7,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:a6,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, 05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux, 03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 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,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, +030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,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, +0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,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,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, @@ -1332,17 +1379,19 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +030000004f04000004b3000010010000,Thrustmaster Firestorm Dual Power,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, 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, +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, 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, +030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 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, @@ -1396,13 +1445,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, # 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, +38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a4,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, +05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android, 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, @@ -1422,9 +1471,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,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, +61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android, +05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 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, @@ -1436,16 +1485,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,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, +33666663316164653937326237613331,8BitDo Zero,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, +38426974646f205a65726f2047616d65,8BitDo Zero,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, +05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, 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 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, +417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, +32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 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, @@ -1464,12 +1514,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +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, 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, +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, 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, @@ -1482,22 +1532,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,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, +6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android, +436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, 37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, 64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Android, 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, +30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,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, +34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,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, @@ -1512,7 +1561,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,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, 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, @@ -1540,6 +1589,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, 050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,x:b2,y:b3,leftshoulder:b9,rightshoulder:b10,lefttrigger:a4,righttrigger:a5,guide:b5,start:b6,leftstick:b7,rightstick:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,back:b15,platform:Android, 64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, 36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -1554,22 +1607,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,platform:Android, 32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android, 37316565396364386635383230353365,Saturn,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, -38613865396530353338373763623431,Saturn,a:b0,b:b1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,platform:Android, +38613865396530353338373763623431,Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b10,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,platform:Android, 61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android, 30353835333338613130373363646337,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, 66386262366536653765333235343634,SG H510,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, 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, -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, +38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,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, +63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,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, @@ -1579,8 +1630,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, +30386438313564306161393537333663,Wii Classic Adapter,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 Adapter,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, diff --git a/core/input/input.cpp b/core/input/input.cpp index 4befdfac58..da0c6cb62a 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -134,8 +134,12 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event); ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input); + ClassDB::bind_method(D_METHOD("is_using_accumulated_input"), &Input::is_using_accumulated_input); ClassDB::bind_method(D_METHOD("flush_buffered_events"), &Input::flush_buffered_events); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input"); + BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED); @@ -321,6 +325,7 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const } float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const { + ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action)); HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action); if (!E) { return 0.0f; @@ -897,6 +902,10 @@ void Input::set_use_accumulated_input(bool p_enable) { use_accumulated_input = p_enable; } +bool Input::is_using_accumulated_input() { + return use_accumulated_input; +} + void Input::release_pressed_events() { flush_buffered_events(); // this is needed to release actions strengths @@ -1401,8 +1410,8 @@ String Input::get_joy_guid(int p_device) const { return joy_names[p_device].uid; } -Array Input::get_connected_joypads() { - Array ret; +TypedArray<int> Input::get_connected_joypads() { + TypedArray<int> ret; HashMap<int, Joypad>::Iterator elem = joy_names.begin(); while (elem) { if (elem->value.connected) { diff --git a/core/input/input.h b/core/input/input.h index 9a5b8e6e06..3ad8c91ddf 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -36,6 +36,7 @@ #include "core/os/keyboard.h" #include "core/os/thread_safe.h" #include "core/templates/rb_set.h" +#include "core/variant/typed_array.h" class Input : public Object { GDCLASS(Input, Object); @@ -109,7 +110,7 @@ private: bool emulate_touch_from_mouse = false; bool emulate_mouse_from_touch = false; bool use_input_buffering = false; - bool use_accumulated_input = false; + bool use_accumulated_input = true; int mouse_from_touch_index = -1; @@ -259,7 +260,7 @@ public: float get_joy_axis(int p_device, JoyAxis p_axis) const; String get_joy_name(int p_idx); - Array get_connected_joypads(); + TypedArray<int> get_connected_joypads(); Vector2 get_joy_vibration_strength(int p_device); float get_joy_vibration_duration(int p_device); uint64_t get_joy_vibration_timestamp(int p_device); @@ -326,6 +327,7 @@ public: bool is_using_input_buffering(); void set_use_input_buffering(bool p_enable); void set_use_accumulated_input(bool p_enable); + bool is_using_accumulated_input(); void release_pressed_events(); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 2d4c203748..3c104c2c86 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -525,8 +525,8 @@ void InputEventMouse::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_position"), &InputEventMouse::get_global_position); ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask"), "set_button_mask", "get_button_mask"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position"), "set_global_position", "get_global_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px"), "set_global_position", "get_global_position"); } /////////////////////////////////// @@ -741,6 +741,14 @@ float InputEventMouseMotion::get_pressure() const { return pressure; } +void InputEventMouseMotion::set_pen_inverted(bool p_inverted) { + pen_inverted = p_inverted; +} + +bool InputEventMouseMotion::get_pen_inverted() const { + return pen_inverted; +} + void InputEventMouseMotion::set_relative(const Vector2 &p_relative) { relative = p_relative; } @@ -768,6 +776,7 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co mm->set_position(p_xform.xform(get_position() + p_local_ofs)); mm->set_pressure(get_pressure()); + mm->set_pen_inverted(get_pen_inverted()); mm->set_tilt(get_tilt()); mm->set_global_position(get_global_position()); @@ -805,9 +814,9 @@ String InputEventMouseMotion::to_string() { break; } - // Work around the fact vformat can only take 5 substitutions but 6 need to be passed. - String mask_and_position = vformat("button_mask=%s, position=(%s)", button_mask_string, String(get_position())); - return vformat("InputEventMouseMotion: %s, relative=(%s), velocity=(%s), pressure=%.2f, tilt=(%s)", mask_and_position, String(get_relative()), String(get_velocity()), get_pressure(), String(get_tilt())); + // Work around the fact vformat can only take 5 substitutions but 7 need to be passed. + String mask_and_position_and_relative = vformat("button_mask=%s, position=(%s), relative=(%s)", button_mask_string, String(get_position()), String(get_relative())); + return vformat("InputEventMouseMotion: %s, velocity=(%s), pressure=%.2f, tilt=(%s), pen_inverted=(%d)", mask_and_position_and_relative, String(get_velocity()), get_pressure(), String(get_tilt()), get_pen_inverted()); } bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) { @@ -859,6 +868,9 @@ void InputEventMouseMotion::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMouseMotion::set_pressure); ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMouseMotion::get_pressure); + ClassDB::bind_method(D_METHOD("set_pen_inverted", "pen_inverted"), &InputEventMouseMotion::set_pen_inverted); + ClassDB::bind_method(D_METHOD("get_pen_inverted"), &InputEventMouseMotion::get_pen_inverted); + ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventMouseMotion::set_relative); ClassDB::bind_method(D_METHOD("get_relative"), &InputEventMouseMotion::get_relative); @@ -867,8 +879,9 @@ void InputEventMouseMotion::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "tilt"), "set_tilt", "get_tilt"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure"), "set_pressure", "get_pressure"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity"), "set_velocity", "get_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pen_inverted"), "set_pen_inverted", "get_pen_inverted"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative", PROPERTY_HINT_NONE, "suffix:px"), "set_relative", "get_relative"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_velocity", "get_velocity"); } /////////////////////////////////// @@ -1167,7 +1180,7 @@ void InputEventScreenTouch::_bind_methods() { //ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed); ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); } @@ -1260,9 +1273,9 @@ void InputEventScreenDrag::_bind_methods() { ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventScreenDrag::get_velocity); ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity"), "set_velocity", "get_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative", PROPERTY_HINT_NONE, "suffix:px"), "set_relative", "get_relative"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_velocity", "get_velocity"); } /////////////////////////////////// @@ -1362,7 +1375,7 @@ void InputEventGesture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventGesture::set_position); ClassDB::bind_method(D_METHOD("get_position"), &InputEventGesture::get_position); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position"); } Vector2 InputEventGesture::get_position() const { diff --git a/core/input/input_event.h b/core/input/input_event.h index 114db46623..59a2df497c 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -272,6 +272,7 @@ class InputEventMouseMotion : public InputEventMouse { float pressure = 0; Vector2 relative; Vector2 velocity; + bool pen_inverted = false; protected: static void _bind_methods(); @@ -283,6 +284,9 @@ public: void set_pressure(float p_pressure); float get_pressure() const; + void set_pen_inverted(bool p_inverted); + bool get_pen_inverted() const; + void set_relative(const Vector2 &p_relative); Vector2 get_relative() const; diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp index dd0191f43f..ae421654ca 100644 --- a/core/io/config_file.cpp +++ b/core/io/config_file.cpp @@ -61,19 +61,19 @@ PackedStringArray ConfigFile::_get_section_keys(const String &p_section) const { } void ConfigFile::set_value(const String &p_section, const String &p_key, const Variant &p_value) { - if (p_value.get_type() == Variant::NIL) { - //erase + if (p_value.get_type() == Variant::NIL) { // Erase key. if (!values.has(p_section)) { - return; // ? + return; } + values[p_section].erase(p_key); if (values[p_section].is_empty()) { values.erase(p_section); } - } else { if (!values.has(p_section)) { - values[p_section] = HashMap<String, Variant>(); + // Insert section-less keys at the beginning. + values.insert(p_section, HashMap<String, Variant>(), p_section.is_empty()); } values[p_section][p_key] = p_value; @@ -125,6 +125,9 @@ void ConfigFile::erase_section_key(const String &p_section, const String &p_key) ERR_FAIL_COND_MSG(!values[p_section].has(p_key), vformat("Cannot erase nonexistent key \"%s\" from section \"%s\".", p_key, p_section)); values[p_section].erase(p_key); + if (values[p_section].is_empty()) { + values.erase(p_section); + } } Error ConfigFile::save(const String &p_path) { diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index 433a7efb21..0a900078b7 100644 --- a/core/io/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -181,6 +181,10 @@ Error DirAccess::make_dir_recursive(String p_dir) { return OK; } +DirAccess::AccessType DirAccess::get_access_type() const { + return _access_type; +} + String DirAccess::fix_path(String p_path) const { switch (_access_type) { case ACCESS_RESOURCES: { diff --git a/core/io/dir_access.h b/core/io/dir_access.h index 0125f011b5..22017efaa3 100644 --- a/core/io/dir_access.h +++ b/core/io/dir_access.h @@ -57,6 +57,7 @@ protected: String _get_root_path() const; String _get_root_string() const; + AccessType get_access_type() const; String fix_path(String p_path) const; template <class T> diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 7d8da1b11c..da25f23917 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -388,9 +388,7 @@ String FileAccess::get_as_utf8_string() const { w[len] = 0; String s; - if (s.parse_utf8((const char *)w)) { - return String(); - } + s.parse_utf8((const char *)w); return s; } @@ -516,7 +514,6 @@ String FileAccess::get_pascal_string() { String ret; ret.parse_utf8(cs.ptr()); - return ret; } diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 19a0cce796..e656f6b885 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -84,8 +84,8 @@ private: return (a == p_val.a) && (b == p_val.b); } static uint32_t hash(const PathMD5 &p_val) { - uint32_t h = hash_djb2_one_32(p_val.a); - return hash_djb2_one_32(p_val.b, h); + uint32_t h = hash_murmur3_one_32(p_val.a); + return hash_fmix32(hash_murmur3_one_32(p_val.b, h)); } PathMD5() {} diff --git a/core/io/image.cpp b/core/io/image.cpp index dfba45c4e9..0f20aabd7e 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -81,9 +81,15 @@ const char *Image::format_names[Image::FORMAT_MAX] = { }; SavePNGFunc Image::save_png_func = nullptr; +SaveJPGFunc Image::save_jpg_func = nullptr; SaveEXRFunc Image::save_exr_func = nullptr; SavePNGBufferFunc Image::save_png_buffer_func = nullptr; +SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr; +SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr; + +SaveWebPFunc Image::save_webp_func = nullptr; +SaveWebPBufferFunc Image::save_webp_buffer_func = nullptr; void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel) { uint32_t ofs = (p_y * width + p_x) * p_pixel_size; @@ -1333,6 +1339,108 @@ void Image::crop(int p_width, int p_height) { crop_from_point(0, 0, p_width, p_height); } +void Image::rotate_90(ClockDirection p_direction) { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + int saved_width = height; + int saved_height = width; + + if (width != height) { + int n = MAX(width, height); + resize(n, n, INTERPOLATE_NEAREST); + } + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + // Flip. + + if (p_direction == CLOCKWISE) { + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(x, height - y - 1, pixel_size, w, dst); + + _put_pixelb(x, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } else { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width / 2; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, y, pixel_size, w, dst); + + _put_pixelb(width - x - 1, y, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + // Transpose. + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (x < y) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(y, x, pixel_size, w, dst); + + _put_pixelb(y, x, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + } + + if (saved_width != saved_height) { + resize(saved_width, saved_height, INTERPOLATE_NEAREST); + } else if (used_mipmaps) { + generate_mipmaps(); + } +} + +void Image::rotate_180() { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, height - y - 1, pixel_size, w, dst); + + _put_pixelb(width - x - 1, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + if (used_mipmaps) { + generate_mipmaps(); + } +} + void Image::flip_y() { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats."); @@ -2278,6 +2386,21 @@ Error Image::load(const String &p_path) { return ImageLoader::load_image(p_path, this); } +Ref<Image> Image::load_from_file(const String &p_path) { +#ifdef DEBUG_ENABLED + if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) { + WARN_PRINT("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource."); + } +#endif + Ref<Image> image; + image.instantiate(); + Error err = ImageLoader::load_image(p_path, image); + if (err != OK) { + ERR_FAIL_V_MSG(Ref<Image>(), vformat("Failed to load image. Error %d", err)); + } + return image; +} + Error Image::save_png(const String &p_path) const { if (save_png_func == nullptr) { return ERR_UNAVAILABLE; @@ -2286,6 +2409,14 @@ Error Image::save_png(const String &p_path) const { return save_png_func(p_path, Ref<Image>((Image *)this)); } +Error Image::save_jpg(const String &p_path, float p_quality) const { + if (save_jpg_func == nullptr) { + return ERR_UNAVAILABLE; + } + + return save_jpg_func(p_path, Ref<Image>((Image *)this), p_quality); +} + Vector<uint8_t> Image::save_png_to_buffer() const { if (save_png_buffer_func == nullptr) { return Vector<uint8_t>(); @@ -2294,6 +2425,14 @@ Vector<uint8_t> Image::save_png_to_buffer() const { return save_png_buffer_func(Ref<Image>((Image *)this)); } +Vector<uint8_t> Image::save_jpg_to_buffer(float p_quality) const { + if (save_jpg_buffer_func == nullptr) { + return Vector<uint8_t>(); + } + + return save_jpg_buffer_func(Ref<Image>((Image *)this), p_quality); +} + Error Image::save_exr(const String &p_path, bool p_grayscale) const { if (save_exr_func == nullptr) { return ERR_UNAVAILABLE; @@ -2302,6 +2441,31 @@ Error Image::save_exr(const String &p_path, bool p_grayscale) const { return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale); } +Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale) const { + if (save_exr_buffer_func == nullptr) { + return Vector<uint8_t>(); + } + return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale); +} + +Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const { + if (save_webp_func == nullptr) { + return ERR_UNAVAILABLE; + } + ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), ERR_INVALID_PARAMETER, "The WebP lossy quality was set to " + rtos(p_quality) + ", which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive)."); + + return save_webp_func(p_path, Ref<Image>((Image *)this), p_lossy, p_quality); +} + +Vector<uint8_t> Image::save_webp_to_buffer(const bool p_lossy, const float p_quality) const { + if (save_webp_buffer_func == nullptr) { + return Vector<uint8_t>(); + } + ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), Vector<uint8_t>(), "The WebP lossy quality was set to " + rtos(p_quality) + ", which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive)."); + + return save_webp_buffer_func(Ref<Image>((Image *)this), p_lossy, p_quality); +} + int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) { int mm; return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps ? -1 : 0); @@ -2416,15 +2580,15 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const V create(p_width, p_height, p_mipmaps, p_format, p_data); } -Rect2 Image::get_used_rect() const { +Rect2i Image::get_used_rect() const { if (format != FORMAT_LA8 && format != FORMAT_RGBA8 && format != FORMAT_RGBAF && format != FORMAT_RGBAH && format != FORMAT_RGBA4444 && format != FORMAT_RGB565) { - return Rect2(Point2(), Size2(width, height)); + return Rect2i(0, 0, width, height); } int len = data.size(); if (len == 0) { - return Rect2(); + return Rect2i(); } int minx = 0xFFFFFF, miny = 0xFFFFFFF; @@ -2450,15 +2614,15 @@ Rect2 Image::get_used_rect() const { } if (maxx == -1) { - return Rect2(); + return Rect2i(); } else { - return Rect2(minx, miny, maxx - minx + 1, maxy - miny + 1); + return Rect2i(minx, miny, maxx - minx + 1, maxy - miny + 1); } } -Ref<Image> Image::get_rect(const Rect2 &p_area) const { +Ref<Image> Image::get_rect(const Rect2i &p_area) const { Ref<Image> img = memnew(Image(p_area.size.x, p_area.size.y, mipmaps, format)); - img->blit_rect(Ref<Image>((Image *)this), p_area, Point2(0, 0)); + img->blit_rect(Ref<Image>((Image *)this), p_area, Point2i(0, 0)); return img; } @@ -2495,7 +2659,7 @@ void Image::_get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2 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) { +void Image::blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); int srcdsize = p_src->data.size(); @@ -2537,7 +2701,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po } } -void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) { +void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); @@ -2587,7 +2751,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co } } -void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) { +void Image::blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); int srcdsize = p_src->data.size(); @@ -2622,7 +2786,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P } } -void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) { +void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); @@ -2694,7 +2858,7 @@ void Image::fill(const Color &p_color) { _repeat_pixel_over_subsequent_memory(dst_data_ptr, pixel_size, width * height); } -void Image::fill_rect(const Rect2 &p_rect, const Color &p_color) { +void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats."); Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs()); @@ -3136,9 +3300,15 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty); ClassDB::bind_method(D_METHOD("load", "path"), &Image::load); + ClassDB::bind_static_method("Image", D_METHOD("load_from_file", "path"), &Image::load_from_file); ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png); ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer); + ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75)); + ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f)); + ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f)); ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha); ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible); @@ -3149,6 +3319,9 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); + ClassDB::bind_method(D_METHOD("rotate_90", "direction"), &Image::rotate_90); + ClassDB::bind_method(D_METHOD("rotate_180"), &Image::rotate_180); + ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges); ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha); ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear); diff --git a/core/io/image.h b/core/io/image.h index 1025554d51..46820a4c08 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -45,17 +45,27 @@ class Image; typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img); typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img); +typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality); +typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality); typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size); +typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality); +typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality); typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale); +typedef Vector<uint8_t> (*SaveEXRBufferFunc)(const Ref<Image> &p_img, bool p_grayscale); class Image : public Resource { GDCLASS(Image, Resource); public: static SavePNGFunc save_png_func; + static SaveJPGFunc save_jpg_func; static SaveEXRFunc save_exr_func; static SavePNGBufferFunc save_png_buffer_func; + static SaveEXRBufferFunc save_exr_buffer_func; + static SaveJPGBufferFunc save_jpg_buffer_func; + static SaveWebPFunc save_webp_func; + static SaveWebPBufferFunc save_webp_buffer_func; enum { MAX_WIDTH = (1 << 24), // force a limit somehow @@ -244,6 +254,9 @@ public: void crop_from_point(int p_x, int p_y, int p_width, int p_height); void crop(int p_width, int p_height); + void rotate_90(ClockDirection p_direction); + void rotate_180(); + void flip_x(); void flip_y(); @@ -280,9 +293,15 @@ public: Vector<uint8_t> get_data() const; Error load(const String &p_path); + static Ref<Image> load_from_file(const String &p_path); Error save_png(const String &p_path) const; + Error save_jpg(const String &p_path, float p_quality = 0.75) const; Vector<uint8_t> save_png_to_buffer() const; + Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const; + Vector<uint8_t> save_exr_to_buffer(bool p_grayscale) const; Error save_exr(const String &p_path, bool p_grayscale) const; + Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const; + Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) 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); @@ -354,15 +373,15 @@ public: Ref<Image> get_image_from_mipmap(int p_mipamp) const; void bump_map_to_normal_map(float bump_scale = 1.0); - void blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); - void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); - void blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); - void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); + void blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest); + void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest); + void blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest); + void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest); void fill(const Color &p_color); - void fill_rect(const Rect2 &p_rect, const Color &p_color); + void fill_rect(const Rect2i &p_rect, const Color &p_color); - Rect2 get_used_rect() const; - Ref<Image> get_rect(const Rect2 &p_area) const; + Rect2i get_used_rect() const; + Ref<Image> get_rect(const Rect2i &p_area) const; static void set_compress_bc_func(void (*p_compress_func)(Image *, float, UsedChannels)); static void set_compress_bptc_func(void (*p_compress_func)(Image *, float, UsedChannels)); diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index bb9606c94b..8ee19f274e 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -78,7 +78,7 @@ static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r ERR_FAIL_COND_V(strlen < 0 || strlen + pad > len, ERR_FILE_EOF); String str; - ERR_FAIL_COND_V(str.parse_utf8((const char *)buf, strlen), ERR_INVALID_DATA); + ERR_FAIL_COND_V(str.parse_utf8((const char *)buf, strlen) != OK, ERR_INVALID_DATA); r_string = str; // Add padding @@ -532,7 +532,13 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::RID: { - r_variant = RID(); + ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); + uint64_t id = decode_uint64(buf); + if (r_len) { + (*r_len) += 8; + } + + r_variant = RID::from_uint64(id); } break; case Variant::OBJECT: { if (type & ENCODE_FLAG_OBJECT_AS_ID) { @@ -614,9 +620,20 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = Callable(); } break; case Variant::SIGNAL: { - r_variant = Signal(); - } break; + String name; + Error err = _decode_string(buf, len, r_len, name); + if (err) { + return err; + } + ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); + ObjectID id = ObjectID(decode_uint64(buf)); + if (r_len) { + (*r_len) += 8; + } + + r_variant = Signal(id, StringName(name)); + } break; case Variant::DICTIONARY: { ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); int32_t count = decode_uint32(buf); @@ -1352,10 +1369,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::RID: { - } break; - case Variant::CALLABLE: { - } break; - case Variant::SIGNAL: { + RID rid = p_variant; + + if (buf) { + encode_uint64(rid.get_id(), buf); + } + r_len += 8; } break; case Variant::OBJECT: { if (p_full_objects) { @@ -1419,6 +1438,18 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; + case Variant::CALLABLE: { + } break; + case Variant::SIGNAL: { + Signal signal = p_variant; + + _encode_string(signal.get_name(), buf, r_len); + + if (buf) { + encode_uint64(signal.get_object_id(), buf); + } + r_len += 8; + } break; case Variant::DICTIONARY: { Dictionary d = p_variant; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index ad01eb1083..fec5ca5c7b 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -52,41 +52,36 @@ void Resource::set_path(const String &p_path, bool p_take_over) { return; } + if (p_path.is_empty()) { + p_take_over = false; // Can't take over an empty path + } + + ResourceCache::lock.lock(); + if (!path_cache.is_empty()) { - ResourceCache::lock.write_lock(); ResourceCache::resources.erase(path_cache); - ResourceCache::lock.write_unlock(); } path_cache = ""; - ResourceCache::lock.read_lock(); - bool has_path = ResourceCache::resources.has(p_path); - ResourceCache::lock.read_unlock(); + Ref<Resource> existing = ResourceCache::get_ref(p_path); - if (has_path) { + if (existing.is_valid()) { if (p_take_over) { - ResourceCache::lock.write_lock(); - Resource **res = ResourceCache::resources.getptr(p_path); - if (res) { - (*res)->set_name(""); - } - ResourceCache::lock.write_unlock(); + existing->path_cache = String(); + ResourceCache::resources.erase(p_path); } else { - ResourceCache::lock.read_lock(); - bool exists = ResourceCache::resources.has(p_path); - ResourceCache::lock.read_unlock(); - - ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion)."); + ResourceCache::lock.unlock(); + ERR_FAIL_MSG("Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion)."); } } + path_cache = p_path; if (!path_cache.is_empty()) { - ResourceCache::lock.write_lock(); ResourceCache::resources[path_cache] = this; - ResourceCache::lock.write_unlock(); } + ResourceCache::lock.unlock(); _resource_path_changed(); } @@ -100,14 +95,14 @@ String Resource::generate_scene_unique_id() { // If it's not unique it does not matter because the saver will try again. OS::Date date = OS::get_singleton()->get_date(); OS::Time time = OS::get_singleton()->get_time(); - uint32_t hash = hash_djb2_one_32(OS::get_singleton()->get_ticks_usec()); - hash = hash_djb2_one_32(date.year, hash); - hash = hash_djb2_one_32(date.month, hash); - hash = hash_djb2_one_32(date.day, hash); - hash = hash_djb2_one_32(time.hour, hash); - hash = hash_djb2_one_32(time.minute, hash); - hash = hash_djb2_one_32(time.second, hash); - hash = hash_djb2_one_32(Math::rand(), hash); + uint32_t hash = hash_murmur3_one_32(OS::get_singleton()->get_ticks_usec()); + hash = hash_murmur3_one_32(date.year, hash); + hash = hash_murmur3_one_32(date.month, hash); + hash = hash_murmur3_one_32(date.day, hash); + hash = hash_murmur3_one_32(time.hour, hash); + hash = hash_murmur3_one_32(time.minute, hash); + hash = hash_murmur3_one_32(time.second, hash); + hash = hash_murmur3_one_32(Math::rand(), hash); static constexpr uint32_t characters = 5; static constexpr uint32_t char_count = ('z' - 'a'); @@ -328,7 +323,7 @@ void Resource::notify_change_to_owners() { #ifdef TOOLS_ENABLED uint32_t Resource::hash_edited_version() const { - uint32_t hash = hash_djb2_one_32(get_edited_version()); + uint32_t hash = hash_murmur3_one_32(get_edited_version()); List<PropertyInfo> plist; get_property_list(&plist); @@ -337,7 +332,7 @@ uint32_t Resource::hash_edited_version() const { if (E.usage & PROPERTY_USAGE_STORAGE && E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_RESOURCE_TYPE) { Ref<Resource> res = get(E.name); if (res.is_valid()) { - hash = hash_djb2_one_32(res->hash_edited_version(), hash); + hash = hash_murmur3_one_32(res->hash_edited_version(), hash); } } } @@ -380,7 +375,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) { return; } - ResourceCache::lock.write_lock(); + ResourceCache::lock.lock(); if (p_remapped) { ResourceLoader::remapped_list.add(&remapped_list); @@ -388,7 +383,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) { ResourceLoader::remapped_list.remove(&remapped_list); } - ResourceCache::lock.write_unlock(); + ResourceCache::lock.unlock(); } bool Resource::is_translation_remapped() const { @@ -455,9 +450,9 @@ Resource::Resource() : Resource::~Resource() { if (!path_cache.is_empty()) { - ResourceCache::lock.write_lock(); + ResourceCache::lock.lock(); ResourceCache::resources.erase(path_cache); - ResourceCache::lock.write_unlock(); + ResourceCache::lock.unlock(); } if (owners.size()) { WARN_PRINT("Resource is still owned."); @@ -469,7 +464,7 @@ HashMap<String, Resource *> ResourceCache::resources; HashMap<String, HashMap<String, String>> ResourceCache::resource_path_cache; #endif -RWLock ResourceCache::lock; +Mutex ResourceCache::lock; #ifdef TOOLS_ENABLED RWLock ResourceCache::path_cache_lock; #endif @@ -491,46 +486,67 @@ void ResourceCache::reload_externals() { } bool ResourceCache::has(const String &p_path) { - lock.read_lock(); - bool b = resources.has(p_path); - lock.read_unlock(); + lock.lock(); + + Resource **res = resources.getptr(p_path); - return b; + if (res && (*res)->reference_get_count() == 0) { + // This resource is in the process of being deleted, ignore its existence. + (*res)->path_cache = String(); + resources.erase(p_path); + res = nullptr; + } + + lock.unlock(); + + if (!res) { + return false; + } + + return true; } -Resource *ResourceCache::get(const String &p_path) { - lock.read_lock(); +Ref<Resource> ResourceCache::get_ref(const String &p_path) { + Ref<Resource> ref; + lock.lock(); Resource **res = resources.getptr(p_path); - lock.read_unlock(); + if (res) { + ref = Ref<Resource>(*res); + } - if (!res) { - return nullptr; + if (res && !ref.is_valid()) { + // This resource is in the process of being deleted, ignore its existence + (*res)->path_cache = String(); + resources.erase(p_path); + res = nullptr; } - return *res; + lock.unlock(); + + return ref; } void ResourceCache::get_cached_resources(List<Ref<Resource>> *p_resources) { - lock.read_lock(); + lock.lock(); for (KeyValue<String, Resource *> &E : resources) { p_resources->push_back(Ref<Resource>(E.value)); } - lock.read_unlock(); + lock.unlock(); } int ResourceCache::get_cached_resource_count() { - lock.read_lock(); + lock.lock(); int rc = resources.size(); - lock.read_unlock(); + lock.unlock(); return rc; } void ResourceCache::dump(const char *p_file, bool p_short) { #ifdef DEBUG_ENABLED - lock.read_lock(); + lock.lock(); HashMap<String, int> type_count; @@ -562,7 +578,7 @@ void ResourceCache::dump(const char *p_file, bool p_short) { } } - lock.read_unlock(); + lock.unlock(); #else WARN_PRINT("ResourceCache::dump only with in debug builds."); #endif diff --git a/core/io/resource.h b/core/io/resource.h index a45bc6e1e4..a2cde87990 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -153,7 +153,7 @@ public: class ResourceCache { friend class Resource; friend class ResourceLoader; //need the lock - static RWLock lock; + static Mutex lock; static HashMap<String, Resource *> resources; #ifdef TOOLS_ENABLED static HashMap<String, HashMap<String, String>> resource_path_cache; // Each tscn has a set of resource paths and IDs. @@ -166,7 +166,7 @@ class ResourceCache { public: static void reload_externals(); static bool has(const String &p_path); - static Resource *get(const String &p_path); + static Ref<Resource> get_ref(const String &p_path); static void dump(const char *p_file = nullptr, bool p_short = false); static void get_cached_resources(List<Ref<Resource>> *p_resources); static int get_cached_resource_count(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 24458f20b4..b1c50e829c 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -693,7 +693,7 @@ Error ResourceLoaderBinary::load() { } if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE && ResourceCache::has(path)) { - Ref<Resource> cached = ResourceCache::get(path); + Ref<Resource> cached = ResourceCache::get_ref(path); if (cached.is_valid()) { //already loaded, don't do anything error = OK; @@ -717,10 +717,10 @@ Error ResourceLoaderBinary::load() { if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) { //use the existing one - Resource *r = ResourceCache::get(path); - if (r->get_class() == t) { - r->reset_state(); - res = Ref<Resource>(r); + Ref<Resource> cached = ResourceCache::get_ref(path); + if (cached->get_class() == t) { + cached->reset_state(); + res = cached; } } @@ -1547,10 +1547,11 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V case Variant::COLOR: { f->store_32(VARIANT_COLOR); Color val = p_property; - f->store_real(val.r); - f->store_real(val.g); - f->store_real(val.b); - f->store_real(val.a); + // Color are always floats + f->store_float(val.r); + f->store_float(val.g); + f->store_float(val.b); + f->store_float(val.a); } break; case Variant::STRING_NAME: { @@ -1685,7 +1686,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V f->store_32(len); const float *r = arr.ptr(); for (int i = 0; i < len; i++) { - f->store_real(r[i]); + f->store_float(r[i]); } } break; @@ -1743,10 +1744,10 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V f->store_32(len); const Color *r = arr.ptr(); for (int i = 0; i < len; i++) { - f->store_real(r[i].r); - f->store_real(r[i].g); - f->store_real(r[i].b); - f->store_real(r[i].a); + f->store_float(r[i].r); + f->store_float(r[i].g); + f->store_float(r[i].b); + f->store_float(r[i].a); } } break; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index fb21db1a19..2cd455475c 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -335,23 +335,15 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String & thread_load_mutex->unlock(); ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Attempted to load a resource already being loaded from this thread, cyclic reference?"); } - //lock first if possible - ResourceCache::lock.read_lock(); - - //get ptr - Resource **rptr = ResourceCache::resources.getptr(local_path); - - if (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 - load_task.resource = res; - load_task.status = THREAD_LOAD_LOADED; - load_task.progress = 1.0; - } + + Ref<Resource> existing = ResourceCache::get_ref(local_path); + + if (existing.is_valid()) { + //referencing is fine + load_task.resource = existing; + load_task.status = THREAD_LOAD_LOADED; + load_task.progress = 1.0; } - ResourceCache::lock.read_unlock(); } if (!p_source_resource.is_empty()) { @@ -530,27 +522,18 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi } //Is it cached? - ResourceCache::lock.read_lock(); - - Resource **rptr = ResourceCache::resources.getptr(local_path); - if (rptr) { - Ref<Resource> res(*rptr); + Ref<Resource> existing = ResourceCache::get_ref(local_path); - //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()) { - ResourceCache::lock.read_unlock(); - thread_load_mutex->unlock(); - - if (r_error) { - *r_error = OK; - } + if (existing.is_valid()) { + thread_load_mutex->unlock(); - return res; //use cached + if (r_error) { + *r_error = OK; } - } - ResourceCache::lock.read_unlock(); + return existing; //use cached + } //load using task (but this thread) ThreadLoadTask load_task; @@ -867,7 +850,7 @@ String ResourceLoader::path_remap(const String &p_path) { } void ResourceLoader::reload_translation_remaps() { - ResourceCache::lock.read_lock(); + ResourceCache::lock.lock(); List<Resource *> to_reload; SelfList<Resource> *E = remapped_list.first(); @@ -877,7 +860,7 @@ void ResourceLoader::reload_translation_remaps() { E = E->next(); } - ResourceCache::lock.read_unlock(); + ResourceCache::lock.unlock(); //now just make sure to not delete any of these resources while changing locale.. while (to_reload.front()) { diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp index ea8435e587..5b90fb52a6 100644 --- a/core/io/stream_peer_ssl.cpp +++ b/core/io/stream_peer_ssl.cpp @@ -60,6 +60,7 @@ void StreamPeerSSL::_bind_methods() { ClassDB::bind_method(D_METHOD("accept_stream", "stream", "private_key", "certificate", "chain"), &StreamPeerSSL::accept_stream, DEFVAL(Ref<X509Certificate>())); ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname", "valid_certificate"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()), DEFVAL(Ref<X509Certificate>())); ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status); + ClassDB::bind_method(D_METHOD("get_stream"), &StreamPeerSSL::get_stream); ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream); ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled); ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerSSL::is_blocking_handshake_enabled); diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h index 15f646d897..fe68667adc 100644 --- a/core/io/stream_peer_ssl.h +++ b/core/io/stream_peer_ssl.h @@ -61,6 +61,7 @@ public: virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>()) = 0; virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_valid_cert = Ref<X509Certificate>()) = 0; virtual Status get_status() const = 0; + virtual Ref<StreamPeer> get_stream() const = 0; virtual void disconnect_from_stream() = 0; diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index 7b43193f47..154b55f5e7 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -72,11 +72,11 @@ void XMLParser::_parse_closing_xml_element() { node_empty = false; attributes.clear(); - ++P; + next_char(); const char *pBeginClose = P; while (*P && *P != '>') { - ++P; + next_char(); } node_name = String::utf8(pBeginClose, (int)(P - pBeginClose)); @@ -85,7 +85,7 @@ void XMLParser::_parse_closing_xml_element() { #endif if (*P) { - ++P; + next_char(); } } @@ -95,12 +95,12 @@ void XMLParser::_ignore_definition() { char *F = P; // move until end marked with '>' reached while (*P && *P != '>') { - ++P; + next_char(); } node_name.parse_utf8(F, P - F); if (*P) { - ++P; + next_char(); } } @@ -114,7 +114,7 @@ bool XMLParser::_parse_cdata() { // skip '<![CDATA[' int count = 0; while (*P && count < 8) { - ++P; + next_char(); ++count; } @@ -134,7 +134,7 @@ bool XMLParser::_parse_cdata() { cDataEnd = P - 2; } - ++P; + next_char(); } if (cDataEnd) { @@ -180,7 +180,7 @@ void XMLParser::_parse_comment() { } else if (*P == '<') { ++count; } - ++P; + next_char(); } if (count) { @@ -206,7 +206,7 @@ void XMLParser::_parse_opening_xml_element() { // find end of element while (*P && *P != '>' && !_is_white_space(*P)) { - ++P; + next_char(); } const char *endName = P; @@ -214,7 +214,7 @@ void XMLParser::_parse_opening_xml_element() { // find attributes while (*P && *P != '>') { if (_is_white_space(*P)) { - ++P; + next_char(); } else { if (*P != '/') { // we've got an attribute @@ -223,7 +223,7 @@ void XMLParser::_parse_opening_xml_element() { const char *attributeNameBegin = P; while (*P && !_is_white_space(*P) && *P != '=') { - ++P; + next_char(); } if (!*P) { @@ -231,12 +231,12 @@ void XMLParser::_parse_opening_xml_element() { } const char *attributeNameEnd = P; - ++P; + next_char(); // read the attribute value // check for quotes and single quotes, thx to murphy while ((*P != '\"') && (*P != '\'') && *P) { - ++P; + next_char(); } if (!*P) { // malformatted xml file @@ -245,16 +245,16 @@ void XMLParser::_parse_opening_xml_element() { const char attributeQuoteChar = *P; - ++P; + next_char(); const char *attributeValueBegin = P; while (*P != attributeQuoteChar && *P) { - ++P; + next_char(); } const char *attributeValueEnd = P; if (*P) { - ++P; + next_char(); } Attribute attr; @@ -268,7 +268,7 @@ void XMLParser::_parse_opening_xml_element() { attributes.push_back(attr); } else { // tag is closed directly - ++P; + next_char(); node_empty = true; break; } @@ -288,7 +288,7 @@ void XMLParser::_parse_opening_xml_element() { #endif if (*P) { - ++P; + next_char(); } } @@ -298,7 +298,7 @@ void XMLParser::_parse_current_node() { // more forward until '<' found while (*P != '<' && *P) { - ++P; + next_char(); } if (P - start > 0) { @@ -312,7 +312,7 @@ void XMLParser::_parse_current_node() { return; } - ++P; + next_char(); // based on current token, parse and report next element switch (*P) { @@ -487,6 +487,7 @@ Error XMLParser::open(const String &p_path) { file->get_buffer((uint8_t *)data, length); data[length] = 0; P = data; + current_line = 0; return OK; } @@ -523,10 +524,7 @@ void XMLParser::close() { } int XMLParser::get_current_line() const { - return 0; -} - -XMLParser::XMLParser() { + return current_line; } XMLParser::~XMLParser() { diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index da14ee8eae..aea252ddc7 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -68,6 +68,7 @@ private: char *data = nullptr; char *P = nullptr; uint64_t length = 0; + uint64_t current_line = 0; String node_name; bool node_empty = false; NodeType node_type = NODE_NONE; @@ -88,6 +89,13 @@ private: void _parse_opening_xml_element(); void _parse_current_node(); + _FORCE_INLINE_ void next_char() { + if (*P == '\n') { + current_line++; + } + P++; + } + static void _bind_methods(); public: @@ -113,7 +121,6 @@ public: void close(); - XMLParser(); ~XMLParser(); }; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index efa970c681..41a0848d01 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -33,19 +33,19 @@ #include "core/math/geometry_3d.h" #include "core/object/script_language.h" -int AStar3D::get_available_point_id() const { +int64_t AStar3D::get_available_point_id() const { if (points.has(last_free_id)) { - int cur_new_id = last_free_id + 1; + int64_t cur_new_id = last_free_id + 1; while (points.has(cur_new_id)) { cur_new_id++; } - const_cast<int &>(last_free_id) = cur_new_id; + const_cast<int64_t &>(last_free_id) = cur_new_id; } return last_free_id; } -void AStar3D::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { +void AStar3D::add_point(int64_t 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 < 0.0, vformat("Can't add a point with weight scale less than 0.0: %f.", p_weight_scale)); @@ -68,7 +68,7 @@ void AStar3D::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { } } -Vector3 AStar3D::get_point_position(int p_id) const { +Vector3 AStar3D::get_point_position(int64_t 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 AStar3D::get_point_position(int p_id) const { return p->pos; } -void AStar3D::set_point_position(int p_id, const Vector3 &p_pos) { +void AStar3D::set_point_position(int64_t 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 AStar3D::set_point_position(int p_id, const Vector3 &p_pos) { p->pos = p_pos; } -real_t AStar3D::get_point_weight_scale(int p_id) const { +real_t AStar3D::get_point_weight_scale(int64_t 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,7 +92,7 @@ real_t AStar3D::get_point_weight_scale(int p_id) const { return p->weight_scale; } -void AStar3D::set_point_weight_scale(int p_id, real_t p_weight_scale) { +void AStar3D::set_point_weight_scale(int64_t 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)); @@ -101,12 +101,12 @@ void AStar3D::set_point_weight_scale(int p_id, real_t p_weight_scale) { p->weight_scale = p_weight_scale; } -void AStar3D::remove_point(int p_id) { +void AStar3D::remove_point(int64_t 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)); - for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { Segment s(p_id, (*it.key)); segments.erase(s); @@ -114,7 +114,7 @@ void AStar3D::remove_point(int p_id) { (*it.value)->unlinked_neighbours.remove(p->id); } - for (OAHashMap<int, Point *>::Iterator it = p->unlinked_neighbours.iter(); it.valid; it = p->unlinked_neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->unlinked_neighbours.iter(); it.valid; it = p->unlinked_neighbours.next_iter(it)) { Segment s(p_id, (*it.key)); segments.erase(s); @@ -127,7 +127,7 @@ void AStar3D::remove_point(int p_id) { last_free_id = p_id; } -void AStar3D::connect_points(int p_id, int p_with_id, bool bidirectional) { +void AStar3D::connect_points(int64_t p_id, int64_t 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 AStar3D::connect_points(int p_id, int p_with_id, bool bidirectional) { segments.insert(s); } -void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) { +void AStar3D::disconnect_points(int64_t p_id, int64_t 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)); @@ -175,7 +175,7 @@ void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) { ERR_FAIL_COND_MSG(!b_exists, vformat("Can't disconnect points. Point with id: %d doesn't exist.", p_with_id)); Segment s(p_id, p_with_id); - int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : s.direction; + int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : (int)s.direction; HashSet<Segment, Segment>::Iterator element = segments.find(s); if (element) { @@ -205,35 +205,35 @@ void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) { } } -bool AStar3D::has_point(int p_id) const { +bool AStar3D::has_point(int64_t p_id) const { return points.has(p_id); } Array AStar3D::get_point_ids() { Array point_list; - for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { point_list.push_back(*(it.key)); } return point_list; } -Vector<int> AStar3D::get_point_connections(int p_id) { +Vector<int64_t> AStar3D::get_point_connections(int64_t 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)); + ERR_FAIL_COND_V_MSG(!p_exists, Vector<int64_t>(), vformat("Can't get point's connections. Point with id: %d doesn't exist.", p_id)); - Vector<int> point_list; + Vector<int64_t> point_list; - for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { point_list.push_back((*it.key)); } return point_list; } -bool AStar3D::are_points_connected(int p_id, int p_with_id, bool bidirectional) const { +bool AStar3D::are_points_connected(int64_t p_id, int64_t p_with_id, bool bidirectional) const { Segment s(p_id, p_with_id); const HashSet<Segment, Segment>::Iterator element = segments.find(s); @@ -243,32 +243,32 @@ bool AStar3D::are_points_connected(int p_id, int p_with_id, bool bidirectional) void AStar3D::clear() { last_free_id = 0; - for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { memdelete(*(it.value)); } segments.clear(); points.clear(); } -int AStar3D::get_point_count() const { +int64_t AStar3D::get_point_count() const { return points.get_num_elements(); } -int AStar3D::get_point_capacity() const { +int64_t AStar3D::get_point_capacity() const { return points.get_capacity(); } -void AStar3D::reserve_space(int p_num_nodes) { +void AStar3D::reserve_space(int64_t 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 AStar3D::get_closest_point(const Vector3 &p_point, bool p_include_disabled) const { - int closest_id = -1; +int64_t AStar3D::get_closest_point(const Vector3 &p_point, bool p_include_disabled) const { + int64_t closest_id = -1; real_t closest_dist = 1e20; - for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { if (!p_include_disabled && !(*it.value)->enabled) { continue; // Disabled points should not be considered. } @@ -276,7 +276,7 @@ int AStar3D::get_closest_point(const Vector3 &p_point, bool p_include_disabled) // Keep the closest point's ID, and in case of multiple closest IDs, // the smallest one (makes it deterministic). real_t d = p_point.distance_squared_to((*it.value)->pos); - int id = *(it.key); + int64_t id = *(it.key); if (d <= closest_dist) { if (d == closest_dist && id > closest_id) { // Keep lowest ID. continue; @@ -295,8 +295,8 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const { for (const Segment &E : segments) { Point *from_point = nullptr, *to_point = nullptr; - points.lookup(E.u, from_point); - points.lookup(E.v, to_point); + points.lookup(E.key.first, from_point); + points.lookup(E.key.second, to_point); if (!(from_point->enabled && to_point->enabled)) { continue; @@ -346,7 +346,7 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) { open_list.remove_at(open_list.size() - 1); p->closed_pass = pass; // Mark the point as closed - for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { Point *e = *(it.value); // The neighbour point if (!e->enabled || e->closed_pass == pass) { @@ -380,7 +380,7 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) { return found_route; } -real_t AStar3D::_estimate_cost(int p_from_id, int p_to_id) { +real_t AStar3D::_estimate_cost(int64_t p_from_id, int64_t 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 AStar3D::_estimate_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -real_t AStar3D::_compute_cost(int p_from_id, int p_to_id) { +real_t AStar3D::_compute_cost(int64_t p_from_id, int64_t 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 AStar3D::_compute_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { +Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t 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)); @@ -438,7 +438,7 @@ Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { } Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; @@ -451,7 +451,7 @@ Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { Vector3 *w = path.ptrw(); Point *p2 = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p2 != begin_point) { w[idx--] = p2->pos; p2 = p2->prev_point; @@ -463,17 +463,17 @@ Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { return path; } -Vector<int> AStar3D::get_id_path(int p_from_id, int p_to_id) { +Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t 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)); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); Point *b; bool to_exists = 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)); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { - Vector<int> ret; + Vector<int64_t> ret; ret.push_back(a->id); return ret; } @@ -483,24 +483,24 @@ Vector<int> AStar3D::get_id_path(int p_from_id, int p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<int>(); + return Vector<int64_t>(); } Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; } - Vector<int> path; + Vector<int64_t> path; path.resize(pc); { - int *w = path.ptrw(); + int64_t *w = path.ptrw(); p = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p != begin_point) { w[idx--] = p->id; p = p->prev_point; @@ -512,7 +512,7 @@ Vector<int> AStar3D::get_id_path(int p_from_id, int p_to_id) { return path; } -void AStar3D::set_point_disabled(int p_id, bool p_disabled) { +void AStar3D::set_point_disabled(int64_t 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 AStar3D::set_point_disabled(int p_id, bool p_disabled) { p->enabled = !p_disabled; } -bool AStar3D::is_point_disabled(int p_id) const { +bool AStar3D::is_point_disabled(int64_t 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)); @@ -568,40 +568,40 @@ AStar3D::~AStar3D() { ///////////////////////////////////////////////////////////// -int AStar2D::get_available_point_id() const { +int64_t AStar2D::get_available_point_id() const { return astar.get_available_point_id(); } -void AStar2D::add_point(int p_id, const Vector2 &p_pos, real_t p_weight_scale) { +void AStar2D::add_point(int64_t p_id, const Vector2 &p_pos, real_t p_weight_scale) { astar.add_point(p_id, Vector3(p_pos.x, p_pos.y, 0), p_weight_scale); } -Vector2 AStar2D::get_point_position(int p_id) const { +Vector2 AStar2D::get_point_position(int64_t p_id) const { Vector3 p = astar.get_point_position(p_id); return Vector2(p.x, p.y); } -void AStar2D::set_point_position(int p_id, const Vector2 &p_pos) { +void AStar2D::set_point_position(int64_t p_id, const Vector2 &p_pos) { astar.set_point_position(p_id, Vector3(p_pos.x, p_pos.y, 0)); } -real_t AStar2D::get_point_weight_scale(int p_id) const { +real_t AStar2D::get_point_weight_scale(int64_t p_id) const { return astar.get_point_weight_scale(p_id); } -void AStar2D::set_point_weight_scale(int p_id, real_t p_weight_scale) { +void AStar2D::set_point_weight_scale(int64_t p_id, real_t p_weight_scale) { astar.set_point_weight_scale(p_id, p_weight_scale); } -void AStar2D::remove_point(int p_id) { +void AStar2D::remove_point(int64_t p_id) { astar.remove_point(p_id); } -bool AStar2D::has_point(int p_id) const { +bool AStar2D::has_point(int64_t p_id) const { return astar.has_point(p_id); } -Vector<int> AStar2D::get_point_connections(int p_id) { +Vector<int64_t> AStar2D::get_point_connections(int64_t p_id) { return astar.get_point_connections(p_id); } @@ -609,31 +609,31 @@ Array AStar2D::get_point_ids() { return astar.get_point_ids(); } -void AStar2D::set_point_disabled(int p_id, bool p_disabled) { +void AStar2D::set_point_disabled(int64_t p_id, bool p_disabled) { astar.set_point_disabled(p_id, p_disabled); } -bool AStar2D::is_point_disabled(int p_id) const { +bool AStar2D::is_point_disabled(int64_t p_id) const { return astar.is_point_disabled(p_id); } -void AStar2D::connect_points(int p_id, int p_with_id, bool p_bidirectional) { +void AStar2D::connect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional) { astar.connect_points(p_id, p_with_id, p_bidirectional); } -void AStar2D::disconnect_points(int p_id, int p_with_id) { - astar.disconnect_points(p_id, p_with_id); +void AStar2D::disconnect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional) { + astar.disconnect_points(p_id, p_with_id, p_bidirectional); } -bool AStar2D::are_points_connected(int p_id, int p_with_id) const { - return astar.are_points_connected(p_id, p_with_id); +bool AStar2D::are_points_connected(int64_t p_id, int64_t p_with_id, bool p_bidirectional) const { + return astar.are_points_connected(p_id, p_with_id, p_bidirectional); } -int AStar2D::get_point_count() const { +int64_t AStar2D::get_point_count() const { return astar.get_point_count(); } -int AStar2D::get_point_capacity() const { +int64_t AStar2D::get_point_capacity() const { return astar.get_point_capacity(); } @@ -641,11 +641,11 @@ void AStar2D::clear() { astar.clear(); } -void AStar2D::reserve_space(int p_num_nodes) { +void AStar2D::reserve_space(int64_t p_num_nodes) { astar.reserve_space(p_num_nodes); } -int AStar2D::get_closest_point(const Vector2 &p_point, bool p_include_disabled) const { +int64_t AStar2D::get_closest_point(const Vector2 &p_point, bool p_include_disabled) const { return astar.get_closest_point(Vector3(p_point.x, p_point.y, 0), p_include_disabled); } @@ -654,7 +654,7 @@ Vector2 AStar2D::get_closest_position_in_segment(const Vector2 &p_point) const { return Vector2(p.x, p.y); } -real_t AStar2D::_estimate_cost(int p_from_id, int p_to_id) { +real_t AStar2D::_estimate_cost(int64_t p_from_id, int64_t p_to_id) { real_t scost; if (GDVIRTUAL_CALL(_estimate_cost, p_from_id, p_to_id, scost)) { return scost; @@ -671,7 +671,7 @@ real_t AStar2D::_estimate_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) { +real_t AStar2D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { real_t scost; if (GDVIRTUAL_CALL(_compute_cost, p_from_id, p_to_id, scost)) { return scost; @@ -688,7 +688,7 @@ real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { +Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) { 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)); @@ -711,7 +711,7 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { } AStar3D::Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; @@ -724,7 +724,7 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { Vector2 *w = path.ptrw(); AStar3D::Point *p2 = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p2 != begin_point) { w[idx--] = Vector2(p2->pos.x, p2->pos.y); p2 = p2->prev_point; @@ -736,17 +736,17 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { return path; } -Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) { +Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) { 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)); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); 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)); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { - Vector<int> ret; + Vector<int64_t> ret; ret.push_back(a->id); return ret; } @@ -756,24 +756,24 @@ Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<int>(); + return Vector<int64_t>(); } AStar3D::Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; } - Vector<int> path; + Vector<int64_t> path; path.resize(pc); { - int *w = path.ptrw(); + int64_t *w = path.ptrw(); p = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p != begin_point) { w[idx--] = p->id; p = p->prev_point; @@ -813,7 +813,7 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { open_list.remove_at(open_list.size() - 1); p->closed_pass = astar.pass; // Mark the point as closed - for (OAHashMap<int, AStar3D::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, 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) { @@ -863,8 +863,8 @@ void AStar2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar2D::is_point_disabled); ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar2D::connect_points, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar2D::disconnect_points); - ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar2D::are_points_connected); + ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id", "bidirectional"), &AStar2D::disconnect_points, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id", "bidirectional"), &AStar2D::are_points_connected, DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_point_count"), &AStar2D::get_point_count); ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar2D::get_point_capacity); diff --git a/core/math/a_star.h b/core/math/a_star.h index e2f75ad18c..c1497d133f 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -47,13 +47,13 @@ class AStar3D : public RefCounted { struct Point { Point() {} - int id = 0; + int64_t id = 0; Vector3 pos; real_t weight_scale = 0; bool enabled = false; - OAHashMap<int, Point *> neighbours = 4u; - OAHashMap<int, Point *> unlinked_neighbours = 4u; + OAHashMap<int64_t, Point *> neighbours = 4u; + OAHashMap<int64_t, Point *> unlinked_neighbours = 4u; // Used for pathfinding. Point *prev_point = nullptr; @@ -76,13 +76,7 @@ class AStar3D : public RefCounted { }; struct Segment { - union { - struct { - int32_t u; - int32_t v; - }; - uint64_t key = 0; - }; + Pair<int64_t, int64_t> key; enum { NONE = 0, @@ -93,28 +87,28 @@ class AStar3D : public RefCounted { unsigned char direction = NONE; static uint32_t hash(const Segment &p_seg) { - return hash_one_uint64(p_seg.key); + return PairHash<int64_t, int64_t>().hash(p_seg.key); } bool operator==(const Segment &p_s) const { return key == p_s.key; } Segment() {} - Segment(int p_from, int p_to) { + Segment(int64_t p_from, int64_t p_to) { if (p_from < p_to) { - u = p_from; - v = p_to; + key.first = p_from; + key.second = p_to; direction = FORWARD; } else { - u = p_to; - v = p_from; + key.first = p_to; + key.second = p_from; direction = BACKWARD; } } }; - int last_free_id = 0; + int64_t last_free_id = 0; uint64_t pass = 1; - OAHashMap<int, Point *> points; + OAHashMap<int64_t, Point *> points; HashSet<Segment, Segment> segments; bool _solve(Point *begin_point, Point *end_point); @@ -122,42 +116,42 @@ class AStar3D : public RefCounted { protected: static void _bind_methods(); - virtual real_t _estimate_cost(int p_from_id, int p_to_id); - virtual real_t _compute_cost(int p_from_id, int p_to_id); + virtual real_t _estimate_cost(int64_t p_from_id, int64_t p_to_id); + virtual real_t _compute_cost(int64_t p_from_id, int64_t p_to_id); GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) public: - int get_available_point_id() const; - - void add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale = 1); - Vector3 get_point_position(int p_id) const; - void set_point_position(int p_id, const Vector3 &p_pos); - real_t get_point_weight_scale(int p_id) const; - void set_point_weight_scale(int p_id, real_t p_weight_scale); - void remove_point(int p_id); - bool has_point(int p_id) const; - Vector<int> get_point_connections(int p_id); + int64_t get_available_point_id() const; + + void add_point(int64_t p_id, const Vector3 &p_pos, real_t p_weight_scale = 1); + Vector3 get_point_position(int64_t p_id) const; + void set_point_position(int64_t p_id, const Vector3 &p_pos); + real_t get_point_weight_scale(int64_t p_id) const; + void set_point_weight_scale(int64_t p_id, real_t p_weight_scale); + void remove_point(int64_t p_id); + bool has_point(int64_t p_id) const; + Vector<int64_t> get_point_connections(int64_t p_id); Array get_point_ids(); - void set_point_disabled(int p_id, bool p_disabled = true); - bool is_point_disabled(int p_id) const; + void set_point_disabled(int64_t p_id, bool p_disabled = true); + bool is_point_disabled(int64_t p_id) const; - void connect_points(int p_id, int p_with_id, bool bidirectional = true); - void disconnect_points(int p_id, int p_with_id, bool bidirectional = true); - bool are_points_connected(int p_id, int p_with_id, bool bidirectional = true) const; + void connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional = true); + void disconnect_points(int64_t p_id, int64_t p_with_id, bool bidirectional = true); + bool are_points_connected(int64_t p_id, int64_t p_with_id, bool bidirectional = true) const; - int get_point_count() const; - int get_point_capacity() const; - void reserve_space(int p_num_nodes); + int64_t get_point_count() const; + int64_t get_point_capacity() const; + void reserve_space(int64_t p_num_nodes); void clear(); - int get_closest_point(const Vector3 &p_point, bool p_include_disabled = false) const; + int64_t get_closest_point(const Vector3 &p_point, bool p_include_disabled = false) const; Vector3 get_closest_position_in_segment(const Vector3 &p_point) const; - Vector<Vector3> get_point_path(int p_from_id, int p_to_id); - Vector<int> get_id_path(int p_from_id, int p_to_id); + Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id); + Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id); AStar3D() {} ~AStar3D(); @@ -172,42 +166,42 @@ class AStar2D : public RefCounted { protected: static void _bind_methods(); - virtual real_t _estimate_cost(int p_from_id, int p_to_id); - virtual real_t _compute_cost(int p_from_id, int p_to_id); + virtual real_t _estimate_cost(int64_t p_from_id, int64_t p_to_id); + virtual real_t _compute_cost(int64_t p_from_id, int64_t p_to_id); GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) public: - int get_available_point_id() const; - - void add_point(int p_id, const Vector2 &p_pos, real_t p_weight_scale = 1); - Vector2 get_point_position(int p_id) const; - void set_point_position(int p_id, const Vector2 &p_pos); - real_t get_point_weight_scale(int p_id) const; - void set_point_weight_scale(int p_id, real_t p_weight_scale); - void remove_point(int p_id); - bool has_point(int p_id) const; - Vector<int> get_point_connections(int p_id); + int64_t get_available_point_id() const; + + void add_point(int64_t p_id, const Vector2 &p_pos, real_t p_weight_scale = 1); + Vector2 get_point_position(int64_t p_id) const; + void set_point_position(int64_t p_id, const Vector2 &p_pos); + real_t get_point_weight_scale(int64_t p_id) const; + void set_point_weight_scale(int64_t p_id, real_t p_weight_scale); + void remove_point(int64_t p_id); + bool has_point(int64_t p_id) const; + Vector<int64_t> get_point_connections(int64_t p_id); Array get_point_ids(); - void set_point_disabled(int p_id, bool p_disabled = true); - bool is_point_disabled(int p_id) const; + void set_point_disabled(int64_t p_id, bool p_disabled = true); + bool is_point_disabled(int64_t p_id) const; - void connect_points(int p_id, int p_with_id, bool p_bidirectional = true); - void disconnect_points(int p_id, int p_with_id); - bool are_points_connected(int p_id, int p_with_id) const; + void connect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional = true); + void disconnect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional = true); + bool are_points_connected(int64_t p_id, int64_t p_with_id, bool p_bidirectional = true) const; - int get_point_count() const; - int get_point_capacity() const; - void reserve_space(int p_num_nodes); + int64_t get_point_count() const; + int64_t get_point_capacity() const; + void reserve_space(int64_t p_num_nodes); void clear(); - int get_closest_point(const Vector2 &p_point, bool p_include_disabled = false) const; + int64_t get_closest_point(const Vector2 &p_point, bool p_include_disabled = false) const; Vector2 get_closest_position_in_segment(const Vector2 &p_point) const; - Vector<Vector2> get_point_path(int p_from_id, int p_to_id); - Vector<int> get_id_path(int p_from_id, int p_to_id); + Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id); + Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id); AStar2D() {} ~AStar2D() {} diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h index 8b244e9fe4..b3d63c0094 100644 --- a/core/math/audio_frame.h +++ b/core/math/audio_frame.h @@ -52,7 +52,7 @@ static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear2db(AUDIO_PEAK_OFFSET) struct AudioFrame { //left and right samples - float l, r; + float l = 0.f, r = 0.f; _ALWAYS_INLINE_ const float &operator[](int idx) const { return idx == 0 ? l : r; } _ALWAYS_INLINE_ float &operator[](int idx) { return idx == 0 ? l : r; } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 65353d8118..f8e7c47107 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -365,12 +365,12 @@ 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 { - return Basis(p_euler) * (*this); +Basis Basis::rotated(const Vector3 &p_euler, EulerOrder p_order) const { + return Basis::from_euler(p_euler, p_order) * (*this); } -void Basis::rotate(const Vector3 &p_euler) { - *this = rotated(p_euler); +void Basis::rotate(const Vector3 &p_euler, EulerOrder p_order) { + *this = rotated(p_euler, p_order); } Basis Basis::rotated(const Quaternion &p_quaternion) const { @@ -817,14 +817,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { #endif */ real_t angle, x, y, z; // variables for result - real_t epsilon = 0.01; // margin to allow for rounding errors - real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees + real_t angle_epsilon = 0.1; // margin to distinguish between 0 and 180 degrees - 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)) { + if ((Math::abs(rows[1][0] - rows[0][1]) < CMP_EPSILON) && (Math::abs(rows[2][0] - rows[0][2]) < CMP_EPSILON) && (Math::abs(rows[2][1] - rows[1][2]) < CMP_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(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)) { + if ((Math::abs(rows[1][0] + rows[0][1]) < angle_epsilon) && (Math::abs(rows[2][0] + rows[0][2]) < angle_epsilon) && (Math::abs(rows[2][1] + rows[1][2]) < angle_epsilon) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < angle_epsilon)) { // this singularity is identity matrix so angle = 0 r_axis = Vector3(0, 1, 0); r_angle = 0; @@ -839,7 +838,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { 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) { + if (xx < CMP_EPSILON) { x = 0; y = Math_SQRT12; z = Math_SQRT12; @@ -849,7 +848,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { z = xz / x; } } else if (yy > zz) { // rows[1][1] is the largest diagonal term - if (yy < epsilon) { + if (yy < CMP_EPSILON) { x = Math_SQRT12; y = 0; z = Math_SQRT12; @@ -859,7 +858,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { z = yz / y; } } else { // rows[2][2] is the largest diagonal term so base result on this - if (zz < epsilon) { + if (zz < CMP_EPSILON) { x = Math_SQRT12; y = Math_SQRT12; z = 0; @@ -935,9 +934,9 @@ void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Ve rotate(p_axis, p_angle); } -void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { +void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order) { _set_diagonal(p_scale); - rotate(p_euler); + rotate(p_euler, p_order); } void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale) { diff --git a/core/math/basis.h b/core/math/basis.h index 9cce22510b..4be325cdd2 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -56,6 +56,15 @@ struct _NO_DISCARD_ Basis { _FORCE_INLINE_ real_t determinant() const; + enum EulerOrder { + EULER_ORDER_XYZ, + EULER_ORDER_XZY, + EULER_ORDER_YXZ, + EULER_ORDER_YZX, + EULER_ORDER_ZXY, + EULER_ORDER_ZYX + }; + void from_z(const Vector3 &p_z); void rotate(const Vector3 &p_axis, real_t p_angle); @@ -64,21 +73,12 @@ struct _NO_DISCARD_ Basis { 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; + void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ); + Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const; void rotate(const Quaternion &p_quaternion); Basis rotated(const Quaternion &p_quaternion) const; - enum EulerOrder { - EULER_ORDER_XYZ, - EULER_ORDER_XZY, - EULER_ORDER_YXZ, - EULER_ORDER_YZX, - EULER_ORDER_ZXY, - EULER_ORDER_ZYX - }; - Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; @@ -119,7 +119,7 @@ struct _NO_DISCARD_ Basis { Vector3 get_scale_local() const; 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_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ); void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale); // transposed dot products diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 9443addd22..57c53b0adb 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -710,6 +710,11 @@ void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) { matrix[3][3] = 1; } +void CameraMatrix::add_jitter_offset(const Vector2 &p_offset) { + matrix[3][0] += p_offset.x; + matrix[3][1] += p_offset.y; +} + CameraMatrix::operator Transform3D() const { Transform3D tr; const real_t *m = &matrix[0][0]; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index f1aea5e4e8..a4051cee3b 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -95,6 +95,7 @@ struct CameraMatrix { operator String() const; void scale_translate_to_fit(const AABB &p_aabb); + void add_jitter_offset(const Vector2 &p_offset); void make_scale(const Vector3 &p_scale); int get_pixels_per_meter(int p_for_pixel_width) const; operator Transform3D() const; diff --git a/core/math/color.cpp b/core/math/color.cpp index 74552a2894..4bdeafd2f2 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -35,6 +35,8 @@ #include "core/string/print_string.h" #include "core/templates/rb_map.h" +#include "thirdparty/misc/ok_color.h" + uint32_t Color::to_argb32() const { uint32_t c = (uint8_t)Math::round(a * 255); c <<= 8; @@ -240,6 +242,20 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) { } } +void Color::set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha) { + ok_color::HSL hsl; + hsl.h = p_h; + hsl.s = p_s; + hsl.l = p_l; + ok_color new_ok_color; + ok_color::RGB rgb = new_ok_color.okhsl_to_srgb(hsl); + Color c = Color(rgb.r, rgb.g, rgb.b, p_alpha).clamp(); + r = c.r; + g = c.g; + b = c.b; + a = c.a; +} + bool Color::is_equal_approx(const Color &p_color) const { return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a); } @@ -568,3 +584,48 @@ Color Color::operator-() const { 1.0f - b, 1.0f - a); } + +Color Color::from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha) { + Color c; + c.set_ok_hsl(p_h, p_s, p_l, p_alpha); + return c; +} + +float Color::get_ok_hsl_h() const { + ok_color::RGB rgb; + rgb.r = r; + rgb.g = g; + rgb.b = b; + ok_color new_ok_color; + ok_color::HSL ok_hsl = new_ok_color.srgb_to_okhsl(rgb); + if (Math::is_nan(ok_hsl.h)) { + return 0.0f; + } + return CLAMP(ok_hsl.h, 0.0f, 1.0f); +} + +float Color::get_ok_hsl_s() const { + ok_color::RGB rgb; + rgb.r = r; + rgb.g = g; + rgb.b = b; + ok_color new_ok_color; + ok_color::HSL ok_hsl = new_ok_color.srgb_to_okhsl(rgb); + if (Math::is_nan(ok_hsl.s)) { + return 0.0f; + } + return CLAMP(ok_hsl.s, 0.0f, 1.0f); +} + +float Color::get_ok_hsl_l() const { + ok_color::RGB rgb; + rgb.r = r; + rgb.g = g; + rgb.b = b; + ok_color new_ok_color; + ok_color::HSL ok_hsl = new_ok_color.srgb_to_okhsl(rgb); + if (Math::is_nan(ok_hsl.l)) { + return 0.0f; + } + return CLAMP(ok_hsl.l, 0.0f, 1.0f); +} diff --git a/core/math/color.h b/core/math/color.h index 91e0bf5532..0afa6006a8 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -56,6 +56,10 @@ struct _NO_DISCARD_ Color { float get_s() const; float get_v() const; void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); + float get_ok_hsl_h() const; + float get_ok_hsl_s() const; + float get_ok_hsl_l() const; + void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0); _FORCE_INLINE_ float &operator[](int p_idx) { return components[p_idx]; @@ -195,6 +199,7 @@ struct _NO_DISCARD_ Color { static Color get_named_color(int p_idx); static Color from_string(const String &p_string, const Color &p_default); static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); + static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0); static Color from_rgbe9995(uint32_t p_rgbe); _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys @@ -213,6 +218,9 @@ struct _NO_DISCARD_ Color { _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v()); } _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v()); } _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v); } + _FORCE_INLINE_ void set_ok_hsl_h(float p_h) { set_ok_hsl(p_h, get_ok_hsl_s(), get_ok_hsl_l()); } + _FORCE_INLINE_ void set_ok_hsl_s(float p_s) { set_ok_hsl(get_ok_hsl_h(), p_s, get_ok_hsl_l()); } + _FORCE_INLINE_ void set_ok_hsl_l(float p_l) { set_ok_hsl(get_ok_hsl_h(), get_ok_hsl_s(), p_l); } _FORCE_INLINE_ Color() {} diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index f8a10ec87e..4ab00e1f34 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -101,7 +101,7 @@ class Delaunay3D { _FORCE_INLINE_ static uint32_t hash(const Triangle &p_triangle) { uint32_t h = hash_djb2_one_32(p_triangle.triangle[0]); h = hash_djb2_one_32(p_triangle.triangle[1], h); - return hash_djb2_one_32(p_triangle.triangle[2], h); + return hash_fmix32(hash_djb2_one_32(p_triangle.triangle[2], h)); } }; diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 97dc175d94..e230b69dc9 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -891,7 +891,7 @@ Expression::ENode *Expression::_parse_expression() { case TK_PERIOD: { //named indexing or function call _get_token(tk); - if (tk.type != TK_IDENTIFIER) { + if (tk.type != TK_IDENTIFIER && tk.type != TK_BUILTIN_FUNC) { _set_error("Expected identifier after '.'"); return nullptr; } @@ -1240,12 +1240,12 @@ bool Expression::_compile_expression() { return false; } -bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str) { +bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str) { switch (p_node->type) { case Expression::ENode::TYPE_INPUT: { const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node); if (in->index < 0 || in->index >= p_inputs.size()) { - r_error_str = vformat(RTR("Invalid input %i (not passed) in expression"), in->index); + r_error_str = vformat(RTR("Invalid input %d (not passed) in expression"), in->index); return true; } r_ret = p_inputs[in->index]; @@ -1266,7 +1266,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node); Variant a; - bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, r_error_str); + bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1274,7 +1274,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: Variant b; if (op->nodes[1]) { - ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str); + ret = _execute(p_inputs, p_instance, op->nodes[1], b, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1292,14 +1292,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::IndexNode *index = static_cast<const Expression::IndexNode *>(p_node); Variant base; - bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str); + bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str); if (ret) { return true; } Variant idx; - ret = _execute(p_inputs, p_instance, index->index, idx, r_error_str); + ret = _execute(p_inputs, p_instance, index->index, idx, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1316,7 +1316,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::NamedIndexNode *index = static_cast<const Expression::NamedIndexNode *>(p_node); Variant base; - bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str); + bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1336,7 +1336,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: arr.resize(array->array.size()); for (int i = 0; i < array->array.size(); i++) { Variant value; - bool ret = _execute(p_inputs, p_instance, array->array[i], value, r_error_str); + bool ret = _execute(p_inputs, p_instance, array->array[i], value, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1353,14 +1353,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: Dictionary d; for (int i = 0; i < dictionary->dict.size(); i += 2) { Variant key; - bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, r_error_str); + bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, p_const_calls_only, r_error_str); if (ret) { return true; } Variant value; - ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, r_error_str); + ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1380,7 +1380,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: for (int i = 0; i < constructor->arguments.size(); i++) { Variant value; - bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, r_error_str); + bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1408,7 +1408,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: for (int i = 0; i < bifunc->arguments.size(); i++) { Variant value; - bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, r_error_str); + bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1429,7 +1429,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::CallNode *call = static_cast<const Expression::CallNode *>(p_node); Variant base; - bool ret = _execute(p_inputs, p_instance, call->base, base, r_error_str); + bool ret = _execute(p_inputs, p_instance, call->base, base, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1442,7 +1442,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: for (int i = 0; i < call->arguments.size(); i++) { Variant value; - ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str); + ret = _execute(p_inputs, p_instance, call->arguments[i], value, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1452,7 +1452,11 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: } Callable::CallError ce; - base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); + if (p_const_calls_only) { + base.call_const(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); + } else { + 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)); @@ -1491,13 +1495,13 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu return OK; } -Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) { +Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error, bool p_const_calls_only) { ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + "."); execution_error = false; Variant output; String error_txt; - bool err = _execute(p_inputs, p_base, root, output, error_txt); + bool err = _execute(p_inputs, p_base, root, output, p_const_calls_only, error_txt); if (err) { execution_error = true; error_str = error_txt; @@ -1517,7 +1521,7 @@ String Expression::get_error_text() const { void Expression::_bind_methods() { ClassDB::bind_method(D_METHOD("parse", "expression", "input_names"), &Expression::parse, DEFVAL(Vector<String>())); - ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error", "const_calls_only"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("has_execute_failed"), &Expression::has_execute_failed); ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text); } diff --git a/core/math/expression.h b/core/math/expression.h index 6ea3c1611f..2d58915996 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -257,14 +257,14 @@ private: Vector<String> input_names; bool execution_error = false; - bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str); + bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str); protected: static void _bind_methods(); public: Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>()); - Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true); + Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true, bool p_const_calls_only = false); bool has_execute_failed() const; String get_error_text() const; diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 068bc0397e..53deb9bd42 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -253,6 +253,27 @@ public: (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight)); } + static _ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + double omt = (1.0 - p_t); + double omt2 = omt * omt; + double omt3 = omt2 * omt; + double t2 = p_t * p_t; + double t3 = t2 * p_t; + + return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; + } + static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + float omt = (1.0f - p_t); + float omt2 = omt * omt; + float omt3 = omt2 * omt; + float t2 = p_t * p_t; + float t3 = t2 * p_t; + + return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3; + } + static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) { double difference = fmod(p_to - p_from, Math_TAU); double distance = fmod(2.0 * difference, Math_TAU) - difference; @@ -302,11 +323,19 @@ public: } static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { double range = max - min; - return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + double result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + if (is_equal_approx(result, max)) { + return min; + } + return result; } static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) { float range = max - min; - return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + float result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + if (is_equal_approx(result, max)) { + return min; + } + return result; } static _ALWAYS_INLINE_ float fract(float value) { diff --git a/core/math/octree.h b/core/math/octree.h deleted file mode 100644 index 8dd103f109..0000000000 --- a/core/math/octree.h +++ /dev/null @@ -1,1271 +0,0 @@ -/*************************************************************************/ -/* octree.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 OCTREE_H -#define OCTREE_H - -#include "core/math/aabb.h" -#include "core/math/geometry_3d.h" -#include "core/math/vector3.h" -#include "core/string/print_string.h" -#include "core/templates/list.h" -#include "core/templates/rb_map.h" -#include "core/variant/variant.h" - -typedef uint32_t OctreeElementID; - -#define OCTREE_ELEMENT_INVALID_ID 0 -#define OCTREE_SIZE_LIMIT 1e15 - -template <class T, bool use_pairs = false, class AL = DefaultAllocator> -class Octree { -public: - typedef void *(*PairCallback)(void *, OctreeElementID, T *, int, OctreeElementID, T *, int); - typedef void (*UnpairCallback)(void *, OctreeElementID, T *, int, OctreeElementID, T *, int, void *); - -private: - enum { - NEG = 0, - POS = 1, - }; - - enum { - OCTANT_NX_NY_NZ, - OCTANT_PX_NY_NZ, - OCTANT_NX_PY_NZ, - OCTANT_PX_PY_NZ, - OCTANT_NX_NY_PZ, - OCTANT_PX_NY_PZ, - OCTANT_NX_PY_PZ, - OCTANT_PX_PY_PZ - }; - - struct PairKey { - union { - struct { - OctreeElementID A; - OctreeElementID B; - }; - uint64_t key; - }; - - _FORCE_INLINE_ bool operator<(const PairKey &p_pair) const { - return key < p_pair.key; - } - - _FORCE_INLINE_ PairKey(OctreeElementID p_A, OctreeElementID p_B) { - if (p_A < p_B) { - A = p_A; - B = p_B; - } else { - B = p_A; - A = p_B; - } - } - - _FORCE_INLINE_ PairKey() {} - }; - - struct Element; - - struct Octant { - // cached for FAST plane check - AABB aabb; - - uint64_t last_pass = 0; - Octant *parent = nullptr; - Octant *children[8] = { nullptr }; - - int children_count = 0; // cache for amount of children (fast check for removal) - int parent_index = -1; // cache for parent index (fast check for removal) - - List<Element *, AL> pairable_elements; - List<Element *, AL> elements; - - Octant() {} - ~Octant() {} - }; - - struct PairData; - - struct Element { - Octree *octree = nullptr; - - T *userdata = nullptr; - int subindex = 0; - bool pairable = false; - uint32_t pairable_mask = 0; - uint32_t pairable_type = 0; - - uint64_t last_pass = 0; - OctreeElementID _id = 0; - Octant *common_parent = nullptr; - - AABB aabb; - AABB container_aabb; - - List<PairData *, AL> pair_list; - - struct OctantOwner { - Octant *octant = nullptr; - typename List<Element *, AL>::Element *E; - }; // an element can be in max 8 octants - - List<OctantOwner, AL> octant_owners; - - Element() {} - }; - - struct PairData { - int refcount; - bool intersect; - Element *A, *B; - void *ud = nullptr; - typename List<PairData *, AL>::Element *eA, *eB; - }; - - typedef HashMap<OctreeElementID, Element, Comparator<OctreeElementID>, AL> ElementMap; - typedef HashMap<PairKey, PairData, Comparator<PairKey>, AL> PairMap; - ElementMap element_map; - PairMap pair_map; - - PairCallback pair_callback = nullptr; - UnpairCallback unpair_callback = nullptr; - void *pair_callback_userdata = nullptr; - void *unpair_callback_userdata = nullptr; - - OctreeElementID last_element_id = 1; - uint64_t pass = 1; - - 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); - - if (intersect != p_pair->intersect) { - if (intersect) { - if (pair_callback) { - p_pair->ud = pair_callback(pair_callback_userdata, p_pair->A->_id, p_pair->A->userdata, p_pair->A->subindex, p_pair->B->_id, p_pair->B->userdata, p_pair->B->subindex); - } - pair_count++; - } else { - if (unpair_callback) { - unpair_callback(pair_callback_userdata, p_pair->A->_id, p_pair->A->userdata, p_pair->A->subindex, p_pair->B->_id, p_pair->B->userdata, p_pair->B->subindex, p_pair->ud); - } - pair_count--; - } - - p_pair->intersect = intersect; - } - } - - _FORCE_INLINE_ void _pair_reference(Element *p_A, Element *p_B) { - if (p_A == p_B || (p_A->userdata == p_B->userdata && p_A->userdata)) { - return; - } - - if (!(p_A->pairable_type & p_B->pairable_mask) && - !(p_B->pairable_type & p_A->pairable_mask)) { - return; // none can pair with none - } - - PairKey key(p_A->_id, p_B->_id); - typename PairMap::Element *E = pair_map.find(key); - - if (!E) { - PairData pdata; - pdata.refcount = 1; - pdata.A = p_A; - pdata.B = p_B; - pdata.intersect = false; - E = pair_map.insert(key, pdata); - E->get().eA = p_A->pair_list.push_back(&E->get()); - E->get().eB = p_B->pair_list.push_back(&E->get()); - } else { - E->get().refcount++; - } - } - - _FORCE_INLINE_ void _pair_unreference(Element *p_A, Element *p_B) { - if (p_A == p_B) { - return; - } - - PairKey key(p_A->_id, p_B->_id); - typename PairMap::Element *E = pair_map.find(key); - if (!E) { - return; // no pair - } - - E->get().refcount--; - - if (E->get().refcount == 0) { - // bye pair - - if (E->get().intersect) { - if (unpair_callback) { - unpair_callback(pair_callback_userdata, p_A->_id, p_A->userdata, p_A->subindex, p_B->_id, p_B->userdata, p_B->subindex, E->get().ud); - } - - pair_count--; - } - - if (p_A == E->get().B) { - //may be reaching inverted - SWAP(p_A, p_B); - } - - p_A->pair_list.erase(E->get().eA); - p_B->pair_list.erase(E->get().eB); - pair_map.erase(E); - } - } - - _FORCE_INLINE_ void _element_check_pairs(Element *p_element) { - typename List<PairData *, AL>::Element *E = p_element->pair_list.front(); - while (E) { - _pair_check(E->get()); - E = E->next(); - } - } - - _FORCE_INLINE_ void _optimize() { - while (root && root->children_count < 2 && !root->elements.size() && !(use_pairs && root->pairable_elements.size())) { - Octant *new_root = nullptr; - if (root->children_count == 1) { - for (int i = 0; i < 8; i++) { - if (root->children[i]) { - new_root = root->children[i]; - root->children[i] = nullptr; - break; - } - } - ERR_FAIL_COND(!new_root); - new_root->parent = nullptr; - new_root->parent_index = -1; - } - - memdelete_allocator<Octant, AL>(root); - octant_count--; - root = new_root; - } - } - - void _insert_element(Element *p_element, Octant *p_octant); - void _ensure_valid_root(const AABB &p_aabb); - bool _remove_element_from_octant(Element *p_element, Octant *p_octant, Octant *p_limit = nullptr); - void _remove_element(Element *p_element); - void _pair_element(Element *p_element, Octant *p_octant); - void _unpair_element(Element *p_element, Octant *p_octant); - - struct _CullConvexData { - const Plane *planes; - int plane_count; - const Vector3 *points; - int point_count; - T **result_array; - int *result_idx = nullptr; - int result_max; - uint32_t mask; - }; - - void _cull_convex(Octant *p_octant, _CullConvexData *p_cull); - void _cull_aabb(Octant *p_octant, const AABB &p_aabb, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask); - void _cull_segment(Octant *p_octant, const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask); - void _cull_point(Octant *p_octant, const Vector3 &p_point, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask); - - void _remove_tree(Octant *p_octant) { - if (!p_octant) { - return; - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _remove_tree(p_octant->children[i]); - } - } - - memdelete_allocator<Octant, AL>(p_octant); - } - -public: - OctreeElementID create(T *p_userdata, const AABB &p_aabb = AABB(), int p_subindex = 0, bool p_pairable = false, uint32_t p_pairable_type = 0, uint32_t pairable_mask = 1); - void move(OctreeElementID p_id, const AABB &p_aabb); - void set_pairable(OctreeElementID p_id, bool p_pairable = false, uint32_t p_pairable_type = 0, uint32_t pairable_mask = 1); - void erase(OctreeElementID p_id); - - bool is_pairable(OctreeElementID p_id) const; - T *get(OctreeElementID p_id) const; - int get_subindex(OctreeElementID p_id) const; - - int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask = 0xFFFFFFFF); - int cull_aabb(const AABB &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF); - int cull_segment(const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF); - - int cull_point(const Vector3 &p_point, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF); - - void set_pair_callback(PairCallback p_callback, void *p_userdata); - void set_unpair_callback(UnpairCallback p_callback, void *p_userdata); - - int get_octant_count() const { return octant_count; } - int get_pair_count() const { return pair_count; } - Octree(real_t p_unit_size = 1.0); - ~Octree() { _remove_tree(root); } -}; - -/* PRIVATE FUNCTIONS */ - -template <class T, bool use_pairs, class AL> -T *Octree<T, use_pairs, AL>::get(OctreeElementID p_id) const { - const typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, nullptr); - return E->get().userdata; -} - -template <class T, bool use_pairs, class AL> -bool Octree<T, use_pairs, AL>::is_pairable(OctreeElementID p_id) const { - const typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, false); - return E->get().pairable; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::get_subindex(OctreeElementID p_id) const { - const typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, -1); - return E->get().subindex; -} - -#define OCTREE_DIVISOR 4 - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_insert_element(Element *p_element, Octant *p_octant) { - real_t element_size = p_element->aabb.get_longest_axis_size() * 1.01; // avoid precision issues - - if (p_octant->aabb.size.x / OCTREE_DIVISOR < element_size) { - //if (p_octant->aabb.size.x*0.5 < element_size) { - /* at smallest possible size for the element */ - typename Element::OctantOwner owner; - owner.octant = p_octant; - - if (use_pairs && p_element->pairable) { - p_octant->pairable_elements.push_back(p_element); - owner.E = p_octant->pairable_elements.back(); - } else { - p_octant->elements.push_back(p_element); - owner.E = p_octant->elements.back(); - } - - p_element->octant_owners.push_back(owner); - - if (p_element->common_parent == nullptr) { - p_element->common_parent = p_octant; - p_element->container_aabb = p_octant->aabb; - } else { - p_element->container_aabb.merge_with(p_octant->aabb); - } - - if (use_pairs && p_octant->children_count > 0) { - pass++; //elements below this only get ONE reference added - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _pair_element(p_element, p_octant->children[i]); - } - } - } - } else { - /* not big enough, send it to subitems */ - int splits = 0; - bool candidate = p_element->common_parent == nullptr; - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - /* element exists, go straight to it */ - if (p_octant->children[i]->aabb.intersects_inclusive(p_element->aabb)) { - _insert_element(p_element, p_octant->children[i]); - splits++; - } - } else { - /* check against AABB where child should be */ - - AABB aabb = p_octant->aabb; - aabb.size *= 0.5; - - if (i & 1) { - aabb.position.x += aabb.size.x; - } - if (i & 2) { - aabb.position.y += aabb.size.y; - } - if (i & 4) { - aabb.position.z += aabb.size.z; - } - - if (aabb.intersects_inclusive(p_element->aabb)) { - /* if actually intersects, create the child */ - - Octant *child = memnew_allocator(Octant, AL); - p_octant->children[i] = child; - child->parent = p_octant; - child->parent_index = i; - - child->aabb = aabb; - - p_octant->children_count++; - - _insert_element(p_element, child); - octant_count++; - splits++; - } - } - } - - if (candidate && splits > 1) { - p_element->common_parent = p_octant; - } - } - - if (use_pairs) { - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - - while (E) { - _pair_reference(p_element, E->get()); - E = E->next(); - } - - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - _pair_reference(p_element, E->get()); - E = E->next(); - } - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_ensure_valid_root(const AABB &p_aabb) { - if (!root) { - // octre is empty - - AABB base(Vector3(), Vector3(1.0, 1.0, 1.0) * unit_size); - - while (!base.encloses(p_aabb)) { - if (ABS(base.position.x + base.size.x) <= ABS(base.position.x)) { - /* grow towards positive */ - base.size *= 2.0; - } else { - base.position -= base.size; - base.size *= 2.0; - } - } - - root = memnew_allocator(Octant, AL); - - root->parent = nullptr; - root->parent_index = -1; - root->aabb = base; - - octant_count++; - - } else { - AABB base = root->aabb; - - while (!base.encloses(p_aabb)) { - ERR_FAIL_COND_MSG(base.size.x > OCTREE_SIZE_LIMIT, "Octree upper size limit reached, does the AABB supplied contain NAN?"); - - Octant *gp = memnew_allocator(Octant, AL); - octant_count++; - root->parent = gp; - - if (ABS(base.position.x + base.size.x) <= ABS(base.position.x)) { - /* grow towards positive */ - base.size *= 2.0; - gp->aabb = base; - gp->children[0] = root; - root->parent_index = 0; - } else { - base.position -= base.size; - base.size *= 2.0; - gp->aabb = base; - gp->children[(1 << 0) | (1 << 1) | (1 << 2)] = root; // add at all-positive - root->parent_index = (1 << 0) | (1 << 1) | (1 << 2); - } - - gp->children_count = 1; - root = gp; - } - } -} - -template <class T, bool use_pairs, class AL> -bool Octree<T, use_pairs, AL>::_remove_element_from_octant(Element *p_element, Octant *p_octant, Octant *p_limit) { - bool octant_removed = false; - - while (true) { - // check all exit conditions - - if (p_octant == p_limit) { // reached limit, nothing to erase, exit - return octant_removed; - } - - bool unpaired = false; - - if (use_pairs && p_octant->last_pass != pass) { - // check whether we should unpair stuff - // always test pairable - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - while (E) { - _pair_unreference(p_element, E->get()); - E = E->next(); - } - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - _pair_unreference(p_element, E->get()); - E = E->next(); - } - } - p_octant->last_pass = pass; - unpaired = true; - } - - bool removed = false; - - Octant *parent = p_octant->parent; - - if (p_octant->children_count == 0 && p_octant->elements.is_empty() && p_octant->pairable_elements.is_empty()) { - // erase octant - - if (p_octant == root) { // won't have a parent, just erase - - root = nullptr; - } else { - ERR_FAIL_INDEX_V(p_octant->parent_index, 8, octant_removed); - - parent->children[p_octant->parent_index] = nullptr; - parent->children_count--; - } - - memdelete_allocator<Octant, AL>(p_octant); - octant_count--; - removed = true; - octant_removed = true; - } - - if (!removed && !unpaired) { - return octant_removed; // no reason to keep going up anymore! was already visited and was not removed - } - - p_octant = parent; - } - - return octant_removed; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_unpair_element(Element *p_element, Octant *p_octant) { - // always test pairable - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - while (E) { - if (E->get()->last_pass != pass) { // only remove ONE reference - _pair_unreference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - if (E->get()->last_pass != pass) { // only remove ONE reference - _pair_unreference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - } - - p_octant->last_pass = pass; - - if (p_octant->children_count == 0) { - return; // small optimization for leafs - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _unpair_element(p_element, p_octant->children[i]); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_pair_element(Element *p_element, Octant *p_octant) { - // always test pairable - - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - - while (E) { - if (E->get()->last_pass != pass) { // only get ONE reference - _pair_reference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - if (E->get()->last_pass != pass) { // only get ONE reference - _pair_reference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - } - p_octant->last_pass = pass; - - if (p_octant->children_count == 0) { - return; // small optimization for leafs - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _pair_element(p_element, p_octant->children[i]); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_remove_element(Element *p_element) { - pass++; // will do a new pass for this - - typename List<typename Element::OctantOwner, AL>::Element *I = p_element->octant_owners.front(); - - /* FIRST remove going up normally */ - for (; I; I = I->next()) { - Octant *o = I->get().octant; - - if (!use_pairs) { // small speedup - o->elements.erase(I->get().E); - } - - _remove_element_from_octant(p_element, o); - } - - /* THEN remove going down */ - - I = p_element->octant_owners.front(); - - if (use_pairs) { - for (; I; I = I->next()) { - Octant *o = I->get().octant; - - // erase children pairs, they are erased ONCE even if repeated - pass++; - for (int i = 0; i < 8; i++) { - if (o->children[i]) { - _unpair_element(p_element, o->children[i]); - } - } - - if (p_element->pairable) { - o->pairable_elements.erase(I->get().E); - } else { - o->elements.erase(I->get().E); - } - } - } - - p_element->octant_owners.clear(); - - if (use_pairs) { - int remaining = p_element->pair_list.size(); - //p_element->pair_list.clear(); - ERR_FAIL_COND(remaining); - } -} - -template <class T, bool use_pairs, class AL> -OctreeElementID Octree<T, use_pairs, AL>::create(T *p_userdata, const AABB &p_aabb, int p_subindex, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) { -// check for AABB validity -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_V(p_aabb.position.x > 1e15 || p_aabb.position.x < -1e15, 0); - ERR_FAIL_COND_V(p_aabb.position.y > 1e15 || p_aabb.position.y < -1e15, 0); - ERR_FAIL_COND_V(p_aabb.position.z > 1e15 || p_aabb.position.z < -1e15, 0); - ERR_FAIL_COND_V(p_aabb.size.x > 1e15 || p_aabb.size.x < 0.0, 0); - ERR_FAIL_COND_V(p_aabb.size.y > 1e15 || p_aabb.size.y < 0.0, 0); - ERR_FAIL_COND_V(p_aabb.size.z > 1e15 || p_aabb.size.z < 0.0, 0); - ERR_FAIL_COND_V(Math::is_nan(p_aabb.size.x), 0); - ERR_FAIL_COND_V(Math::is_nan(p_aabb.size.y), 0); - ERR_FAIL_COND_V(Math::is_nan(p_aabb.size.z), 0); - -#endif - typename ElementMap::Element *E = element_map.insert(last_element_id++, - Element()); - Element &e = E->get(); - - e.aabb = p_aabb; - e.userdata = p_userdata; - e.subindex = p_subindex; - e.last_pass = 0; - e.octree = this; - e.pairable = p_pairable; - e.pairable_type = p_pairable_type; - e.pairable_mask = p_pairable_mask; - e._id = last_element_id - 1; - - if (!e.aabb.has_no_surface()) { - _ensure_valid_root(p_aabb); - _insert_element(&e, root); - if (use_pairs) { - _element_check_pairs(&e); - } - } - - return last_element_id - 1; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::move(OctreeElementID p_id, const AABB &p_aabb) { -#ifdef DEBUG_ENABLED - // check for AABB validity - ERR_FAIL_COND(p_aabb.position.x > 1e15 || p_aabb.position.x < -1e15); - ERR_FAIL_COND(p_aabb.position.y > 1e15 || p_aabb.position.y < -1e15); - ERR_FAIL_COND(p_aabb.position.z > 1e15 || p_aabb.position.z < -1e15); - ERR_FAIL_COND(p_aabb.size.x > 1e15 || p_aabb.size.x < 0.0); - ERR_FAIL_COND(p_aabb.size.y > 1e15 || p_aabb.size.y < 0.0); - ERR_FAIL_COND(p_aabb.size.z > 1e15 || p_aabb.size.z < 0.0); - ERR_FAIL_COND(Math::is_nan(p_aabb.size.x)); - ERR_FAIL_COND(Math::is_nan(p_aabb.size.y)); - ERR_FAIL_COND(Math::is_nan(p_aabb.size.z)); -#endif - typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - Element &e = E->get(); - - bool old_has_surf = !e.aabb.has_no_surface(); - bool new_has_surf = !p_aabb.has_no_surface(); - - if (old_has_surf != new_has_surf) { - if (old_has_surf) { - _remove_element(&e); // removing - e.common_parent = nullptr; - e.aabb = AABB(); - _optimize(); - } else { - _ensure_valid_root(p_aabb); // inserting - e.common_parent = nullptr; - e.aabb = p_aabb; - _insert_element(&e, root); - if (use_pairs) { - _element_check_pairs(&e); - } - } - - return; - } - - if (!old_has_surf) { // doing nothing - return; - } - - // it still is enclosed in the same AABB it was assigned to - if (e.container_aabb.encloses(p_aabb)) { - e.aabb = p_aabb; - if (use_pairs) { - _element_check_pairs(&e); // must check pairs anyway - } - - return; - } - - AABB combined = e.aabb; - combined.merge_with(p_aabb); - _ensure_valid_root(combined); - - ERR_FAIL_COND(e.octant_owners.front() == nullptr); - - /* FIND COMMON PARENT */ - - List<typename Element::OctantOwner, AL> owners = e.octant_owners; // save the octant owners - Octant *common_parent = e.common_parent; - ERR_FAIL_COND(!common_parent); - - //src is now the place towards where insertion is going to happen - pass++; - - while (common_parent && !common_parent->aabb.encloses(p_aabb)) { - common_parent = common_parent->parent; - } - - ERR_FAIL_COND(!common_parent); - - //prepare for reinsert - e.octant_owners.clear(); - e.common_parent = nullptr; - e.aabb = p_aabb; - - _insert_element(&e, common_parent); // reinsert from this point - - pass++; - - for (typename List<typename Element::OctantOwner, AL>::Element *F = owners.front(); F;) { - Octant *o = F->get().octant; - typename List<typename Element::OctantOwner, AL>::Element *N = F->next(); - - if (use_pairs && e.pairable) { - o->pairable_elements.erase(F->get().E); - } else { - o->elements.erase(F->get().E); - } - - if (_remove_element_from_octant(&e, o, common_parent->parent)) { - owners.erase(F); - } - - F = N; - } - - if (use_pairs) { - //unpair child elements in anything that survived - for (typename List<typename Element::OctantOwner, AL>::Element *F = owners.front(); F; F = F->next()) { - Octant *o = F->get().octant; - - // erase children pairs, unref ONCE - pass++; - for (int i = 0; i < 8; i++) { - if (o->children[i]) { - _unpair_element(&e, o->children[i]); - } - } - } - - _element_check_pairs(&e); - } - - _optimize(); -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::set_pairable(OctreeElementID p_id, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) { - typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - - Element &e = E->get(); - - if (p_pairable == e.pairable && e.pairable_type == p_pairable_type && e.pairable_mask == p_pairable_mask) { - return; // no changes, return - } - - if (!e.aabb.has_no_surface()) { - _remove_element(&e); - } - - e.pairable = p_pairable; - e.pairable_type = p_pairable_type; - e.pairable_mask = p_pairable_mask; - e.common_parent = nullptr; - - if (!e.aabb.has_no_surface()) { - _ensure_valid_root(e.aabb); - _insert_element(&e, root); - if (use_pairs) { - _element_check_pairs(&e); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::erase(OctreeElementID p_id) { - typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - - Element &e = E->get(); - - if (!e.aabb.has_no_surface()) { - _remove_element(&e); - } - - element_map.erase(p_id); - _optimize(); -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_convex(Octant *p_octant, _CullConvexData *p_cull) { - if (*p_cull->result_idx == p_cull->result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_cull->mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) { - if (*p_cull->result_idx < p_cull->result_max) { - p_cull->result_array[*p_cull->result_idx] = e->userdata; - (*p_cull->result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_cull->mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) { - if (*p_cull->result_idx < p_cull->result_max) { - p_cull->result_array[*p_cull->result_idx] = e->userdata; - (*p_cull->result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) { - _cull_convex(p_octant->children[i], p_cull); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_aabb(Octant *p_octant, const AABB &p_aabb, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (*p_result_idx == p_result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (p_aabb.intersects_inclusive(e->aabb)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - - (*p_result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (p_aabb.intersects_inclusive(e->aabb)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - (*p_result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_inclusive(p_aabb)) { - _cull_aabb(p_octant->children[i], p_aabb, p_result_array, p_result_idx, p_result_max, p_subindex_array, p_mask); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_segment(Octant *p_octant, const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (*p_result_idx == p_result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.intersects_segment(p_from, p_to)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - - e->last_pass = pass; - - if (e->aabb.intersects_segment(p_from, p_to)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_segment(p_from, p_to)) { - _cull_segment(p_octant->children[i], p_from, p_to, p_result_array, p_result_idx, p_result_max, p_subindex_array, p_mask); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_point(Octant *p_octant, const Vector3 &p_point, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (*p_result_idx == p_result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.has_point(p_point)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - - e->last_pass = pass; - - if (e->aabb.has_point(p_point)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - //could be optimized.. - if (p_octant->children[i] && p_octant->children[i]->aabb.has_point(p_point)) { - _cull_point(p_octant->children[i], p_point, p_result_array, p_result_idx, p_result_max, p_subindex_array, p_mask); - } - } -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask) { - if (!root || p_convex.size() == 0) { - return 0; - } - - Vector<Vector3> convex_points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); - if (convex_points.size() == 0) { - return 0; - } - - int result_count = 0; - pass++; - _CullConvexData cdata; - cdata.planes = &p_convex[0]; - cdata.plane_count = p_convex.size(); - cdata.points = &convex_points[0]; - cdata.point_count = convex_points.size(); - cdata.result_array = p_result_array; - cdata.result_max = p_result_max; - cdata.result_idx = &result_count; - cdata.mask = p_mask; - - _cull_convex(root, &cdata); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_aabb(const AABB &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (!root) { - return 0; - } - - int result_count = 0; - pass++; - _cull_aabb(root, p_aabb, p_result_array, &result_count, p_result_max, p_subindex_array, p_mask); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_segment(const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (!root) { - return 0; - } - - int result_count = 0; - pass++; - _cull_segment(root, p_from, p_to, p_result_array, &result_count, p_result_max, p_subindex_array, p_mask); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_point(const Vector3 &p_point, T **p_result_array, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (!root) { - return 0; - } - - int result_count = 0; - pass++; - _cull_point(root, p_point, p_result_array, &result_count, p_result_max, p_subindex_array, p_mask); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::set_pair_callback(PairCallback p_callback, void *p_userdata) { - pair_callback = p_callback; - pair_callback_userdata = p_userdata; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::set_unpair_callback(UnpairCallback p_callback, void *p_userdata) { - unpair_callback = p_callback; - unpair_callback_userdata = p_userdata; -} - -template <class T, bool use_pairs, class AL> -Octree<T, use_pairs, AL>::Octree(real_t p_unit_size) { - unit_size = p_unit_size; -} - -#endif // OCTREE_H diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 54461bf70f..4433559e6d 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -104,9 +104,11 @@ void TriangleMesh::get_indices(Vector<int> *r_triangles_indices) const { } } -void TriangleMesh::create(const Vector<Vector3> &p_faces) { +void TriangleMesh::create(const Vector<Vector3> &p_faces, const Vector<int32_t> &p_surface_indices) { valid = false; + ERR_FAIL_COND(p_surface_indices.size() && p_surface_indices.size() != p_faces.size()); + int fc = p_faces.size(); ERR_FAIL_COND(!fc || ((fc % 3) != 0)); fc /= 3; @@ -121,6 +123,7 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces) { //goes in-place. const Vector3 *r = p_faces.ptr(); + const int32_t *si = p_surface_indices.ptr(); Triangle *w = triangles.ptrw(); HashMap<Vector3, int> db; @@ -148,6 +151,7 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces) { } f.normal = Face3(r[i * 3 + 0], r[i * 3 + 1], r[i * 3 + 2]).get_plane().get_normal(); + f.surface_index = si ? si[i] : 0; bw[i].left = -1; bw[i].right = -1; @@ -264,7 +268,7 @@ Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const { return n; } -bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const { +bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const { uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); enum { @@ -317,6 +321,9 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en d = nd; r_point = res; r_normal = f3.get_plane().get_normal(); + if (r_surf_index) { + *r_surf_index = s.surface_index; + } inters = true; } } @@ -366,7 +373,7 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en return inters; } -bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const { +bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const { uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); enum { @@ -417,6 +424,9 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V d = nd; r_point = res; r_normal = f3.get_plane().get_normal(); + if (r_surf_index) { + *r_surf_index = s.surface_index; + } inters = true; } } diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 1b99945698..166b4adb7a 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -41,6 +41,7 @@ public: struct Triangle { Vector3 normal; int indices[3]; + int32_t surface_index; }; private: @@ -81,8 +82,8 @@ private: public: bool is_valid() const; - bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const; - bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const; + bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; + bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; bool intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const; bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const; Vector3 get_area_normal(const AABB &p_aabb) const; @@ -92,7 +93,7 @@ public: const Vector<Vector3> &get_vertices() const { return vertices; } void get_indices(Vector<int> *r_triangles_indices) const; - void create(const Vector<Vector3> &p_faces); + void create(const Vector<Vector3> &p_faces, const Vector<int32_t> &p_surface_indices = Vector<int32_t>()); TriangleMesh(); }; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index a27227905c..d9b5d55454 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -152,13 +152,6 @@ Vector2 Vector2::limit_length(const real_t p_len) const { return v; } -Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const { - Vector2 res = *this; - res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); - res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); - return res; -} - Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const { Vector2 v = *this; Vector2 vd = p_to - v; diff --git a/core/math/vector2.h b/core/math/vector2.h index bd67299f33..91d3d3a56b 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -113,7 +113,9 @@ struct _NO_DISCARD_ Vector2 { _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const; _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const; - Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const; + Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const; Vector2 slide(const Vector2 &p_normal) const; @@ -261,6 +263,26 @@ Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const { return rotated(angle * p_weight) * (result_length / start_length); } +Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const { + Vector2 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + return res; +} + +Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const { + Vector2 res = *this; + + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - p_t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = p_t * p_t; + real_t t3 = t2 * p_t; + + return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +} + Vector2 Vector2::direction_to(const Vector2 &p_to) const { Vector2 ret(p_to.x - x, p_to.y - y); ret.normalize(); diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index f94f39b7f2..d71d365053 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -85,14 +85,6 @@ Vector3 Vector3::limit_length(const real_t p_len) const { return v; } -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 res = *this; - res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); - res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); - res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight); - return res; -} - Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const { Vector3 v = *this; Vector3 vd = p_to - v; diff --git a/core/math/vector3.h b/core/math/vector3.h index 8891532f42..970416234d 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -104,7 +104,9 @@ struct _NO_DISCARD_ Vector3 { _FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const; _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const; - Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const; + Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; Vector2 octahedron_encode() const; @@ -227,6 +229,27 @@ Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length); } +Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const { + Vector3 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight); + return res; +} + +Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const { + Vector3 res = *this; + + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - p_t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = p_t * p_t; + real_t t3 = t2 * p_t; + + return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +} + real_t Vector3::distance_to(const Vector3 &p_to) const { return (p_to - *this).length(); } diff --git a/core/multiplayer/multiplayer.h b/core/multiplayer/multiplayer.h index 5eb968171a..f4c965b0f8 100644 --- a/core/multiplayer/multiplayer.h +++ b/core/multiplayer/multiplayer.h @@ -46,7 +46,7 @@ enum TransferMode { enum RPCMode { RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) RPC_MODE_ANY_PEER, // Any peer can call this RPC - RPC_MODE_AUTHORITY, // / Only the node's multiplayer authority (server by default) can call this RPC + RPC_MODE_AUTHORITY, // Only the node's multiplayer authority (server by default) can call this RPC }; struct RPCConfig { diff --git a/core/multiplayer/multiplayer_peer.cpp b/core/multiplayer/multiplayer_peer.cpp index ae3b139bcc..b262903ce8 100644 --- a/core/multiplayer/multiplayer_peer.cpp +++ b/core/multiplayer/multiplayer_peer.cpp @@ -36,17 +36,18 @@ uint32_t MultiplayerPeer::generate_unique_id() const { uint32_t hash = 0; while (hash == 0 || hash == 1) { - hash = hash_djb2_one_32( + hash = hash_murmur3_one_32( (uint32_t)OS::get_singleton()->get_ticks_usec()); - hash = hash_djb2_one_32( + hash = hash_murmur3_one_32( (uint32_t)OS::get_singleton()->get_unix_time(), hash); - hash = hash_djb2_one_32( + hash = hash_murmur3_one_32( (uint32_t)OS::get_singleton()->get_user_data_dir().hash64(), hash); - hash = hash_djb2_one_32( + hash = hash_murmur3_one_32( (uint32_t)((uint64_t)this), hash); // Rely on ASLR heap - hash = hash_djb2_one_32( + hash = hash_murmur3_one_32( (uint32_t)((uint64_t)&hash), hash); // Rely on ASLR stack + hash = hash_fmix32(hash); hash = hash & 0x7FFFFFFF; // Make it compatible with unsigned, since negative ID is used for exclusion } diff --git a/core/object/callable_method_pointer.cpp b/core/object/callable_method_pointer.cpp index 1bf926cafc..81f8ab6be2 100644 --- a/core/object/callable_method_pointer.cpp +++ b/core/object/callable_method_pointer.cpp @@ -85,9 +85,9 @@ void CallableCustomMethodPointerBase::_setup(uint32_t *p_base_ptr, uint32_t p_pt // Precompute hash. for (uint32_t i = 0; i < comp_size; i++) { if (i == 0) { - h = hash_djb2_one_32(comp_ptr[i]); + h = hash_murmur3_one_32(comp_ptr[i]); } else { - h = hash_djb2_one_32(comp_ptr[i], h); + h = hash_murmur3_one_32(comp_ptr[i], h); } } } diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index f61bd24efd..ac008dad88 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -164,7 +164,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { OBJTYPE_RLOCK; #ifdef DEBUG_METHODS_ENABLED - uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); + uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); List<StringName> class_list; ClassDB::get_class_list(&class_list); @@ -177,8 +177,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { if (t->api != p_api || !t->exposed) { continue; } - hash = hash_djb2_one_64(t->name.hash(), hash); - hash = hash_djb2_one_64(t->inherits.hash(), hash); + hash = hash_murmur3_one_64(t->name.hash(), hash); + hash = hash_murmur3_one_64(t->inherits.hash(), hash); { //methods @@ -200,27 +200,27 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { for (const StringName &F : snames) { MethodBind *mb = t->method_map[F]; - hash = hash_djb2_one_64(mb->get_name().hash(), hash); - hash = hash_djb2_one_64(mb->get_argument_count(), hash); - hash = hash_djb2_one_64(mb->get_argument_type(-1), hash); //return + hash = hash_murmur3_one_64(mb->get_name().hash(), hash); + hash = hash_murmur3_one_64(mb->get_argument_count(), hash); + hash = hash_murmur3_one_64(mb->get_argument_type(-1), hash); //return for (int i = 0; i < mb->get_argument_count(); i++) { const PropertyInfo info = mb->get_argument_info(i); - hash = hash_djb2_one_64(info.type, hash); - hash = hash_djb2_one_64(info.name.hash(), hash); - hash = hash_djb2_one_64(info.hint, hash); - hash = hash_djb2_one_64(info.hint_string.hash(), hash); + hash = hash_murmur3_one_64(info.type, hash); + hash = hash_murmur3_one_64(info.name.hash(), hash); + hash = hash_murmur3_one_64(info.hint, hash); + hash = hash_murmur3_one_64(info.hint_string.hash(), hash); } - hash = hash_djb2_one_64(mb->get_default_argument_count(), hash); + hash = hash_murmur3_one_64(mb->get_default_argument_count(), hash); for (int i = 0; i < mb->get_default_argument_count(); i++) { //hash should not change, i hope for tis Variant da = mb->get_default_argument(i); - hash = hash_djb2_one_64(da.hash(), hash); + hash = hash_murmur3_one_64(da.hash(), hash); } - hash = hash_djb2_one_64(mb->get_hint_flags(), hash); + hash = hash_murmur3_one_64(mb->get_hint_flags(), hash); } } @@ -228,15 +228,15 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { List<StringName> snames; - for (const KeyValue<StringName, int> &F : t->constant_map) { + for (const KeyValue<StringName, int64_t> &F : t->constant_map) { snames.push_back(F.key); } snames.sort_custom<StringName::AlphCompare>(); for (const StringName &F : snames) { - hash = hash_djb2_one_64(F.hash(), hash); - hash = hash_djb2_one_64(t->constant_map[F], hash); + hash = hash_murmur3_one_64(F.hash(), hash); + hash = hash_murmur3_one_64(t->constant_map[F], hash); } } @@ -252,9 +252,9 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { for (const StringName &F : snames) { MethodInfo &mi = t->signal_map[F]; - hash = hash_djb2_one_64(F.hash(), hash); + hash = hash_murmur3_one_64(F.hash(), hash); for (int i = 0; i < mi.arguments.size(); i++) { - hash = hash_djb2_one_64(mi.arguments[i].type, hash); + hash = hash_murmur3_one_64(mi.arguments[i].type, hash); } } } @@ -273,23 +273,23 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { PropertySetGet *psg = t->property_setget.getptr(F); ERR_FAIL_COND_V(!psg, 0); - hash = hash_djb2_one_64(F.hash(), hash); - hash = hash_djb2_one_64(psg->setter.hash(), hash); - hash = hash_djb2_one_64(psg->getter.hash(), hash); + hash = hash_murmur3_one_64(F.hash(), hash); + hash = hash_murmur3_one_64(psg->setter.hash(), hash); + hash = hash_murmur3_one_64(psg->getter.hash(), hash); } } //property list for (const PropertyInfo &F : t->property_list) { - hash = hash_djb2_one_64(F.name.hash(), hash); - hash = hash_djb2_one_64(F.type, hash); - hash = hash_djb2_one_64(F.hint, hash); - hash = hash_djb2_one_64(F.hint_string.hash(), hash); - hash = hash_djb2_one_64(F.usage, hash); + hash = hash_murmur3_one_64(F.name.hash(), hash); + hash = hash_murmur3_one_64(F.type, hash); + hash = hash_murmur3_one_64(F.hint, hash); + hash = hash_murmur3_one_64(F.hint_string.hash(), hash); + hash = hash_murmur3_one_64(F.usage, hash); } } - return hash; + return hash_fmix32(hash); #else return 0; #endif @@ -536,7 +536,7 @@ MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_n return nullptr; } -void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant) { +void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield) { OBJTYPE_WLOCK; ClassInfo *type = classes.getptr(p_class); @@ -555,13 +555,15 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName enum_name = enum_name.get_slicec('.', 1); } - List<StringName> *constants_list = type->enum_map.getptr(enum_name); + ClassInfo::EnumInfo *constants_list = type->enum_map.getptr(enum_name); if (constants_list) { - constants_list->push_back(p_name); + constants_list->constants.push_back(p_name); + constants_list->is_bitfield = p_is_bitfield; } else { - List<StringName> new_list; - new_list.push_back(p_name); + ClassInfo::EnumInfo new_list; + new_list.is_bitfield = p_is_bitfield; + new_list.constants.push_back(p_name); type->enum_map[enum_name] = new_list; } } @@ -583,7 +585,7 @@ void ClassDB::get_integer_constant_list(const StringName &p_class, List<String> } #else - for (const KeyValue<StringName, int> &E : type->constant_map) { + for (const KeyValue<StringName, int64_t> &E : type->constant_map) { p_constants->push_back(E.key); } @@ -596,13 +598,13 @@ void ClassDB::get_integer_constant_list(const StringName &p_class, List<String> } } -int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success) { +int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success) { OBJTYPE_RLOCK; ClassInfo *type = classes.getptr(p_class); while (type) { - int *constant = type->constant_map.getptr(p_name); + int64_t *constant = type->constant_map.getptr(p_name); if (constant) { if (p_success) { *p_success = true; @@ -645,8 +647,8 @@ StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const S ClassInfo *type = classes.getptr(p_class); while (type) { - for (KeyValue<StringName, List<StringName>> &E : type->enum_map) { - List<StringName> &constants_list = E.value; + for (KeyValue<StringName, ClassInfo::EnumInfo> &E : type->enum_map) { + List<StringName> &constants_list = E.value.constants; const List<StringName>::Element *found = constants_list.find(p_name); if (found) { return E.key; @@ -669,7 +671,7 @@ void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums ClassInfo *type = classes.getptr(p_class); while (type) { - for (KeyValue<StringName, List<StringName>> &E : type->enum_map) { + for (KeyValue<StringName, ClassInfo::EnumInfo> &E : type->enum_map) { p_enums->push_back(E.key); } @@ -687,10 +689,10 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_ ClassInfo *type = classes.getptr(p_class); while (type) { - const List<StringName> *constants = type->enum_map.getptr(p_enum); + const ClassInfo::EnumInfo *constants = type->enum_map.getptr(p_enum); if (constants) { - for (const List<StringName>::Element *E = constants->front(); E; E = E->next()) { + for (const List<StringName>::Element *E = constants->constants.front(); E; E = E->next()) { p_constants->push_back(E->get()); } } @@ -748,6 +750,25 @@ bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool return false; } +bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { + OBJTYPE_RLOCK; + + ClassInfo *type = classes.getptr(p_class); + + while (type) { + if (type->enum_map.has(p_name) && type->enum_map[p_name].is_bitfield) { + return true; + } + if (p_no_inheritance) { + return false; + } + + type = type->inherits_ptr; + } + + return false; +} + void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) { OBJTYPE_WLOCK; @@ -1066,7 +1087,7 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia return true; } - const int *c = check->constant_map.getptr(p_property); //constants count + const int64_t *c = check->constant_map.getptr(p_property); //constants count if (c) { r_value = *c; return true; diff --git a/core/object/class_db.h b/core/object/class_db.h index 2448a86e33..1d26eb18f1 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -103,8 +103,13 @@ public: ObjectNativeExtension *native_extension = nullptr; HashMap<StringName, MethodBind *> method_map; - HashMap<StringName, int> constant_map; - HashMap<StringName, List<StringName>> enum_map; + HashMap<StringName, int64_t> constant_map; + struct EnumInfo { + List<StringName> constants; + bool is_bitfield = false; + }; + + HashMap<StringName, EnumInfo> enum_map; HashMap<StringName, MethodInfo> signal_map; List<PropertyInfo> property_list; HashMap<StringName, PropertyInfo> property_map; @@ -325,15 +330,17 @@ public: static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true, const Vector<String> &p_arg_names = Vector<String>(), bool p_object_core = false); static void get_virtual_methods(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false); - static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant); + static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield = false); static void get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance = false); - static int get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success = nullptr); + static int64_t get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success = nullptr); static bool has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static StringName get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); + static StringName get_integer_constant_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static void get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance = false); static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false); static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); + static bool is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static void set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values); static Vector<Error> get_method_error_return_values(const StringName &p_class, const StringName &p_method); @@ -370,6 +377,9 @@ public: #define BIND_ENUM_CONSTANT(m_constant) \ ::ClassDB::bind_integer_constant(get_class_static(), __constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant); +#define BIND_BITFIELD_FLAG(m_constant) \ + ::ClassDB::bind_integer_constant(get_class_static(), __constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true); + _FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr) { } @@ -401,6 +411,9 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) { #define BIND_ENUM_CONSTANT(m_constant) \ ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant); +#define BIND_BITFIELD_FLAG(m_constant) \ + ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant, true); + #define BIND_METHOD_ERR_RETURN_DOC(m_method, ...) #endif diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp index a208c1a2b2..a4474ea53b 100644 --- a/core/object/method_bind.cpp +++ b/core/object/method_bind.cpp @@ -35,32 +35,27 @@ #include "method_bind.h" uint32_t MethodBind::get_hash() const { - uint32_t hash = hash_djb2_one_32(has_return() ? 1 : 0); - hash = hash_djb2_one_32(get_argument_count(), hash); - -#ifndef _MSC_VER -#warning This needs proper class name and argument type for hashing -#endif -#if 0 + uint32_t hash = hash_murmur3_one_32(has_return() ? 1 : 0); + hash = hash_murmur3_one_32(get_argument_count(), hash); for (int i = (has_return() ? -1 : 0); i < get_argument_count(); i++) { PropertyInfo pi = i == -1 ? get_return_info() : get_argument_info(i); - hash = hash_djb2_one_32(get_argument_type(i), hash); + hash = hash_murmur3_one_32(get_argument_type(i), hash); if (pi.class_name != StringName()) { - hash = hash_djb2_one_32(pi.class_name.operator String().hash(), hash); + hash = hash_murmur3_one_32(pi.class_name.operator String().hash(), hash); } } -#endif - hash = hash_djb2_one_32(get_default_argument_count(), hash); + + hash = hash_murmur3_one_32(get_default_argument_count(), hash); for (int i = 0; i < get_default_argument_count(); i++) { Variant v = get_default_argument(i); - hash = hash_djb2_one_32(v.hash(), hash); + hash = hash_murmur3_one_32(v.hash(), hash); } - hash = hash_djb2_one_32(is_const(), hash); - hash = hash_djb2_one_32(is_vararg(), hash); + hash = hash_murmur3_one_32(is_const(), hash); + hash = hash_murmur3_one_32(is_vararg(), hash); - return hash; + return hash_fmix32(hash); } PropertyInfo MethodBind::get_argument_info(int p_argument) const { diff --git a/core/object/method_bind.h b/core/object/method_bind.h index 2870195911..d60550c899 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -33,20 +33,6 @@ #include "core/variant/binder_common.h" -enum MethodFlags { - METHOD_FLAG_NORMAL = 1, - METHOD_FLAG_EDITOR = 2, - METHOD_FLAG_NOSCRIPT = 4, - METHOD_FLAG_CONST = 8, - METHOD_FLAG_REVERSE = 16, // used for events - METHOD_FLAG_VIRTUAL = 32, - METHOD_FLAG_FROM_SCRIPT = 64, - METHOD_FLAG_VARARG = 128, - METHOD_FLAG_STATIC = 256, - METHOD_FLAG_OBJECT_CORE = 512, - METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL, -}; - VARIANT_ENUM_CAST(MethodFlags) // some helpers diff --git a/core/object/object.cpp b/core/object/object.cpp index 0912ea55f0..5f2287c9d3 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -161,161 +161,6 @@ MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) { return mi; } -MethodInfo::MethodInfo() : - flags(METHOD_FLAG_NORMAL) {} - -MethodInfo::MethodInfo(const String &p_name) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); -} - -MethodInfo::MethodInfo(Variant::Type ret) : - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); -} - Object::Connection::operator Variant() const { Dictionary d; d["signal"] = signal; @@ -648,7 +493,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons uint32_t pcount; const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_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)); + p_list->push_back(PropertyInfo(pinfo[i])); } if (_extension->free_property_list) { _extension->free_property_list(_extension_instance, pinfo); @@ -824,6 +669,51 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_ case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: + case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST: + return ret; + case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: { + } + } + } + + //extension does not need this, because all methods are registered in MethodBind + + MethodBind *method = ClassDB::get_method(get_class_name(), p_method); + + if (method) { + ret = method->call(this, p_args, p_argcount, r_error); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; + } + + return ret; +} + +Variant Object::call_const(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) { + // Free is not const, so fail. + r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST; + return Variant(); + } + + Variant ret; + OBJ_DEBUG_LOCK + + if (script_instance) { + ret = script_instance->call_const(p_method, p_args, p_argcount, r_error); + //force jumptable + switch (r_error.error) { + case Callable::CallError::CALL_OK: + return ret; + case Callable::CallError::CALL_ERROR_INVALID_METHOD: + break; + case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST: + break; + case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: + case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: + case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: return ret; case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: { } @@ -835,6 +725,10 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_ MethodBind *method = ClassDB::get_method(get_class_name(), p_method); if (method) { + if (!method->is_const()) { + r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST; + return ret; + } ret = method->call(this, p_args, p_argcount, r_error); } else { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -1196,7 +1090,7 @@ Array Object::_get_signal_list() const { return ret; } -Array Object::_get_signal_connection_list(const String &p_signal) const { +Array Object::_get_signal_connection_list(const StringName &p_signal) const { List<Connection> conns; get_all_signal_connections(&conns); @@ -1422,11 +1316,11 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, } } -void Object::_set_bind(const String &p_set, const Variant &p_value) { +void Object::_set_bind(const StringName &p_set, const Variant &p_value) { set(p_set, p_value); } -Variant Object::_get_bind(const String &p_name) const { +Variant Object::_get_bind(const StringName &p_name) const { return get(p_name); } diff --git a/core/object/object.h b/core/object/object.h index 988d261d77..705d6451dc 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -47,12 +47,11 @@ 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. + PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range. PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") - PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) - PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) + PROPERTY_HINT_LINK, PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) PROPERTY_HINT_LAYERS_2D_RENDER, PROPERTY_HINT_LAYERS_2D_PHYSICS, @@ -66,6 +65,7 @@ enum PropertyHint { PROPERTY_HINT_GLOBAL_DIR, ///< a directory path must be passed PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines + PROPERTY_HINT_EXPRESSION, ///< used for string properties that can contain multiple lines PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color PROPERTY_HINT_IMAGE_COMPRESS_LOSSY, @@ -84,51 +84,52 @@ enum PropertyHint { PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send PROPERTY_HINT_NODE_PATH_VALID_TYPES, PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog + PROPERTY_HINT_GLOBAL_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog PROPERTY_HINT_INT_IS_OBJECTID, PROPERTY_HINT_ARRAY_TYPE, PROPERTY_HINT_INT_IS_POINTER, PROPERTY_HINT_LOCALE_ID, PROPERTY_HINT_LOCALIZABLE_STRING, + PROPERTY_HINT_NODE_TYPE, ///< a node object type PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; enum PropertyUsageFlags { PROPERTY_USAGE_NONE = 0, - PROPERTY_USAGE_STORAGE = 1, - PROPERTY_USAGE_EDITOR = 2, - PROPERTY_USAGE_NETWORK = 4, - PROPERTY_USAGE_EDITOR_HELPER = 8, - PROPERTY_USAGE_CHECKABLE = 16, //used for editing global variables - PROPERTY_USAGE_CHECKED = 32, //used for editing global variables - PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings - PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor - PROPERTY_USAGE_CATEGORY = 256, - PROPERTY_USAGE_SUBGROUP = 512, - PROPERTY_USAGE_NO_INSTANCE_STATE = 2048, - PROPERTY_USAGE_RESTART_IF_CHANGED = 4096, - PROPERTY_USAGE_SCRIPT_VARIABLE = 8192, - PROPERTY_USAGE_STORE_IF_NULL = 16384, - PROPERTY_USAGE_ANIMATE_AS_TRIGGER = 32768, - PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 65536, - PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 17, - PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 18, - PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 19, - PROPERTY_USAGE_INTERNAL = 1 << 20, - PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE = 1 << 21, // If the object is duplicated also this property will be duplicated - PROPERTY_USAGE_HIGH_END_GFX = 1 << 22, - PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 23, - PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24, - PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player - PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading - PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor. - PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 28, //for project or editor settings, show when basic settings are selected - PROPERTY_USAGE_READ_ONLY = 1 << 29, // Mark a property as read-only in the inspector. - PROPERTY_USAGE_ARRAY = 1 << 30, // Used in the inspector to group properties as elements of an array. - - PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, - PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, - PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK, + PROPERTY_USAGE_STORAGE = 1 << 1, + PROPERTY_USAGE_EDITOR = 1 << 2, + PROPERTY_USAGE_CHECKABLE = 1 << 3, // Used for editing global variables. + PROPERTY_USAGE_CHECKED = 1 << 4, // Used for editing global variables. + PROPERTY_USAGE_INTERNATIONALIZED = 1 << 5, // Hint for internationalized strings. + PROPERTY_USAGE_GROUP = 1 << 6, // Used for grouping props in the editor. + PROPERTY_USAGE_CATEGORY = 1 << 7, + PROPERTY_USAGE_SUBGROUP = 1 << 8, + PROPERTY_USAGE_CLASS_IS_BITFIELD = 1 << 9, + PROPERTY_USAGE_NO_INSTANCE_STATE = 1 << 10, + PROPERTY_USAGE_RESTART_IF_CHANGED = 1 << 11, + PROPERTY_USAGE_SCRIPT_VARIABLE = 1 << 12, + PROPERTY_USAGE_STORE_IF_NULL = 1 << 13, + PROPERTY_USAGE_ANIMATE_AS_TRIGGER = 1 << 14, + PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 1 << 15, + PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 16, + PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 17, + PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 18, + PROPERTY_USAGE_INTERNAL = 1 << 19, + PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE = 1 << 20, // If the object is duplicated also this property will be duplicated. + PROPERTY_USAGE_HIGH_END_GFX = 1 << 21, + PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 22, + PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 23, + PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 24, // Used in inspector to increment property when keyed in animation player. + PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 25, // when loading, the resource for this property can be set at the end of loading. + PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 26, // For Object properties, instantiate them when creating in editor. + PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 27, //for project or editor settings, show when basic settings are selected. + PROPERTY_USAGE_READ_ONLY = 1 << 28, // Mark a property as read-only in the inspector. + PROPERTY_USAGE_ARRAY = 1 << 29, // Used in the inspector to group properties as elements of an array. + + PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR, + PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNATIONALIZED, + PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE, }; #define ADD_SIGNAL(m_signal) ::ClassDB::add_signal(get_class_static(), m_signal) @@ -186,6 +187,14 @@ struct PropertyInfo { type(Variant::OBJECT), class_name(p_class_name) {} + explicit PropertyInfo(const GDNativePropertyInfo &pinfo) : + type((Variant::Type)pinfo.type), + name(pinfo.name), + class_name(pinfo.class_name), // can be null + hint((PropertyHint)pinfo.hint), + hint_string(pinfo.hint_string), // can be null + usage(pinfo.usage) {} + bool operator==(const PropertyInfo &p_info) const { return ((type == p_info.type) && (name == p_info.name) && @@ -202,10 +211,21 @@ struct PropertyInfo { Array convert_property_list(const List<PropertyInfo> *p_list); +enum MethodFlags { + METHOD_FLAG_NORMAL = 1, + METHOD_FLAG_EDITOR = 2, + METHOD_FLAG_CONST = 4, + METHOD_FLAG_VIRTUAL = 8, + METHOD_FLAG_VARARG = 16, + METHOD_FLAG_STATIC = 32, + METHOD_FLAG_OBJECT_CORE = 64, + METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL, +}; + struct MethodInfo { String name; PropertyInfo return_val; - uint32_t flags; // NOLINT - prevent clang-tidy to assign method_bind.h constant here, it should stay in .cpp. + uint32_t flags = METHOD_FLAGS_DEFAULT; int id = 0; List<PropertyInfo> arguments; Vector<Variant> default_arguments; @@ -217,26 +237,50 @@ struct MethodInfo { static MethodInfo from_dict(const Dictionary &p_dict); - MethodInfo(); - MethodInfo(const String &p_name); - MethodInfo(const String &p_name, const PropertyInfo &p_param1); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5); - MethodInfo(Variant::Type ret); - MethodInfo(Variant::Type ret, const String &p_name); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5); - MethodInfo(const PropertyInfo &p_ret, const String &p_name); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5); + MethodInfo() {} + + void _push_params(const PropertyInfo &p_param) { + arguments.push_back(p_param); + } + + template <typename... VarArgs> + void _push_params(const PropertyInfo &p_param, VarArgs... p_params) { + arguments.push_back(p_param); + _push_params(p_params...); + } + + MethodInfo(const String &p_name) { name = p_name; } + + template <typename... VarArgs> + MethodInfo(const String &p_name, VarArgs... p_params) { + name = p_name; + _push_params(p_params...); + } + + MethodInfo(Variant::Type ret) { return_val.type = ret; } + MethodInfo(Variant::Type ret, const String &p_name) { + return_val.type = ret; + name = p_name; + } + + template <typename... VarArgs> + MethodInfo(Variant::Type ret, const String &p_name, VarArgs... p_params) { + name = p_name; + return_val.type = ret; + _push_params(p_params...); + } + + MethodInfo(const PropertyInfo &p_ret, const String &p_name) { + return_val = p_ret; + name = p_name; + } + + template <typename... VarArgs> + MethodInfo(const PropertyInfo &p_ret, const String &p_name, VarArgs... p_params) { + return_val = p_ret; + name = p_name; + _push_params(p_params...); + } }; // API used to extend in GDNative and other C compatible compiled languages. @@ -523,10 +567,10 @@ private: bool _has_user_signal(const StringName &p_name) const; Error _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Array _get_signal_list() const; - Array _get_signal_connection_list(const String &p_signal) const; + Array _get_signal_connection_list(const StringName &p_signal) const; Array _get_incoming_connections() const; - void _set_bind(const String &p_set, const Variant &p_value); - Variant _get_bind(const String &p_name) const; + void _set_bind(const StringName &p_set, const Variant &p_value); + Variant _get_bind(const StringName &p_name) const; void _set_indexed_bind(const NodePath &p_name, const Variant &p_value); Variant _get_indexed_bind(const NodePath &p_name) const; @@ -718,6 +762,7 @@ public: void get_method_list(List<MethodInfo> *p_list) const; Variant callv(const StringName &p_method, const Array &p_args); virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); + virtual Variant call_const(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) { diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 66c9a80193..4623d0e525 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -295,6 +295,11 @@ void ScriptServer::save_global_classes() { } //////////////////// + +Variant ScriptInstance::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + return callp(p_method, p_args, p_argcount, r_error); +} + void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state) { List<PropertyInfo> pinfo; get_property_list(&pinfo); diff --git a/core/object/script_language.h b/core/object/script_language.h index 0a8e79a24e..686ab5b8d3 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -190,6 +190,7 @@ public: return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr); } + virtual Variant call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); // implement if language supports const functions virtual void notification(int p_notification) = 0; virtual String to_string(bool *r_valid) { if (r_valid) { @@ -349,6 +350,7 @@ public: LOOKUP_RESULT_CLASS_SIGNAL, LOOKUP_RESULT_CLASS_ENUM, LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE, + LOOKUP_RESULT_CLASS_ANNOTATION, LOOKUP_RESULT_MAX }; @@ -401,6 +403,7 @@ public: virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; virtual void get_public_functions(List<MethodInfo> *p_functions) const = 0; virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const = 0; + virtual void get_public_annotations(List<MethodInfo> *p_annotations) const = 0; struct ProfilingInfo { StringName signature; diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp index 5af79bbea3..ab8dd6d1ee 100644 --- a/core/object/script_language_extension.cpp +++ b/core/object/script_language_extension.cpp @@ -134,6 +134,7 @@ void ScriptLanguageExtension::_bind_methods() { GDVIRTUAL_BIND(_get_recognized_extensions); GDVIRTUAL_BIND(_get_public_functions); GDVIRTUAL_BIND(_get_public_constants); + GDVIRTUAL_BIND(_get_public_annotations); GDVIRTUAL_BIND(_profiling_start); GDVIRTUAL_BIND(_profiling_stop); @@ -160,6 +161,7 @@ void ScriptLanguageExtension::_bind_methods() { BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_SIGNAL); BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_ENUM); BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE); + BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_ANNOTATION); BIND_ENUM_CONSTANT(LOOKUP_RESULT_MAX); BIND_ENUM_CONSTANT(LOCATION_LOCAL); diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index 406a431a11..2c53139ec2 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -580,6 +580,15 @@ public: p_constants->push_back(Pair<String, Variant>(d["name"], d["value"])); } } + GDVIRTUAL0RC(TypedArray<Dictionary>, _get_public_annotations) + virtual void get_public_annotations(List<MethodInfo> *p_annotations) const override { + TypedArray<Dictionary> ret; + GDVIRTUAL_REQUIRED_CALL(_get_public_annotations, ret); + for (int i = 0; i < ret.size(); i++) { + MethodInfo mi = MethodInfo::from_dict(ret[i]); + p_annotations->push_back(mi); + } + } EXBIND0(profiling_start) EXBIND0(profiling_stop) @@ -671,7 +680,7 @@ public: 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)); + p_list->push_back(PropertyInfo(pinfo[i])); } if (native_info->free_property_list_func) { native_info->free_property_list_func(instance, pinfo); @@ -716,9 +725,9 @@ public: 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); + m.return_val = PropertyInfo(minfo[i].return_value); 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)); + m.arguments.push_back(PropertyInfo(minfo[i].arguments[j])); } const Variant *def_values = (const Variant *)minfo[i].default_arguments; for (uint32_t j = 0; j < minfo[i].default_argument_count; j++) { diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 24907d34c8..3e690991d9 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -86,6 +86,25 @@ static const _KeyCodeText _keycodes[] = { {Key::F14 ,"F14"}, {Key::F15 ,"F15"}, {Key::F16 ,"F16"}, + {Key::F17 ,"F17"}, + {Key::F18 ,"F18"}, + {Key::F19 ,"F19"}, + {Key::F20 ,"F20"}, + {Key::F21 ,"F21"}, + {Key::F22 ,"F22"}, + {Key::F23 ,"F23"}, + {Key::F24 ,"F24"}, + {Key::F25 ,"F25"}, + {Key::F26 ,"F26"}, + {Key::F27 ,"F27"}, + {Key::F28 ,"F28"}, + {Key::F29 ,"F29"}, + {Key::F30 ,"F30"}, + {Key::F31 ,"F31"}, + {Key::F32 ,"F32"}, + {Key::F33 ,"F33"}, + {Key::F34 ,"F34"}, + {Key::F35 ,"F35"}, {Key::KP_MULTIPLY ,"Kp Multiply"}, {Key::KP_DIVIDE ,"Kp Divide"}, {Key::KP_SUBTRACT ,"Kp Subtract"}, @@ -333,6 +352,25 @@ bool keycode_has_unicode(Key p_keycode) { case Key::F14: case Key::F15: case Key::F16: + case Key::F17: + case Key::F18: + case Key::F19: + case Key::F20: + case Key::F21: + case Key::F22: + case Key::F23: + case Key::F24: + case Key::F25: + case Key::F26: + case Key::F27: + case Key::F28: + case Key::F29: + case Key::F30: + case Key::F31: + case Key::F32: + case Key::F33: + case Key::F34: + case Key::F35: case Key::SUPER_L: case Key::SUPER_R: case Key::MENU: diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 3176a8a210..517a53e505 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -85,6 +85,25 @@ enum class Key { F14 = SPECIAL | 0x29, F15 = SPECIAL | 0x2A, F16 = SPECIAL | 0x2B, + F17 = SPECIAL | 0x2C, + F18 = SPECIAL | 0x2D, + F19 = SPECIAL | 0x2E, + F20 = SPECIAL | 0x2F, + F21 = SPECIAL | 0x30, + F22 = SPECIAL | 0x31, + F23 = SPECIAL | 0x32, + F24 = SPECIAL | 0x33, + F25 = SPECIAL | 0x34, + F26 = SPECIAL | 0x35, + F27 = SPECIAL | 0x36, + F28 = SPECIAL | 0x37, + F29 = SPECIAL | 0x38, + F30 = SPECIAL | 0x39, + F31 = SPECIAL | 0x3A, + F32 = SPECIAL | 0x3B, + F33 = SPECIAL | 0x3C, + F34 = SPECIAL | 0x3D, + F35 = SPECIAL | 0x3E, KP_MULTIPLY = SPECIAL | 0x81, KP_DIVIDE = SPECIAL | 0x82, KP_SUBTRACT = SPECIAL | 0x83, @@ -100,54 +119,54 @@ enum class Key { KP_7 = SPECIAL | 0x8D, KP_8 = SPECIAL | 0x8E, KP_9 = SPECIAL | 0x8F, - SUPER_L = SPECIAL | 0x2C, - SUPER_R = SPECIAL | 0x2D, - MENU = SPECIAL | 0x2E, - HYPER_L = SPECIAL | 0x2F, - HYPER_R = SPECIAL | 0x30, - HELP = SPECIAL | 0x31, - DIRECTION_L = SPECIAL | 0x32, - DIRECTION_R = SPECIAL | 0x33, - BACK = SPECIAL | 0x40, - FORWARD = SPECIAL | 0x41, - STOP = SPECIAL | 0x42, - REFRESH = SPECIAL | 0x43, - VOLUMEDOWN = SPECIAL | 0x44, - VOLUMEMUTE = SPECIAL | 0x45, - VOLUMEUP = SPECIAL | 0x46, - BASSBOOST = SPECIAL | 0x47, - BASSUP = SPECIAL | 0x48, - BASSDOWN = SPECIAL | 0x49, - TREBLEUP = SPECIAL | 0x4A, - TREBLEDOWN = SPECIAL | 0x4B, - MEDIAPLAY = SPECIAL | 0x4C, - MEDIASTOP = SPECIAL | 0x4D, - MEDIAPREVIOUS = SPECIAL | 0x4E, - MEDIANEXT = SPECIAL | 0x4F, - MEDIARECORD = SPECIAL | 0x50, - HOMEPAGE = SPECIAL | 0x51, - FAVORITES = SPECIAL | 0x52, - SEARCH = SPECIAL | 0x53, - STANDBY = SPECIAL | 0x54, - OPENURL = SPECIAL | 0x55, - LAUNCHMAIL = SPECIAL | 0x56, - LAUNCHMEDIA = SPECIAL | 0x57, - LAUNCH0 = SPECIAL | 0x58, - LAUNCH1 = SPECIAL | 0x59, - LAUNCH2 = SPECIAL | 0x5A, - LAUNCH3 = SPECIAL | 0x5B, - LAUNCH4 = SPECIAL | 0x5C, - LAUNCH5 = SPECIAL | 0x5D, - LAUNCH6 = SPECIAL | 0x5E, - LAUNCH7 = SPECIAL | 0x5F, - LAUNCH8 = SPECIAL | 0x60, - LAUNCH9 = SPECIAL | 0x61, - LAUNCHA = SPECIAL | 0x62, - LAUNCHB = SPECIAL | 0x63, - LAUNCHC = SPECIAL | 0x64, - LAUNCHD = SPECIAL | 0x65, - LAUNCHE = SPECIAL | 0x66, - LAUNCHF = SPECIAL | 0x67, + SUPER_L = SPECIAL | 0x40, + SUPER_R = SPECIAL | 0x41, + MENU = SPECIAL | 0x42, + HYPER_L = SPECIAL | 0x43, + HYPER_R = SPECIAL | 0x44, + HELP = SPECIAL | 0x45, + DIRECTION_L = SPECIAL | 0x46, + DIRECTION_R = SPECIAL | 0x47, + BACK = SPECIAL | 0x48, + FORWARD = SPECIAL | 0x49, + STOP = SPECIAL | 0x4A, + REFRESH = SPECIAL | 0x4B, + VOLUMEDOWN = SPECIAL | 0x4C, + VOLUMEMUTE = SPECIAL | 0x4D, + VOLUMEUP = SPECIAL | 0x4E, + BASSBOOST = SPECIAL | 0x4F, + BASSUP = SPECIAL | 0x50, + BASSDOWN = SPECIAL | 0x51, + TREBLEUP = SPECIAL | 0x52, + TREBLEDOWN = SPECIAL | 0x53, + MEDIAPLAY = SPECIAL | 0x54, + MEDIASTOP = SPECIAL | 0x55, + MEDIAPREVIOUS = SPECIAL | 0x56, + MEDIANEXT = SPECIAL | 0x57, + MEDIARECORD = SPECIAL | 0x58, + HOMEPAGE = SPECIAL | 0x59, + FAVORITES = SPECIAL | 0x5A, + SEARCH = SPECIAL | 0x5B, + STANDBY = SPECIAL | 0x5C, + OPENURL = SPECIAL | 0x5D, + LAUNCHMAIL = SPECIAL | 0x5E, + LAUNCHMEDIA = SPECIAL | 0x5F, + LAUNCH0 = SPECIAL | 0x60, + LAUNCH1 = SPECIAL | 0x61, + LAUNCH2 = SPECIAL | 0x62, + LAUNCH3 = SPECIAL | 0x63, + LAUNCH4 = SPECIAL | 0x64, + LAUNCH5 = SPECIAL | 0x65, + LAUNCH6 = SPECIAL | 0x66, + LAUNCH7 = SPECIAL | 0x67, + LAUNCH8 = SPECIAL | 0x68, + LAUNCH9 = SPECIAL | 0x69, + LAUNCHA = SPECIAL | 0x6A, + LAUNCHB = SPECIAL | 0x6B, + LAUNCHC = SPECIAL | 0x6C, + LAUNCHD = SPECIAL | 0x6D, + LAUNCHE = SPECIAL | 0x6E, + LAUNCHF = SPECIAL | 0x6F, UNKNOWN = SPECIAL | 0xFFFFFF, diff --git a/core/os/os.cpp b/core/os/os.cpp index 4f7095b0fc..b9daf6fa53 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -100,6 +100,21 @@ void OS::print(const char *p_format, ...) { va_end(argp); } +void OS::print_rich(const char *p_format, ...) { + if (!_stdout_enabled) { + return; + } + + va_list argp; + va_start(argp, p_format); + + if (_logger) { + _logger->logv(p_format, argp, false); + } + + va_end(argp); +} + void OS::printerr(const char *p_format, ...) { if (!_stderr_enabled) { return; @@ -388,6 +403,10 @@ bool OS::has_feature(const String &p_feature) { return true; } + if (p_feature == "movie") { + return _writing_movie; + } + #ifdef DEBUG_ENABLED if (p_feature == "debug") { return true; @@ -413,19 +432,29 @@ bool OS::has_feature(const String &p_feature) { if (sizeof(void *) == 4 && p_feature == "32") { return true; } -#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64) +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) if (p_feature == "x86_64") { return true; } -#elif (defined(__i386) || defined(__i386__)) +#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) + if (p_feature == "x86_32") { + return true; + } +#endif if (p_feature == "x86") { return true; } -#elif defined(__aarch64__) +#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64) +#if defined(__aarch64__) || defined(_M_ARM64) if (p_feature == "arm64") { return true; } -#elif defined(__arm__) +#elif defined(__arm__) || defined(_M_ARM) + if (p_feature == "arm32") { + return true; + } +#endif #if defined(__ARM_ARCH_7A__) if (p_feature == "armv7a" || p_feature == "armv7") { return true; @@ -457,6 +486,19 @@ bool OS::has_feature(const String &p_feature) { if (p_feature == "ppc") { return true; } +#elif defined(__wasm__) +#if defined(__wasm64__) + if (p_feature == "wasm64") { + return true; + } +#elif defined(__wasm32__) + if (p_feature == "wasm32") { + return true; + } +#endif + if (p_feature == "wasm") { + return true; + } #endif if (_check_internal_feature_support(p_feature)) { diff --git a/core/os/os.h b/core/os/os.h index 157b8ab992..0428f6df2a 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -58,6 +58,7 @@ class OS { bool _allow_layered = false; bool _stdout_enabled = true; bool _stderr_enabled = true; + bool _writing_movie = false; CompositeLogger *_logger = nullptr; @@ -119,6 +120,7 @@ public: void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR); void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; + void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; virtual String get_stdin_string(bool p_block = true) = 0; @@ -158,6 +160,7 @@ public: virtual String get_name() const = 0; virtual List<String> get_cmdline_args() const { return _cmdline; } + virtual List<String> get_cmdline_platform_args() const { return List<String>(); } virtual String get_model_name() const; bool is_layered_allowed() const { return _allow_layered; } diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp index 238897c2b1..30fa434fad 100644 --- a/core/string/node_path.cpp +++ b/core/string/node_path.cpp @@ -199,6 +199,21 @@ Vector<StringName> NodePath::get_subnames() const { return Vector<StringName>(); } +StringName NodePath::get_concatenated_names() const { + ERR_FAIL_COND_V(!data, StringName()); + + if (!data->concatenated_path) { + int pc = data->path.size(); + String concatenated; + const StringName *sn = data->path.ptr(); + for (int i = 0; i < pc; i++) { + concatenated += i == 0 ? sn[i].operator String() : "/" + sn[i]; + } + data->concatenated_path = concatenated; + } + return data->concatenated_path; +} + StringName NodePath::get_concatenated_subnames() const { ERR_FAIL_COND_V(!data, StringName()); diff --git a/core/string/node_path.h b/core/string/node_path.h index 53976bd524..2bce33e21e 100644 --- a/core/string/node_path.h +++ b/core/string/node_path.h @@ -39,6 +39,7 @@ class NodePath { SafeRefCount refcount; Vector<StringName> path; Vector<StringName> subpath; + StringName concatenated_path; StringName concatenated_subpath; bool absolute; bool has_slashes; @@ -59,6 +60,7 @@ public: StringName get_subname(int p_idx) const; Vector<StringName> get_names() const; Vector<StringName> get_subnames() const; + StringName get_concatenated_names() const; StringName get_concatenated_subnames() const; NodePath rel_path_to(const NodePath &p_np) const; diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp index 919c9e08e3..f58486e0a5 100644 --- a/core/string/print_string.cpp +++ b/core/string/print_string.cpp @@ -79,7 +79,98 @@ void __print_line(String p_string) { _global_lock(); PrintHandlerList *l = print_handler_list; while (l) { - l->printfunc(l->userdata, p_string, false); + l->printfunc(l->userdata, p_string, false, false); + l = l->next; + } + + _global_unlock(); +} + +void __print_line_rich(String p_string) { + if (!_print_line_enabled) { + return; + } + + // Convert a subset of BBCode tags to ANSI escape codes for correct display in the terminal. + // Support of those ANSI escape codes varies across terminal emulators, + // especially for italic and strikethrough. + String p_string_ansi = p_string; + + p_string_ansi = p_string_ansi.replace("[b]", "\u001b[1m"); + p_string_ansi = p_string_ansi.replace("[/b]", "\u001b[22m"); + p_string_ansi = p_string_ansi.replace("[i]", "\u001b[3m"); + p_string_ansi = p_string_ansi.replace("[/i]", "\u001b[23m"); + p_string_ansi = p_string_ansi.replace("[u]", "\u001b[4m"); + p_string_ansi = p_string_ansi.replace("[/u]", "\u001b[24m"); + p_string_ansi = p_string_ansi.replace("[s]", "\u001b[9m"); + p_string_ansi = p_string_ansi.replace("[/s]", "\u001b[29m"); + + p_string_ansi = p_string_ansi.replace("[indent]", " "); + p_string_ansi = p_string_ansi.replace("[/indent]", ""); + p_string_ansi = p_string_ansi.replace("[code]", "\u001b[2m"); + p_string_ansi = p_string_ansi.replace("[/code]", "\u001b[22m"); + p_string_ansi = p_string_ansi.replace("[url]", ""); + p_string_ansi = p_string_ansi.replace("[/url]", ""); + p_string_ansi = p_string_ansi.replace("[center]", "\n\t\t\t"); + p_string_ansi = p_string_ansi.replace("[/center]", ""); + p_string_ansi = p_string_ansi.replace("[right]", "\n\t\t\t\t\t\t"); + p_string_ansi = p_string_ansi.replace("[/right]", ""); + + if (p_string_ansi.contains("[color")) { + p_string_ansi = p_string_ansi.replace("[color=black]", "\u001b[30m"); + p_string_ansi = p_string_ansi.replace("[color=red]", "\u001b[91m"); + p_string_ansi = p_string_ansi.replace("[color=green]", "\u001b[92m"); + p_string_ansi = p_string_ansi.replace("[color=lime]", "\u001b[92m"); + p_string_ansi = p_string_ansi.replace("[color=yellow]", "\u001b[93m"); + p_string_ansi = p_string_ansi.replace("[color=blue]", "\u001b[94m"); + p_string_ansi = p_string_ansi.replace("[color=magenta]", "\u001b[95m"); + p_string_ansi = p_string_ansi.replace("[color=pink]", "\u001b[38;5;218m"); + p_string_ansi = p_string_ansi.replace("[color=purple]", "\u001b[38;5;98m"); + p_string_ansi = p_string_ansi.replace("[color=cyan]", "\u001b[96m"); + p_string_ansi = p_string_ansi.replace("[color=white]", "\u001b[97m"); + p_string_ansi = p_string_ansi.replace("[color=orange]", "\u001b[38;5;208m"); + p_string_ansi = p_string_ansi.replace("[color=gray]", "\u001b[90m"); + p_string_ansi = p_string_ansi.replace("[/color]", "\u001b[39m"); + } + if (p_string_ansi.contains("[bgcolor")) { + p_string_ansi = p_string_ansi.replace("[bgcolor=black]", "\u001b[40m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=red]", "\u001b[101m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=green]", "\u001b[102m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=lime]", "\u001b[102m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=yellow]", "\u001b[103m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=blue]", "\u001b[104m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=magenta]", "\u001b[105m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=pink]", "\u001b[48;5;218m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=purple]", "\u001b[48;5;98m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=cyan]", "\u001b[106m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=white]", "\u001b[107m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=orange]", "\u001b[48;5;208m"); + p_string_ansi = p_string_ansi.replace("[bgcolor=gray]", "\u001b[100m"); + p_string_ansi = p_string_ansi.replace("[/bgcolor]", "\u001b[49m"); + } + if (p_string_ansi.contains("[fgcolor")) { + p_string_ansi = p_string_ansi.replace("[fgcolor=black]", "\u001b[30;40m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=red]", "\u001b[91;101m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=green]", "\u001b[92;102m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=lime]", "\u001b[92;102m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=yellow]", "\u001b[93;103m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=blue]", "\u001b[94;104m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=magenta]", "\u001b[95;105m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=pink]", "\u001b[38;5;218;48;5;218m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=purple]", "\u001b[38;5;98;48;5;98m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=cyan]", "\u001b[96;106m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=white]", "\u001b[97;107m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=orange]", "\u001b[38;5;208;48;5;208m"); + p_string_ansi = p_string_ansi.replace("[fgcolor=gray]", "\u001b[90;100m"); + p_string_ansi = p_string_ansi.replace("[/fgcolor]", "\u001b[39;49m"); + } + + OS::get_singleton()->print_rich("%s\n", p_string_ansi.utf8().get_data()); + + _global_lock(); + PrintHandlerList *l = print_handler_list; + while (l) { + l->printfunc(l->userdata, p_string, false, true); l = l->next; } @@ -96,7 +187,7 @@ void print_error(String p_string) { _global_lock(); PrintHandlerList *l = print_handler_list; while (l) { - l->printfunc(l->userdata, p_string, true); + l->printfunc(l->userdata, p_string, true, false); l = l->next; } diff --git a/core/string/print_string.h b/core/string/print_string.h index f7d0f25030..823e2c29e8 100644 --- a/core/string/print_string.h +++ b/core/string/print_string.h @@ -35,7 +35,7 @@ extern void (*_print_func)(String); -typedef void (*PrintHandlerFunc)(void *, const String &p_string, bool p_error); +typedef void (*PrintHandlerFunc)(void *, const String &p_string, bool p_error, bool p_rich); struct PrintHandlerList { PrintHandlerFunc printfunc = nullptr; @@ -59,6 +59,7 @@ 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_line_rich(String p_string); extern void print_error(String p_string); extern void print_verbose(String p_string); @@ -66,9 +67,18 @@ inline void print_line(Variant v) { __print_line(stringify_variants(v)); } +inline void print_line_rich(Variant v) { + __print_line_rich(stringify_variants(v)); +} + template <typename... Args> void print_line(Variant p_var, Args... p_args) { __print_line(stringify_variants(p_var, p_args...)); } +template <typename... Args> +void print_line_rich(Variant p_var, Args... p_args) { + __print_line_rich(stringify_variants(p_var, p_args...)); +} + #endif // PRINT_STRING_H diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 44df349613..beefe54faf 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -323,7 +323,13 @@ void String::copy_from(const char *p_cstr) { char32_t *dst = this->ptrw(); for (size_t i = 0; i <= len; i++) { - dst[i] = p_cstr[i]; + uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]); + if (c == 0 && i < len) { + print_unicode_error("NUL character", true); + dst[i] = 0x20; + } else { + dst[i] = c; + } } } @@ -350,7 +356,13 @@ void String::copy_from(const char *p_cstr, const int p_clip_to) { char32_t *dst = this->ptrw(); for (int i = 0; i < len; i++) { - dst[i] = p_cstr[i]; + uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]); + if (c == 0) { + print_unicode_error("NUL character", true); + dst[i] = 0x20; + } else { + dst[i] = c; + } } dst[len] = 0; } @@ -376,14 +388,21 @@ void String::copy_from(const wchar_t *p_cstr, const int p_clip_to) { } void String::copy_from(const char32_t &p_char) { + if (p_char == 0) { + print_unicode_error("NUL character", true); + return; + } + if ((p_char & 0xfffff800) == 0xd800) { + print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char)); + } + if (p_char > 0x10ffff) { + print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_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) + "."); - dst[0] = 0xfffd; - } else { - dst[0] = p_char; - } + dst[0] = p_char; dst[1] = 0; } @@ -437,12 +456,18 @@ void String::copy_from_unchecked(const char32_t *p_char, const int p_length) { 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)) { - print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char[i], 16) + "."); - dst[i] = 0xfffd; - } else { - dst[i] = p_char[i]; + if (p_char[i] == 0) { + print_unicode_error("NUL character", true); + dst[i] = 0x20; + continue; } + if ((p_char[i] & 0xfffff800) == 0xd800) { + print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char[i])); + } + if (p_char[i] > 0x10ffff) { + print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char[i])); + } + dst[i] = p_char[i]; } } @@ -481,7 +506,7 @@ String operator+(const wchar_t *p_chr, const String &p_str) { // wchar_t is 16-bit String tmp = String::utf16((const char16_t *)p_chr); #else - // wchar_t is 32-bi + // wchar_t is 32-bit String tmp = (const char32_t *)p_chr; #endif tmp += p_str; @@ -527,7 +552,13 @@ String &String::operator+=(const char *p_str) { char32_t *dst = ptrw() + lhs_len; for (size_t i = 0; i <= rhs_len; i++) { - dst[i] = p_str[i]; + uint8_t c = p_str[i] >= 0 ? p_str[i] : uint8_t(256 + p_str[i]); + if (c == 0 && i < rhs_len) { + print_unicode_error("NUL character", true); + dst[i] = 0x20; + } else { + dst[i] = c; + } } return *this; @@ -550,15 +581,21 @@ String &String::operator+=(const char32_t *p_str) { } String &String::operator+=(char32_t p_char) { + if (p_char == 0) { + print_unicode_error("NUL character", true); + return *this; + } + if ((p_char & 0xfffff800) == 0xd800) { + print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char)); + } + if (p_char > 0x10ffff) { + print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char)); + } + 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) + "."); - dst[lhs_len] = 0xfffd; - } else { - dst[lhs_len] = p_char; - } + dst[lhs_len] = p_char; dst[lhs_len + 1] = 0; return *this; @@ -1583,6 +1620,14 @@ String String::hex_encode_buffer(const uint8_t *p_buffer, int p_len) { return ret; } +void String::print_unicode_error(const String &p_message, bool p_critical) const { + if (p_critical) { + print_error(vformat("Unicode parsing error, some characters were replaced with spaces: %s", p_message)); + } else { + print_error(vformat("Unicode parsing error: %s", p_message)); + } +} + CharString String::ascii(bool p_allow_extended) const { if (!length()) { return CharString(); @@ -1596,7 +1641,7 @@ CharString String::ascii(bool p_allow_extended) const { if ((c <= 0x7f) || (c <= 0xff && p_allow_extended)) { cs[i] = c; } else { - print_error("Unicode parsing error: Cannot represent " + num_int64(c, 16) + " as ASCII/Latin-1 character."); + print_unicode_error(vformat("Invalid unicode codepoint (%x), cannot represent as ASCII/Latin-1", (uint32_t)c)); cs[i] = 0x20; } } @@ -1611,11 +1656,9 @@ String String::utf8(const char *p_utf8, int p_len) { return ret; } -bool String::parse_utf8(const char *p_utf8, int p_len) { -#define UNICERROR(m_err) print_error("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-8?"); - +Error String::parse_utf8(const char *p_utf8, int p_len) { if (!p_utf8) { - return true; + return ERR_INVALID_DATA; } String aux; @@ -1635,14 +1678,17 @@ bool String::parse_utf8(const char *p_utf8, int p_len) { } } + bool decode_error = false; + bool decode_failed = false; { const char *ptrtmp = p_utf8; const char *ptrtmp_limit = &p_utf8[p_len]; int skip = 0; + uint8_t c_start = 0; while (ptrtmp != ptrtmp_limit && *ptrtmp) { - if (skip == 0) { - uint8_t c = *ptrtmp >= 0 ? *ptrtmp : uint8_t(256 + *ptrtmp); + uint8_t c = *ptrtmp >= 0 ? *ptrtmp : uint8_t(256 + *ptrtmp); + if (skip == 0) { /* Determine the number of characters in sequence */ if ((c & 0x80) == 0) { skip = 0; @@ -1652,20 +1698,34 @@ bool String::parse_utf8(const char *p_utf8, int p_len) { skip = 2; } else if ((c & 0xf8) == 0xf0) { skip = 3; + } else if ((c & 0xfc) == 0xf8) { + skip = 4; + } else if ((c & 0xfe) == 0xfc) { + skip = 5; } else { - UNICERROR("invalid skip at " + num_int64(cstr_size)); - return true; //invalid utf8 + skip = 0; + print_unicode_error(vformat("Invalid UTF-8 leading byte (%x)", c), true); + decode_failed = true; } + c_start = c; if (skip == 1 && (c & 0x1e) == 0) { - UNICERROR("overlong rejected at " + num_int64(cstr_size)); - return true; //reject overlong + print_unicode_error(vformat("Overlong encoding (%x ...)", c)); + decode_error = true; } - str_size++; - } else { - --skip; + if ((c_start == 0xe0 && skip == 2 && c < 0xa0) || (c_start == 0xf0 && skip == 3 && c < 0x90) || (c_start == 0xf8 && skip == 4 && c < 0x88) || (c_start == 0xfc && skip == 5 && c < 0x84)) { + print_unicode_error(vformat("Overlong encoding (%x %x ...)", c_start, c)); + decode_error = true; + } + if (c < 0x80 || c > 0xbf) { + print_unicode_error(vformat("Invalid UTF-8 continuation byte (%x ... %x ...)", c_start, c), true); + decode_failed = true; + skip = 0; + } else { + --skip; + } } cstr_size++; @@ -1673,80 +1733,91 @@ bool String::parse_utf8(const char *p_utf8, int p_len) { } if (skip) { - UNICERROR("no space left"); - return true; //not enough space + print_unicode_error(vformat("Missing %d UTF-8 continuation byte(s)", skip), true); + decode_failed = true; } } if (str_size == 0) { clear(); - return false; + return OK; // empty string } resize(str_size + 1); char32_t *dst = ptrw(); dst[str_size] = 0; + int skip = 0; + uint32_t unichar = 0; while (cstr_size) { - int len = 0; - - /* Determine the number of characters in sequence */ - if ((*p_utf8 & 0x80) == 0) { - len = 1; - } else if ((*p_utf8 & 0xe0) == 0xc0) { - len = 2; - } else if ((*p_utf8 & 0xf0) == 0xe0) { - len = 3; - } else if ((*p_utf8 & 0xf8) == 0xf0) { - len = 4; - } else { - UNICERROR("invalid len"); - return true; //invalid UTF8 - } - - if (len > cstr_size) { - UNICERROR("no space left"); - return true; //not enough space - } - - if (len == 2 && (*p_utf8 & 0x1E) == 0) { - UNICERROR("no space left"); - return true; //reject overlong - } - - /* Convert the first character */ - - uint32_t unichar = 0; - - if (len == 1) { - unichar = *p_utf8; + uint8_t c = *p_utf8 >= 0 ? *p_utf8 : uint8_t(256 + *p_utf8); + + if (skip == 0) { + /* Determine the number of characters in sequence */ + if ((c & 0x80) == 0) { + *(dst++) = c; + unichar = 0; + skip = 0; + } else if ((c & 0xe0) == 0xc0) { + unichar = (0xff >> 3) & c; + skip = 1; + } else if ((c & 0xf0) == 0xe0) { + unichar = (0xff >> 4) & c; + skip = 2; + } else if ((c & 0xf8) == 0xf0) { + unichar = (0xff >> 5) & c; + skip = 3; + } else if ((c & 0xfc) == 0xf8) { + unichar = (0xff >> 6) & c; + skip = 4; + } else if ((c & 0xfe) == 0xfc) { + unichar = (0xff >> 7) & c; + skip = 5; + } else { + *(dst++) = 0x20; + unichar = 0; + skip = 0; + } } else { - unichar = (0xff >> (len + 1)) & *p_utf8; - - for (int i = 1; i < len; i++) { - if ((p_utf8[i] & 0xc0) != 0x80) { - UNICERROR("invalid utf8"); - return true; //invalid utf8 - } - if (unichar == 0 && i == 2 && ((p_utf8[i] & 0x7f) >> (7 - len)) == 0) { - UNICERROR("invalid utf8 overlong"); - return true; //no overlong + if (c < 0x80 || c > 0xbf) { + *(dst++) = 0x20; + skip = 0; + } else { + unichar = (unichar << 6) | (c & 0x3f); + --skip; + if (skip == 0) { + if (unichar == 0) { + print_unicode_error("NUL character", true); + decode_failed = true; + unichar = 0x20; + } + if ((unichar & 0xfffff800) == 0xd800) { + print_unicode_error(vformat("Unpaired surrogate (%x)", unichar)); + decode_error = true; + } + if (unichar > 0x10ffff) { + print_unicode_error(vformat("Invalid unicode codepoint (%x)", unichar)); + decode_error = true; + } + *(dst++) = unichar; } - unichar = (unichar << 6) | (p_utf8[i] & 0x3f); } } - if (unichar >= 0xd800 && unichar <= 0xdfff) { - UNICERROR("invalid code point"); - return CharString(); - } - *(dst++) = unichar; - cstr_size -= len; - p_utf8 += len; + cstr_size--; + p_utf8++; + } + if (skip) { + *(dst++) = 0x20; } - return false; -#undef UNICERROR + if (decode_failed) { + return ERR_INVALID_DATA; + } else if (decode_error) { + return ERR_PARSE_ERROR; + } else { + return OK; + } } CharString String::utf8() const { @@ -1765,15 +1836,17 @@ CharString String::utf8() const { fl += 2; } else if (c <= 0xffff) { // 16 bits fl += 3; - } else if (c <= 0x0010ffff) { // 21 bits + } else if (c <= 0x001fffff) { // 21 bits fl += 4; + } else if (c <= 0x03ffffff) { // 26 bits + fl += 5; + print_unicode_error(vformat("Invalid unicode codepoint (%x)", c)); + } else if (c <= 0x7fffffff) { // 31 bits + fl += 6; + print_unicode_error(vformat("Invalid unicode codepoint (%x)", c)); } else { - print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + "."); - return CharString(); - } - if (c >= 0xd800 && c <= 0xdfff) { - print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + "."); - return CharString(); + fl += 1; + print_unicode_error(vformat("Invalid unicode codepoint (%x), cannot represent as UTF-8", c), true); } } @@ -1799,11 +1872,26 @@ CharString String::utf8() const { APPEND_CHAR(uint32_t(0xe0 | ((c >> 12) & 0x0f))); // Top 4 bits. APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Middle 6 bits. APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits. - } else { // 21 bits + } else if (c <= 0x001fffff) { // 21 bits APPEND_CHAR(uint32_t(0xf0 | ((c >> 18) & 0x07))); // Top 3 bits. APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // Upper middle 6 bits. APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower middle 6 bits. APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits. + } else if (c <= 0x03ffffff) { // 26 bits + APPEND_CHAR(uint32_t(0xf8 | ((c >> 24) & 0x03))); // Top 2 bits. + APPEND_CHAR(uint32_t(0x80 | ((c >> 18) & 0x3f))); // Upper middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits. + } else if (c <= 0x7fffffff) { // 31 bits + APPEND_CHAR(uint32_t(0xfc | ((c >> 30) & 0x01))); // Top 1 bit. + APPEND_CHAR(uint32_t(0x80 | ((c >> 24) & 0x3f))); // Upper upper middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | ((c >> 18) & 0x3f))); // Lower upper middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // Upper lower middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower lower middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits. + } else { + APPEND_CHAR(0x20); } } #undef APPEND_CHAR @@ -1819,11 +1907,9 @@ String String::utf16(const char16_t *p_utf16, int p_len) { return ret; } -bool String::parse_utf16(const char16_t *p_utf16, int p_len) { -#define UNICERROR(m_err) print_error("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-16?"); - +Error String::parse_utf16(const char16_t *p_utf16, int p_len) { if (!p_utf16) { - return true; + return ERR_INVALID_DATA; } String aux; @@ -1850,80 +1936,90 @@ bool String::parse_utf16(const char16_t *p_utf16, int p_len) { } } + bool decode_error = false; { const char16_t *ptrtmp = p_utf16; const char16_t *ptrtmp_limit = &p_utf16[p_len]; - int skip = 0; + uint32_t c_prev = 0; + bool skip = false; while (ptrtmp != ptrtmp_limit && *ptrtmp) { uint32_t c = (byteswap) ? BSWAP16(*ptrtmp) : *ptrtmp; - if (skip == 0) { - if ((c & 0xfffffc00) == 0xd800) { - skip = 1; // lead surrogate - } else if ((c & 0xfffffc00) == 0xdc00) { - UNICERROR("invalid utf16 surrogate at " + num_int64(cstr_size)); - return true; // invalid UTF16 - } else { - skip = 0; + + if ((c & 0xfffffc00) == 0xd800) { // lead surrogate + if (skip) { + print_unicode_error(vformat("Unpaired lead surrogate (%x [trail?] %x)", c_prev, c)); + decode_error = true; } - str_size++; - } else { - if ((c & 0xfffffc00) == 0xdc00) { // trail surrogate - --skip; + skip = true; + } else if ((c & 0xfffffc00) == 0xdc00) { // trail surrogate + if (skip) { + str_size--; } else { - UNICERROR("invalid utf16 surrogate at " + num_int64(cstr_size)); - return true; // invalid UTF16 + print_unicode_error(vformat("Unpaired trail surrogate (%x [lead?] %x)", c_prev, c)); + decode_error = true; } + skip = false; + } else { + skip = false; } + c_prev = c; + str_size++; cstr_size++; ptrtmp++; } if (skip) { - UNICERROR("no space left"); - return true; // not enough space + print_unicode_error(vformat("Unpaired lead surrogate (%x [eol])", c_prev)); + decode_error = true; } } if (str_size == 0) { clear(); - return false; + return OK; // empty string } resize(str_size + 1); char32_t *dst = ptrw(); dst[str_size] = 0; + bool skip = false; + uint32_t c_prev = 0; while (cstr_size) { - int len = 0; uint32_t c = (byteswap) ? BSWAP16(*p_utf16) : *p_utf16; - if ((c & 0xfffffc00) == 0xd800) { - len = 2; + if ((c & 0xfffffc00) == 0xd800) { // lead surrogate + if (skip) { + *(dst++) = c_prev; // unpaired, store as is + } + skip = true; + } else if ((c & 0xfffffc00) == 0xdc00) { // trail surrogate + if (skip) { + *(dst++) = (c_prev << 10UL) + c - ((0xd800 << 10UL) + 0xdc00 - 0x10000); // decode pair + } else { + *(dst++) = c; // unpaired, store as is + } + skip = false; } else { - len = 1; + *(dst++) = c; + skip = false; } - if (len > cstr_size) { - UNICERROR("no space left"); - return true; //not enough space - } - - uint32_t unichar = 0; - if (len == 1) { - unichar = c; - } else { - uint32_t c2 = (byteswap) ? BSWAP16(p_utf16[1]) : p_utf16[1]; - unichar = (c << 10UL) + c2 - ((0xd800 << 10UL) + 0xdc00 - 0x10000); - } + cstr_size--; + p_utf16++; + c_prev = c; + } - *(dst++) = unichar; - cstr_size -= len; - p_utf16 += len; + if (skip) { + *(dst++) = c_prev; } - return false; -#undef UNICERROR + if (decode_error) { + return ERR_PARSE_ERROR; + } else { + return OK; + } } Char16String String::utf16() const { @@ -1938,15 +2034,14 @@ Char16String String::utf16() const { uint32_t c = d[i]; if (c <= 0xffff) { // 16 bits. fl += 1; + if ((c & 0xfffff800) == 0xd800) { + print_unicode_error(vformat("Unpaired surrogate (%x)", c)); + } } else if (c <= 0x10ffff) { // 32 bits. fl += 2; } else { - print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + "."); - return Char16String(); - } - if (c >= 0xd800 && c <= 0xdfff) { - print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + "."); - return Char16String(); + print_unicode_error(vformat("Invalid unicode codepoint (%x), cannot represent as UTF-16", c), true); + fl += 1; } } @@ -1965,9 +2060,11 @@ Char16String String::utf16() const { if (c <= 0xffff) { // 16 bits. APPEND_CHAR(c); - } else { // 32 bits. + } else if (c <= 0x10ffff) { // 32 bits. APPEND_CHAR(uint32_t((c >> 10) + 0xd7c0)); // lead surrogate. APPEND_CHAR(uint32_t((c & 0x3ff) | 0xdc00)); // trail surrogate. + } else { + APPEND_CHAR(0x20); } } #undef APPEND_CHAR @@ -3359,36 +3456,36 @@ String String::repeat(int p_count) const { return new_string; } -String String::left(int p_pos) const { - if (p_pos < 0) { - p_pos = length() + p_pos; +String String::left(int p_len) const { + if (p_len < 0) { + p_len = length() + p_len; } - if (p_pos <= 0) { + if (p_len <= 0) { return ""; } - if (p_pos >= length()) { + if (p_len >= length()) { return *this; } - return substr(0, p_pos); + return substr(0, p_len); } -String String::right(int p_pos) const { - if (p_pos < 0) { - p_pos = length() + p_pos; +String String::right(int p_len) const { + if (p_len < 0) { + p_len = length() + p_len; } - if (p_pos <= 0) { + if (p_len <= 0) { return ""; } - if (p_pos >= length()) { + if (p_len >= length()) { return *this; } - return substr(length() - p_pos); + return substr(length() - p_len); } char32_t String::unicode_at(int p_idx) const { @@ -3712,18 +3809,15 @@ String String::uri_encode() const { const CharString temp = utf8(); String res; for (int i = 0; i < temp.length(); ++i) { - char ord = temp[i]; + uint8_t ord = temp[i]; if (ord == '.' || ord == '-' || ord == '~' || is_ascii_identifier_char(ord)) { res += ord; } else { - char h_Val[3]; -#if defined(__GNUC__) || defined(_MSC_VER) - snprintf(h_Val, 3, "%02hhX", ord); -#else - sprintf(h_Val, "%02hhX", ord); -#endif - res += "%"; - res += h_Val; + char p[4] = { '%', 0, 0, 0 }; + static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + p[1] = hex[ord >> 4]; + p[2] = hex[ord & 0xF]; + res += p; } } return res; diff --git a/core/string/ustring.h b/core/string/ustring.h index e4f6c3327a..1b8bf3d234 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -271,6 +271,9 @@ public: bool is_valid_string() const; + /* debug, error messages */ + void print_unicode_error(const String &p_message, bool p_critical = false) const; + /* complex helpers */ String substr(int p_from, int p_chars = -1) const; int find(const String &p_str, int p_from = 0) const; ///< return <0 if failed @@ -356,8 +359,8 @@ public: int count(const String &p_string, int p_from = 0, int p_to = 0) const; int countn(const String &p_string, int p_from = 0, int p_to = 0) const; - String left(int p_pos) const; - String right(int p_pos) const; + String left(int p_len) const; + String right(int p_len) const; String indent(const String &p_prefix) const; String dedent() const; String strip_edges(bool left = true, bool right = true) const; @@ -373,11 +376,11 @@ public: CharString ascii(bool p_allow_extended = false) const; CharString utf8() const; - bool parse_utf8(const char *p_utf8, int p_len = -1); //return true on error + Error parse_utf8(const char *p_utf8, int p_len = -1); static String utf8(const char *p_utf8, int p_len = -1); Char16String utf16() const; - bool parse_utf16(const char16_t *p_utf16, int p_len = -1); //return true on error + Error parse_utf16(const char16_t *p_utf16, int p_len = -1); static String utf16(const char16_t *p_utf16, int p_len = -1); static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */ diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index e5f73171a2..191f21a3dd 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -91,9 +91,9 @@ private: return hash; } - _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const { - uint32_t original_pos = p_hash % p_capacity; - return (p_pos - original_pos + p_capacity) % p_capacity; + static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { + const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); + return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); } bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { @@ -101,9 +101,10 @@ private: return false; // Failed lookups, no elements } - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = _hash(p_key); - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); uint32_t distance = 0; while (true) { @@ -111,7 +112,7 @@ private: return false; } - if (distance > _get_probe_length(pos, hashes[pos], capacity)) { + if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) { return false; } @@ -120,17 +121,18 @@ private: return true; } - pos = (pos + 1) % capacity; + pos = fastmod((pos + 1), capacity_inv, capacity); distance++; } } void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) { - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = p_hash; HashMapElement<TKey, TValue> *value = p_value; uint32_t distance = 0; - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); while (true) { if (hashes[pos] == EMPTY_HASH) { @@ -143,14 +145,14 @@ private: } // Not an empty slot, let's check the probing length of the existing one. - uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity); + uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv); if (existing_probe_len < distance) { SWAP(hash, hashes[pos]); SWAP(value, elements[pos]); distance = existing_probe_len; } - pos = (pos + 1) % capacity; + pos = fastmod((pos + 1), capacity_inv, capacity); distance++; } } @@ -316,13 +318,14 @@ public: return false; } - uint32_t capacity = hash_table_size_primes[capacity_index]; - uint32_t next_pos = (pos + 1) % capacity; - while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) { + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; + uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity); + while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) { SWAP(hashes[next_pos], hashes[pos]); SWAP(elements[next_pos], elements[pos]); pos = next_pos; - next_pos = (pos + 1) % capacity; + next_pos = fastmod((pos + 1), capacity_inv, capacity); } hashes[pos] = EMPTY_HASH; diff --git a/core/templates/hash_set.h b/core/templates/hash_set.h index 2318067dcc..7b3a5d46f8 100644 --- a/core/templates/hash_set.h +++ b/core/templates/hash_set.h @@ -74,9 +74,9 @@ private: return hash; } - _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const { - uint32_t original_pos = p_hash % p_capacity; - return (p_pos - original_pos + p_capacity) % p_capacity; + static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { + const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); + return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); } bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { @@ -84,9 +84,10 @@ private: return false; // Failed lookups, no elements } - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = _hash(p_key); - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); uint32_t distance = 0; while (true) { @@ -94,7 +95,7 @@ private: return false; } - if (distance > _get_probe_length(pos, hashes[pos], capacity)) { + if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) { return false; } @@ -103,17 +104,18 @@ private: return true; } - pos = (pos + 1) % capacity; + pos = fastmod(pos + 1, capacity_inv, capacity); distance++; } } uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) { - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = p_hash; uint32_t index = p_index; uint32_t distance = 0; - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); while (true) { if (hashes[pos] == EMPTY_HASH) { @@ -124,7 +126,7 @@ private: } // Not an empty slot, let's check the probing length of the existing one. - uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity); + uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv); if (existing_probe_len < distance) { key_to_hash[index] = pos; SWAP(hash, hashes[pos]); @@ -132,7 +134,7 @@ private: distance = existing_probe_len; } - pos = (pos + 1) % capacity; + pos = fastmod(pos + 1, capacity_inv, capacity); distance++; } } @@ -265,9 +267,10 @@ public: uint32_t key_pos = pos; pos = key_to_hash[pos]; //make hash pos - uint32_t capacity = hash_table_size_primes[capacity_index]; - uint32_t next_pos = (pos + 1) % capacity; - while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) { + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; + uint32_t next_pos = fastmod(pos + 1, capacity_inv, capacity); + while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) { uint32_t kpos = hash_to_key[pos]; uint32_t kpos_next = hash_to_key[next_pos]; SWAP(key_to_hash[kpos], key_to_hash[kpos_next]); @@ -275,7 +278,7 @@ public: SWAP(hash_to_key[next_pos], hash_to_key[pos]); pos = next_pos; - next_pos = (pos + 1) % capacity; + next_pos = fastmod(pos + 1, capacity_inv, capacity); } hashes[pos] = EMPTY_HASH; diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h index 1330d55270..547534f26a 100644 --- a/core/templates/hashfuncs.h +++ b/core/templates/hashfuncs.h @@ -56,30 +56,30 @@ * @param C String * @return 32-bits hashcode */ -static inline uint32_t hash_djb2(const char *p_cstr) { +static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) { const unsigned char *chr = (const unsigned char *)p_cstr; uint32_t hash = 5381; uint32_t c; while ((c = *chr++)) { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */ } return hash; } -static inline uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) { +static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) { uint32_t hash = p_prev; for (int i = 0; i < p_len; i++) { - hash = ((hash << 5) + hash) + p_buff[i]; /* hash * 33 + c */ + hash = ((hash << 5) + hash) ^ p_buff[i]; /* hash * 33 + c */ } return hash; } -static inline uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) { - return ((p_prev << 5) + p_prev) + p_in; +static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) { + return ((p_prev << 5) + p_prev) ^ p_in; } /** @@ -89,7 +89,7 @@ static inline uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) { * @param p_int - 64-bit unsigned integer key to be hashed * @return unsigned 32-bit value representing hashcode */ -static inline uint32_t hash_one_uint64(const uint64_t p_int) { +static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) { uint64_t v = p_int; v = (~v) + (v << 18); // v = (v << 18) - v - 1; v = v ^ (v >> 31); @@ -100,7 +100,134 @@ static inline uint32_t hash_one_uint64(const uint64_t p_int) { return uint32_t(v); } -static inline uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) { +#define HASH_MURMUR3_SEED 0x7F07C65 +// Murmurhash3 32-bit version. +// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code. + +static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { + p_in *= 0xcc9e2d51; + p_in = (p_in << 15) | (p_in >> 17); + p_in *= 0x1b873593; + + p_seed ^= p_in; + p_seed = (p_seed << 13) | (p_seed >> 19); + p_seed = p_seed * 5 + 0xe6546b64; + + return p_seed; +} + +static _FORCE_INLINE_ uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { + union { + float f; + uint32_t i; + } u; + + // Normalize +/- 0.0 and NaN values so they hash the same. + if (p_in == 0.0f) { + u.f = 0.0; + } else if (Math::is_nan(p_in)) { + u.f = NAN; + } else { + u.f = p_in; + } + + return hash_murmur3_one_32(u.i, p_seed); +} + +static _FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { + p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed); + return hash_murmur3_one_32(p_in >> 32, p_seed); +} + +static _FORCE_INLINE_ uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { + union { + double d; + uint64_t i; + } u; + + // Normalize +/- 0.0 and NaN values so they hash the same. + if (p_in == 0.0f) { + u.d = 0.0; + } else if (Math::is_nan(p_in)) { + u.d = NAN; + } else { + u.d = p_in; + } + + return hash_murmur3_one_64(u.i, p_seed); +} + +static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) { +#ifdef REAL_T_IS_DOUBLE + return hash_murmur3_one_double(p_in, p_seed); +#else + return hash_murmur3_one_float(p_in, p_seed); +#endif +} + +static _FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) { + return (x << r) | (x >> (32 - r)); +} + +static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed = HASH_MURMUR3_SEED) { + // Although not required, this is a random prime number. + const uint8_t *data = (const uint8_t *)key; + const int nblocks = length / 4; + + uint32_t h1 = seed; + + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4); + + for (int i = -nblocks; i; i++) { + uint32_t k1 = blocks[i]; + + k1 *= c1; + k1 = hash_rotl32(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = hash_rotl32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } + + const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); + + uint32_t k1 = 0; + + switch (length & 3) { + case 3: + k1 ^= tail[2] << 16; + [[fallthrough]]; + case 2: + k1 ^= tail[1] << 8; + [[fallthrough]]; + case 1: + k1 ^= tail[0]; + k1 *= c1; + k1 = hash_rotl32(k1, 15); + k1 *= c2; + h1 ^= k1; + }; + + // Finalize with additional bit mixing. + h1 ^= length; + return hash_fmix32(h1); +} + +static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) { union { double d; uint64_t i; @@ -119,7 +246,7 @@ static inline uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) } template <class T> -static inline uint32_t make_uint32_t(T p_in) { +static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) { union { T t; uint32_t _u32; @@ -129,7 +256,7 @@ static inline uint32_t make_uint32_t(T p_in) { return _u._u32; } -static inline uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) { +static _FORCE_INLINE_ uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) { union { double d; uint64_t i; @@ -147,12 +274,12 @@ static inline uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 538 return ((p_prev << 5) + p_prev) + u.i; } -static inline uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) { - return ((p_prev << 5) + p_prev) + p_in; +static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) { + return ((p_prev << 5) + p_prev) ^ p_in; } template <class T> -static inline uint64_t make_uint64_t(T p_in) { +static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) { union { T t; uint64_t _u64; @@ -167,78 +294,78 @@ template <class T> class Ref; struct HashMapHasherDefault { - static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } - static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } - static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } - static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); } - - static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_djb2_one_float(p_float); } - static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_djb2_one_float(p_double); } - static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; } - static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return (uint32_t)p_uchar; } - static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return (uint32_t)p_uchar; } - static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); } - - static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } - static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } - + // Generic hash function for any type. template <class T> static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); } template <class T> static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); } + static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } + static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } + static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(p_wchar); } + static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); } + static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); } + static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); } + static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } + static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } + static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); } + + static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } + static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(p_int); } + static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); } + static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); } + static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); } + static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(p_int); } + static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(p_int); } + static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(p_int); } + static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(p_int); } + static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(p_int); } static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) { - uint32_t h = hash_djb2_one_32(p_vec.x); - return hash_djb2_one_32(p_vec.y, h); + uint32_t h = hash_murmur3_one_32(p_vec.x); + h = hash_murmur3_one_32(p_vec.y, h); + return hash_fmix32(h); } static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) { - uint32_t h = hash_djb2_one_32(p_vec.x); - h = hash_djb2_one_32(p_vec.y, h); - return hash_djb2_one_32(p_vec.z, h); + uint32_t h = hash_murmur3_one_32(p_vec.x); + h = hash_murmur3_one_32(p_vec.y, h); + h = hash_murmur3_one_32(p_vec.z, h); + return hash_fmix32(h); } - static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) { - uint32_t h = hash_djb2_one_float(p_vec.x); - return hash_djb2_one_float(p_vec.y, h); + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + return hash_fmix32(h); } static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) { - uint32_t h = hash_djb2_one_float(p_vec.x); - h = hash_djb2_one_float(p_vec.y, h); - return hash_djb2_one_float(p_vec.z, h); + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + h = hash_murmur3_one_real(p_vec.z, h); + return hash_fmix32(h); } - static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) { - uint32_t h = hash_djb2_one_32(p_rect.position.x); - h = hash_djb2_one_32(p_rect.position.y, h); - h = hash_djb2_one_32(p_rect.size.x, h); - return hash_djb2_one_32(p_rect.size.y, h); + uint32_t h = hash_murmur3_one_32(p_rect.position.x); + h = hash_murmur3_one_32(p_rect.position.y, h); + h = hash_murmur3_one_32(p_rect.size.x, h); + h = hash_murmur3_one_32(p_rect.size.y, h); + return hash_fmix32(h); } - static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) { - uint32_t h = hash_djb2_one_float(p_rect.position.x); - h = hash_djb2_one_float(p_rect.position.y, h); - h = hash_djb2_one_float(p_rect.size.x, h); - return hash_djb2_one_float(p_rect.size.y, h); + uint32_t h = hash_murmur3_one_real(p_rect.position.x); + h = hash_murmur3_one_real(p_rect.position.y, h); + h = hash_murmur3_one_real(p_rect.size.x, h); + h = hash_murmur3_one_real(p_rect.size.y, h); + return hash_fmix32(h); } - static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) { - uint32_t h = hash_djb2_one_float(p_aabb.position.x); - h = hash_djb2_one_float(p_aabb.position.y, h); - h = hash_djb2_one_float(p_aabb.position.z, h); - h = hash_djb2_one_float(p_aabb.size.x, h); - h = hash_djb2_one_float(p_aabb.size.y, h); - return hash_djb2_one_float(p_aabb.size.z, h); + uint32_t h = hash_murmur3_one_real(p_aabb.position.x); + h = hash_murmur3_one_real(p_aabb.position.y, h); + h = hash_murmur3_one_real(p_aabb.position.z, h); + h = hash_murmur3_one_real(p_aabb.size.x, h); + h = hash_murmur3_one_real(p_aabb.size.y, h); + h = hash_murmur3_one_real(p_aabb.size.z, h); + return hash_fmix32(h); } - - //static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); } }; template <typename T> @@ -310,4 +437,66 @@ const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { 1610612741, }; +// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array. +const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = { + 3689348814741910324, + 1418980313362273202, + 802032351030850071, + 392483916461905354, + 190172619316593316, + 95578984837873325, + 47420935922132524, + 23987963684927896, + 11955116055547344, + 5991147799191151, + 2998982941588287, + 1501077717772769, + 750081082979285, + 375261795343686, + 187625172388393, + 93822606204624, + 46909513691883, + 23456218233098, + 11728086747027, + 5864041509391, + 2932024948977, + 1466014921160, + 733007198436, + 366503839517, + 183251896093, + 91625960335, + 45812983922, + 22906489714, + 11453246088 +}; + +/** + * Fastmod computes ( n mod d ) given the precomputed c much faster than n % d. + * The implementation of fastmod is based on the following paper by Daniel Lemire et al. + * Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries + * https://arxiv.org/abs/1902.01961 + */ +static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) { +#if defined(_MSC_VER) + // Returns the upper 64 bits of the product of two 64-bit unsigned integers. + // This intrinsic function is required since MSVC does not support unsigned 128-bit integers. +#if defined(_M_X64) || defined(_M_ARM64) + return __umulh(c * n, d); +#else + // Fallback to the slower method for 32-bit platforms. + return n % d; +#endif // _M_X64 || _M_ARM64 +#else +#ifdef __SIZEOF_INT128__ + // Prevent compiler warning, because we know what we are doing. + uint64_t lowbits = c * n; + __extension__ typedef unsigned __int128 uint128; + return static_cast<uint64_t>(((uint128)lowbits * d) >> 64); +#else + // Fallback to the slower method if no 128-bit unsigned integer type is available. + return n % d; +#endif // __SIZEOF_INT128__ +#endif // _MSC_VER +} + #endif // HASHFUNCS_H diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h index f4e0748c27..8d687effcf 100644 --- a/core/templates/local_vector.h +++ b/core/templates/local_vector.h @@ -38,7 +38,9 @@ #include <initializer_list> -template <class T, class U = uint32_t, bool force_trivial = false> +// If tight, it grows strictly as much as needed. +// Otherwise, it grows exponentially (the default and what you want in most cases). +template <class T, class U = uint32_t, bool force_trivial = false, bool tight = false> class LocalVector { private: U count = 0; @@ -121,7 +123,7 @@ public: _FORCE_INLINE_ bool is_empty() const { return count == 0; } _FORCE_INLINE_ U get_capacity() const { return capacity; } _FORCE_INLINE_ void reserve(U p_size) { - p_size = nearest_power_of_2_templated(p_size); + p_size = tight ? p_size : nearest_power_of_2_templated(p_size); if (p_size > capacity) { capacity = p_size; data = (T *)memrealloc(data, capacity * sizeof(T)); @@ -262,4 +264,7 @@ public: } }; +template <class T, class U = uint32_t, bool force_trivial = false> +using TightLocalVector = LocalVector<T, U, force_trivial, true>; + #endif // LOCAL_VECTOR_H diff --git a/core/templates/lru.h b/core/templates/lru.h index 48ba318b12..b08b6455b6 100644 --- a/core/templates/lru.h +++ b/core/templates/lru.h @@ -35,7 +35,7 @@ #include "hash_map.h" #include "list.h" -template <class TKey, class TData> +template <class TKey, class TData, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>> class LRUCache { private: struct Pair { @@ -52,7 +52,7 @@ private: typedef typename List<Pair>::Element *Element; List<Pair> _list; - HashMap<TKey, Element> _map; + HashMap<TKey, Element, Hasher, Comparator> _map; size_t capacity; public: @@ -102,6 +102,7 @@ public: } _FORCE_INLINE_ size_t get_capacity() const { return capacity; } + _FORCE_INLINE_ size_t get_size() const { return _map.size(); } void set_capacity(size_t p_capacity) { if (capacity > 0) { diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h index 76f76be96a..3148283dca 100644 --- a/core/templates/safe_refcount.h +++ b/core/templates/safe_refcount.h @@ -111,7 +111,7 @@ public: if (tmp >= p_value) { return tmp; // already greater, or equal } - if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) { + if (value.compare_exchange_weak(tmp, p_value, std::memory_order_acq_rel)) { return p_value; } } @@ -123,7 +123,7 @@ public: if (c == 0) { return 0; } - if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) { + if (value.compare_exchange_weak(c, c + 1, std::memory_order_acq_rel)) { return c + 1; } } diff --git a/core/templates/vector.h b/core/templates/vector.h index 2ac7c7630a..f3f5ed76a7 100644 --- a/core/templates/vector.h +++ b/core/templates/vector.h @@ -145,6 +145,9 @@ public: Vector<uint8_t> to_byte_array() const { Vector<uint8_t> ret; + if (is_empty()) { + return ret; + } ret.resize(size() * sizeof(T)); memcpy(ret.ptrw(), ptr(), sizeof(T) * size()); return ret; diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 7551350c95..af166e09a3 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -190,13 +190,13 @@ uint32_t Array::recursive_hash(int recursion_count) const { return 0; } - uint32_t h = hash_djb2_one_32(Variant::ARRAY); + uint32_t h = hash_murmur3_one_32(Variant::ARRAY); recursion_count++; for (int i = 0; i < _p->array.size(); i++) { - h = hash_djb2_one_32(_p->array[i].recursive_hash(recursion_count), h); + h = hash_murmur3_one_32(_p->array[i].recursive_hash(recursion_count), h); } - return h; + return hash_fmix32(h); } bool Array::_assign(const Array &p_array) { @@ -260,7 +260,9 @@ void Array::push_back(const Variant &p_value) { void Array::append_array(const Array &p_array) { ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state."); - ERR_FAIL_COND(!_p->typed.validate(p_array, "append_array")); + for (int i = 0; i < p_array.size(); ++i) { + ERR_FAIL_COND(!_p->typed.validate(p_array[i], "append_array")); + } _p->array.append_array(p_array._p->array); } @@ -501,6 +503,50 @@ Variant Array::reduce(const Callable &p_callable, const Variant &p_accum) const return ret; } +bool Array::any(const Callable &p_callable) const { + const Variant *argptrs[1]; + for (int i = 0; i < size(); i++) { + argptrs[0] = &get(i); + + Variant result; + Callable::CallError ce; + p_callable.call(argptrs, 1, result, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_FAIL_V_MSG(false, "Error calling method from 'any': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce)); + } + + if (result.operator bool()) { + // Return as early as possible when one of the conditions is `true`. + // This improves performance compared to relying on `filter(...).size() >= 1`. + return true; + } + } + + return false; +} + +bool Array::all(const Callable &p_callable) const { + const Variant *argptrs[1]; + for (int i = 0; i < size(); i++) { + argptrs[0] = &get(i); + + Variant result; + Callable::CallError ce; + p_callable.call(argptrs, 1, result, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_FAIL_V_MSG(false, "Error calling method from 'all': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce)); + } + + if (!(result.operator bool())) { + // Return as early as possible when one of the inverted conditions is `false`. + // This improves performance compared to relying on `filter(...).size() >= array_size().`. + return false; + } + } + + return true; +} + struct _ArrayVariantSort { _FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const { bool valid = false; diff --git a/core/variant/array.h b/core/variant/array.h index f537700f99..c007376734 100644 --- a/core/variant/array.h +++ b/core/variant/array.h @@ -108,6 +108,8 @@ public: Array filter(const Callable &p_callable) const; Array map(const Callable &p_callable) const; Variant reduce(const Callable &p_callable, const Variant &p_accum) const; + bool any(const Callable &p_callable) const; + bool all(const Callable &p_callable) const; bool operator<(const Array &p_array) const; bool operator<=(const Array &p_array) const; diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 22a13b0fab..84f894dcbf 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -106,6 +106,29 @@ struct VariantCaster<const T &> { static void initialize(m_enum &value) { value = (m_enum)0; } \ }; +#define VARIANT_BITFIELD_CAST(m_enum) \ + MAKE_BITFIELD_TYPE_INFO(m_enum) \ + template <> \ + struct VariantCaster<BitField<m_enum>> { \ + static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) { \ + return BitField<m_enum>(p_variant.operator int64_t()); \ + } \ + }; \ + template <> \ + struct PtrToArg<BitField<m_enum>> { \ + _FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) { \ + return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \ + } \ + typedef int64_t EncodeT; \ + _FORCE_INLINE_ static void encode(BitField<m_enum> p_val, const void *p_ptr) { \ + *(int64_t *)p_ptr = p_val; \ + } \ + }; \ + template <> \ + struct ZeroInitializer<BitField<m_enum>> { \ + static void initialize(BitField<m_enum> &value) { value = 0; } \ + }; + // Object enum casts must go here VARIANT_ENUM_CAST(Object::ConnectFlags); diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 516b8f2d51..5453f0d5c6 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -143,7 +143,8 @@ uint32_t Callable::hash() const { return custom->hash(); } else { uint32_t hash = method.hash(); - return hash_djb2_one_64(object, hash); + hash = hash_murmur3_one_64(object, hash); + return hash_fmix32(hash); } } diff --git a/core/variant/callable.h b/core/variant/callable.h index 6a760958d6..bbcf5427ba 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -61,6 +61,7 @@ public: CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments CALL_ERROR_INSTANCE_IS_NULL, + CALL_ERROR_METHOD_NOT_CONST, }; Error error = Error::CALL_OK; int argument = 0; diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index bda8c93a79..d9f4359ee5 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -269,6 +269,14 @@ void Dictionary::clear() { _p->variant_map.clear(); } +void Dictionary::merge(const Dictionary &p_dictionary, bool p_overwrite) { + for (const KeyValue<Variant, Variant> &E : p_dictionary._p->variant_map) { + if (p_overwrite || !has(E.key)) { + this->operator[](E.key) = E.value; + } + } +} + void Dictionary::_unref() const { ERR_FAIL_COND(!_p); if (_p->refcount.unref()) { @@ -290,15 +298,15 @@ uint32_t Dictionary::recursive_hash(int recursion_count) const { return 0; } - uint32_t h = hash_djb2_one_32(Variant::DICTIONARY); + uint32_t h = hash_murmur3_one_32(Variant::DICTIONARY); recursion_count++; for (const KeyValue<Variant, Variant> &E : _p->variant_map) { - h = hash_djb2_one_32(E.key.recursive_hash(recursion_count), h); - h = hash_djb2_one_32(E.value.recursive_hash(recursion_count), h); + h = hash_murmur3_one_32(E.key.recursive_hash(recursion_count), h); + h = hash_murmur3_one_32(E.value.recursive_hash(recursion_count), h); } - return h; + return hash_fmix32(h); } Array Dictionary::keys() const { diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h index 1224a4ff6f..2632893e8d 100644 --- a/core/variant/dictionary.h +++ b/core/variant/dictionary.h @@ -62,6 +62,7 @@ public: int size() const; bool is_empty() const; void clear(); + void merge(const Dictionary &p_dictionary, bool p_overwrite = false); bool has(const Variant &p_key) const; bool has_all(const Array &p_keys) const; diff --git a/core/variant/type_info.h b/core/variant/type_info.h index bacd0d19ce..1bd3a74289 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -279,6 +279,52 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) { return GetTypeInfo<T>::get_class_info().class_name; } +template <class T> +class BitField { + uint32_t value = 0; + +public: + _FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; } + _FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; } + _FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; } + _FORCE_INLINE_ BitField(uint32_t p_value) { value = p_value; } + _FORCE_INLINE_ operator uint32_t() const { return value; } + _FORCE_INLINE_ operator Variant() const { return value; } +}; + +#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \ + template <> \ + struct GetTypeInfo<m_impl> { \ + static const Variant::Type VARIANT_TYPE = Variant::INT; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \ + godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \ + } \ + }; \ + template <> \ + struct GetTypeInfo<BitField<m_impl>> { \ + static const Variant::Type VARIANT_TYPE = Variant::INT; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \ + godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \ + } \ + }; + +#define MAKE_BITFIELD_TYPE_INFO(m_enum) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &) + +template <typename T> +inline StringName __constant_get_bitfield_name(T param, const String &p_constant) { + if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) { + ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's bitfield: " + p_constant); + } + return GetTypeInfo<BitField<T>>::get_class_info().class_name; +} #define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info()) template <typename T> diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index e69bd88413..ae92d7b5c4 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -2780,7 +2780,7 @@ uint32_t Variant::recursive_hash(int recursion_count) const { return hash_one_uint64((uint64_t)_data._int); } break; case FLOAT: { - return hash_djb2_one_float(_data._float); + return hash_murmur3_one_float(_data._float); } break; case STRING: { return reinterpret_cast<const String *>(_data._mem)->hash(); @@ -2788,106 +2788,102 @@ uint32_t Variant::recursive_hash(int recursion_count) const { // math types case VECTOR2: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Vector2 *>(_data._mem)->x); - return hash_djb2_one_float(reinterpret_cast<const Vector2 *>(_data._mem)->y, hash); + return HashMapHasherDefault::hash(*reinterpret_cast<const Vector2 *>(_data._mem)); } break; case VECTOR2I: { - uint32_t hash = hash_djb2_one_32((uint32_t) reinterpret_cast<const Vector2i *>(_data._mem)->x); - return hash_djb2_one_32((uint32_t) reinterpret_cast<const Vector2i *>(_data._mem)->y, hash); + return HashMapHasherDefault::hash(*reinterpret_cast<const Vector2i *>(_data._mem)); } break; case RECT2: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->position.x); - hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->position.y, hash); - hash = hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->size.x, hash); - return hash_djb2_one_float(reinterpret_cast<const Rect2 *>(_data._mem)->size.y, hash); + return HashMapHasherDefault::hash(*reinterpret_cast<const Rect2 *>(_data._mem)); } break; case RECT2I: { - uint32_t hash = hash_djb2_one_32((uint32_t) reinterpret_cast<const Rect2i *>(_data._mem)->position.x); - hash = hash_djb2_one_32((uint32_t) reinterpret_cast<const Rect2i *>(_data._mem)->position.y, hash); - hash = hash_djb2_one_32((uint32_t) reinterpret_cast<const Rect2i *>(_data._mem)->size.x, hash); - return hash_djb2_one_32((uint32_t) reinterpret_cast<const Rect2i *>(_data._mem)->size.y, hash); + return HashMapHasherDefault::hash(*reinterpret_cast<const Rect2i *>(_data._mem)); } break; case TRANSFORM2D: { - 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->columns[i][j], hash); - } - } + uint32_t h = HASH_MURMUR3_SEED; + const Transform2D &t = *_data._transform2d; + h = hash_murmur3_one_real(t[0].x, h); + h = hash_murmur3_one_real(t[0].y, h); + h = hash_murmur3_one_real(t[1].x, h); + h = hash_murmur3_one_real(t[1].y, h); + h = hash_murmur3_one_real(t[2].x, h); + h = hash_murmur3_one_real(t[2].y, h); - return hash; + return hash_fmix32(h); } break; case VECTOR3: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->x); - hash = hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->y, hash); - return hash_djb2_one_float(reinterpret_cast<const Vector3 *>(_data._mem)->z, hash); + return HashMapHasherDefault::hash(*reinterpret_cast<const Vector3 *>(_data._mem)); } break; case VECTOR3I: { - uint32_t hash = hash_djb2_one_32((uint32_t) reinterpret_cast<const Vector3i *>(_data._mem)->x); - hash = hash_djb2_one_32((uint32_t) reinterpret_cast<const Vector3i *>(_data._mem)->y, hash); - return hash_djb2_one_32((uint32_t) reinterpret_cast<const Vector3i *>(_data._mem)->z, hash); + return HashMapHasherDefault::hash(*reinterpret_cast<const Vector3i *>(_data._mem)); } break; case PLANE: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->normal.x); - hash = hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->normal.y, hash); - hash = hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->normal.z, hash); - return hash_djb2_one_float(reinterpret_cast<const Plane *>(_data._mem)->d, hash); - + uint32_t h = HASH_MURMUR3_SEED; + const Plane &p = *reinterpret_cast<const Plane *>(_data._mem); + h = hash_murmur3_one_real(p.normal.x, h); + h = hash_murmur3_one_real(p.normal.y, h); + h = hash_murmur3_one_real(p.normal.z, h); + h = hash_murmur3_one_real(p.d, h); + return hash_fmix32(h); } break; case AABB: { - uint32_t hash = 5831; - for (int i = 0; i < 3; i++) { - hash = hash_djb2_one_float(_data._aabb->position[i], hash); - hash = hash_djb2_one_float(_data._aabb->size[i], hash); - } - - return hash; - + return HashMapHasherDefault::hash(*_data._aabb); } break; case QUATERNION: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->x); - hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->y, hash); - hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->z, hash); - return hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->w, hash); - + uint32_t h = HASH_MURMUR3_SEED; + const Quaternion &q = *reinterpret_cast<const Quaternion *>(_data._mem); + h = hash_murmur3_one_real(q.x, h); + h = hash_murmur3_one_real(q.y, h); + h = hash_murmur3_one_real(q.z, h); + h = hash_murmur3_one_real(q.w, h); + return hash_fmix32(h); } break; case BASIS: { - 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->rows[i][j], hash); - } - } - - return hash; - + uint32_t h = HASH_MURMUR3_SEED; + const Basis &b = *_data._basis; + h = hash_murmur3_one_real(b[0].x, h); + h = hash_murmur3_one_real(b[0].y, h); + h = hash_murmur3_one_real(b[0].z, h); + h = hash_murmur3_one_real(b[1].x, h); + h = hash_murmur3_one_real(b[1].y, h); + h = hash_murmur3_one_real(b[1].z, h); + h = hash_murmur3_one_real(b[2].x, h); + h = hash_murmur3_one_real(b[2].y, h); + h = hash_murmur3_one_real(b[2].z, h); + return hash_fmix32(h); } break; case TRANSFORM3D: { - 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.rows[i][j], hash); - } - hash = hash_djb2_one_float(_data._transform3d->origin[i], hash); - } - - return hash; - + uint32_t h = HASH_MURMUR3_SEED; + const Transform3D &t = *_data._transform3d; + h = hash_murmur3_one_real(t.basis[0].x, h); + h = hash_murmur3_one_real(t.basis[0].y, h); + h = hash_murmur3_one_real(t.basis[0].z, h); + h = hash_murmur3_one_real(t.basis[1].x, h); + h = hash_murmur3_one_real(t.basis[1].y, h); + h = hash_murmur3_one_real(t.basis[1].z, h); + h = hash_murmur3_one_real(t.basis[2].x, h); + h = hash_murmur3_one_real(t.basis[2].y, h); + h = hash_murmur3_one_real(t.basis[2].z, h); + h = hash_murmur3_one_real(t.origin.x, h); + h = hash_murmur3_one_real(t.origin.y, h); + h = hash_murmur3_one_real(t.origin.z, h); + return hash_fmix32(h); } break; - // misc types case COLOR: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->r); - hash = hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->g, hash); - hash = hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->b, hash); - return hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->a, hash); - + uint32_t h = HASH_MURMUR3_SEED; + const Color &c = *reinterpret_cast<const Color *>(_data._mem); + h = hash_murmur3_one_float(c.r, h); + h = hash_murmur3_one_float(c.g, h); + h = hash_murmur3_one_float(c.b, h); + h = hash_murmur3_one_float(c.a, h); + return hash_fmix32(h); } break; case RID: { - return hash_djb2_one_64(reinterpret_cast<const ::RID *>(_data._mem)->get_id()); + return hash_one_uint64(reinterpret_cast<const ::RID *>(_data._mem)->get_id()); } break; case OBJECT: { - return hash_djb2_one_64(make_uint64_t(_get_obj().obj)); + return hash_one_uint64(hash_make_uint64_t(_get_obj().obj)); } break; case STRING_NAME: { return reinterpret_cast<const StringName *>(_data._mem)->hash(); @@ -2906,7 +2902,7 @@ uint32_t Variant::recursive_hash(int recursion_count) const { case SIGNAL: { const Signal &s = *reinterpret_cast<const Signal *>(_data._mem); uint32_t hash = s.get_name().hash(); - return hash_djb2_one_64(s.get_object_id(), hash); + return hash_murmur3_one_64(s.get_object_id(), hash); } break; case ARRAY: { const Array &arr = *reinterpret_cast<const Array *>(_data._mem); @@ -2918,9 +2914,9 @@ uint32_t Variant::recursive_hash(int recursion_count) const { int len = arr.size(); if (likely(len)) { const uint8_t *r = arr.ptr(); - return hash_djb2_buffer((uint8_t *)&r[0], len); + return hash_murmur3_buffer((uint8_t *)&r[0], len); } else { - return hash_djb2_one_64(0); + return hash_murmur3_one_64(0); } } break; @@ -2929,9 +2925,9 @@ uint32_t Variant::recursive_hash(int recursion_count) const { int len = arr.size(); if (likely(len)) { const int32_t *r = arr.ptr(); - return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(int32_t)); + return hash_murmur3_buffer((uint8_t *)&r[0], len * sizeof(int32_t)); } else { - return hash_djb2_one_64(0); + return hash_murmur3_one_64(0); } } break; @@ -2940,9 +2936,9 @@ uint32_t Variant::recursive_hash(int recursion_count) const { int len = arr.size(); if (likely(len)) { const int64_t *r = arr.ptr(); - return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(int64_t)); + return hash_murmur3_buffer((uint8_t *)&r[0], len * sizeof(int64_t)); } else { - return hash_djb2_one_64(0); + return hash_murmur3_one_64(0); } } break; @@ -2952,9 +2948,13 @@ uint32_t Variant::recursive_hash(int recursion_count) const { if (likely(len)) { const float *r = arr.ptr(); - return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(float)); + uint32_t h = HASH_MURMUR3_SEED; + for (int32_t i = 0; i < len; i++) { + h = hash_murmur3_one_float(r[i], h); + } + return hash_fmix32(h); } else { - return hash_djb2_one_float(0.0); + return hash_murmur3_one_float(0.0); } } break; @@ -2964,14 +2964,18 @@ uint32_t Variant::recursive_hash(int recursion_count) const { if (likely(len)) { const double *r = arr.ptr(); - return hash_djb2_buffer((uint8_t *)&r[0], len * sizeof(double)); + uint32_t h = HASH_MURMUR3_SEED; + for (int32_t i = 0; i < len; i++) { + h = hash_murmur3_one_double(r[i], h); + } + return hash_fmix32(h); } else { - return hash_djb2_one_float(0.0); + return hash_murmur3_one_float(0.0); } } break; case PACKED_STRING_ARRAY: { - uint32_t hash = 5831; + uint32_t hash = HASH_MURMUR3_SEED; const Vector<String> &arr = PackedArrayRef<String>::get_array(_data.packed_array); int len = arr.size(); @@ -2979,14 +2983,15 @@ uint32_t Variant::recursive_hash(int recursion_count) const { const String *r = arr.ptr(); for (int i = 0; i < len; i++) { - hash = hash_djb2_one_32(r[i].hash(), hash); + hash = hash_murmur3_one_32(r[i].hash(), hash); } + hash = hash_fmix32(hash); } return hash; } break; case PACKED_VECTOR2_ARRAY: { - uint32_t hash = 5831; + uint32_t hash = HASH_MURMUR3_SEED; const Vector<Vector2> &arr = PackedArrayRef<Vector2>::get_array(_data.packed_array); int len = arr.size(); @@ -2994,15 +2999,16 @@ uint32_t Variant::recursive_hash(int recursion_count) const { const Vector2 *r = arr.ptr(); for (int i = 0; i < len; i++) { - hash = hash_djb2_one_float(r[i].x, hash); - hash = hash_djb2_one_float(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); } + hash = hash_fmix32(hash); } return hash; } break; case PACKED_VECTOR3_ARRAY: { - uint32_t hash = 5831; + uint32_t hash = HASH_MURMUR3_SEED; const Vector<Vector3> &arr = PackedArrayRef<Vector3>::get_array(_data.packed_array); int len = arr.size(); @@ -3010,16 +3016,17 @@ uint32_t Variant::recursive_hash(int recursion_count) const { const Vector3 *r = arr.ptr(); for (int i = 0; i < len; i++) { - hash = hash_djb2_one_float(r[i].x, hash); - hash = hash_djb2_one_float(r[i].y, hash); - hash = hash_djb2_one_float(r[i].z, hash); + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].z, hash); } + hash = hash_fmix32(hash); } return hash; } break; case PACKED_COLOR_ARRAY: { - uint32_t hash = 5831; + uint32_t hash = HASH_MURMUR3_SEED; const Vector<Color> &arr = PackedArrayRef<Color>::get_array(_data.packed_array); int len = arr.size(); @@ -3027,11 +3034,12 @@ uint32_t Variant::recursive_hash(int recursion_count) const { const Color *r = arr.ptr(); for (int i = 0; i < len; i++) { - hash = hash_djb2_one_float(r[i].r, hash); - hash = hash_djb2_one_float(r[i].g, hash); - hash = hash_djb2_one_float(r[i].b, hash); - hash = hash_djb2_one_float(r[i].a, hash); + hash = hash_murmur3_one_float(r[i].r, hash); + hash = hash_murmur3_one_float(r[i].g, hash); + hash = hash_murmur3_one_float(r[i].b, hash); + hash = hash_murmur3_one_float(r[i].a, hash); } + hash = hash_fmix32(hash); } return hash; @@ -3102,6 +3110,10 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const return *reinterpret_cast<const String *>(_data._mem) == *reinterpret_cast<const String *>(p_variant._data._mem); } break; + case STRING_NAME: { + return *reinterpret_cast<const StringName *>(_data._mem) == *reinterpret_cast<const StringName *>(p_variant._data._mem); + } break; + case VECTOR2: { const Vector2 *l = reinterpret_cast<const Vector2 *>(_data._mem); const Vector2 *r = reinterpret_cast<const Vector2 *>(p_variant._data._mem); @@ -3315,13 +3327,20 @@ Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Varia void Variant::static_assign(const Variant &p_variant) { } -bool Variant::is_shared() const { - switch (type) { +bool Variant::is_type_shared(Variant::Type p_type) { + switch (p_type) { case OBJECT: - return true; case ARRAY: - return true; case DICTIONARY: + case PACKED_BYTE_ARRAY: + case PACKED_INT32_ARRAY: + case PACKED_INT64_ARRAY: + case PACKED_FLOAT32_ARRAY: + case PACKED_FLOAT64_ARRAY: + case PACKED_STRING_ARRAY: + case PACKED_VECTOR2_ARRAY: + case PACKED_VECTOR3_ARRAY: + case PACKED_COLOR_ARRAY: return true; default: { } @@ -3330,6 +3349,10 @@ bool Variant::is_shared() const { return false; } +bool Variant::is_shared() const { + return is_type_shared(type); +} + void Variant::_variant_call_error(const String &p_method, Callable::CallError &error) { switch (error.error) { case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { @@ -3383,6 +3406,8 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_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_ERROR_METHOD_NOT_CONST) { + err_text = "Method not const in const instance"; } else if (ce.error == Callable::CallError::CALL_OK) { return "Call OK"; } diff --git a/core/variant/variant.h b/core/variant/variant.h index 726ba120b5..872b374b13 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -297,6 +297,7 @@ public: static String get_type_name(Variant::Type p_type); static bool can_convert(Type p_type_from, Type p_type_to); static bool can_convert_strict(Type p_type_from, Type p_type_to); + static bool is_type_shared(Variant::Type p_type); bool is_ref_counted() const; _FORCE_INLINE_ bool is_num() const { @@ -555,6 +556,7 @@ public: return ret; } + void call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error); 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); static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce); @@ -716,6 +718,10 @@ public: static bool has_constant(Variant::Type p_type, const StringName &p_value); static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr); + static void get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums); + static void get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations); + static int get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid = nullptr); + typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud); typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index a3568a8d6a..8e16a767cf 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -753,40 +753,56 @@ struct _VariantCall { static PackedInt32Array func_PackedByteArray_decode_s32_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedInt32Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(int32_t), dest, "Size didn't match array of size int32_t, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(int32_t), dest, "PackedByteArray size must be a multiple of 4 (size of 32-bit integer) to convert to PackedInt32Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(int32_t)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(int32_t)); return dest; } static PackedInt64Array func_PackedByteArray_decode_s64_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedInt64Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(int64_t), dest, "Size didn't match array of size int64_t, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(int64_t), dest, "PackedByteArray size must be a multiple of 8 (size of 64-bit integer) to convert to PackedInt64Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(int64_t)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(int64_t)); return dest; } static PackedFloat32Array func_PackedByteArray_decode_float_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedFloat32Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(float), dest, "Size didn't match array of size float, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(float), dest, "PackedByteArray size must be a multiple of 4 (size of 32-bit float) to convert to PackedFloat32Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(float)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(float)); return dest; } static PackedFloat64Array func_PackedByteArray_decode_double_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedFloat64Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(double), dest, "Size didn't match array of size double, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(double), dest, "PackedByteArray size must be a multiple of 8 (size of 64-bit double) to convert to PackedFloat64Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(double)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(double)); return dest; } @@ -919,7 +935,7 @@ struct _VariantCall { } struct ConstantData { - HashMap<StringName, int> value; + HashMap<StringName, int64_t> value; #ifdef DEBUG_ENABLED List<StringName> value_ordered; #endif @@ -931,7 +947,7 @@ struct _VariantCall { static ConstantData *constant_data; - static void add_constant(int p_type, StringName p_constant_name, int p_constant_value) { + static void add_constant(int p_type, StringName p_constant_name, int64_t p_constant_value) { constant_data[p_type].value[p_constant_name] = p_constant_value; #ifdef DEBUG_ENABLED constant_data[p_type].value_ordered.push_back(p_constant_name); @@ -944,9 +960,20 @@ struct _VariantCall { constant_data[p_type].variant_value_ordered.push_back(p_constant_name); #endif } + + struct EnumData { + HashMap<StringName, HashMap<StringName, int>> value; + }; + + static EnumData *enum_data; + + static void add_enum_constant(int p_type, StringName p_enum_type_name, StringName p_enumeration_name, int p_enum_value) { + enum_data[p_type].value[p_enum_type_name][p_enumeration_name] = p_enum_value; + } }; _VariantCall::ConstantData *_VariantCall::constant_data = nullptr; +_VariantCall::EnumData *_VariantCall::enum_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) = nullptr; @@ -1020,6 +1047,37 @@ void Variant::callp(const StringName &p_method, const Variant **p_args, int p_ar #endif r_ret = _get_obj().obj->callp(p_method, p_args, p_argcount, r_error); + } else { + r_error.error = Callable::CallError::CALL_OK; + + const VariantBuiltInMethodInfo *imf = builtin_method_info[type].lookup_ptr(p_method); + + if (!imf) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; + return; + } + + imf->call(this, p_args, p_argcount, r_ret, imf->default_arguments, r_error); + } +} + +void Variant::call_const(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; + if (!obj) { + r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return; + } +#ifdef DEBUG_ENABLED + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return; + } + +#endif + r_ret = _get_obj().obj->call_const(p_method, p_args, p_argcount, r_error); + //else if (type==Variant::METHOD) { } else { r_error.error = Callable::CallError::CALL_OK; @@ -1031,6 +1089,11 @@ void Variant::callp(const StringName &p_method, const Variant **p_args, int p_ar return; } + if (!imf->is_const) { + r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST; + return; + } + imf->call(this, p_args, p_argcount, r_ret, imf->default_arguments, r_error); } } @@ -1170,19 +1233,19 @@ uint32_t Variant::get_builtin_method_hash(Variant::Type p_type, const StringName ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0); const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); ERR_FAIL_COND_V(!method, 0); - uint32_t hash = hash_djb2_one_32(method->is_const); - hash = hash_djb2_one_32(method->is_static, hash); - hash = hash_djb2_one_32(method->is_vararg, hash); - hash = hash_djb2_one_32(method->has_return_type, hash); + uint32_t hash = hash_murmur3_one_32(method->is_const); + hash = hash_murmur3_one_32(method->is_static, hash); + hash = hash_murmur3_one_32(method->is_vararg, hash); + hash = hash_murmur3_one_32(method->has_return_type, hash); if (method->has_return_type) { - hash = hash_djb2_one_32(method->return_type, hash); + hash = hash_murmur3_one_32(method->return_type, hash); } - hash = hash_djb2_one_32(method->argument_count, hash); + hash = hash_murmur3_one_32(method->argument_count, hash); for (int i = 0; i < method->argument_count; i++) { - hash = method->get_argument_type(i); + hash = hash_murmur3_one_32(method->get_argument_type(i), hash); } - return hash; + return hash_fmix32(hash); } void Variant::get_method_list(List<MethodInfo> *p_list) const { @@ -1245,7 +1308,7 @@ void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_c 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) { + for (const KeyValue<StringName, int64_t> &E : cd.value) { p_constants->push_back(E.key); #endif } @@ -1281,7 +1344,7 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0); _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type]; - HashMap<StringName, int>::Iterator E = cd.value.find(p_value); + HashMap<StringName, int64_t>::Iterator E = cd.value.find(p_value); if (!E) { HashMap<StringName, Variant>::Iterator F = cd.variant_value.find(p_value); if (F) { @@ -1300,6 +1363,54 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va return E->value; } +void Variant::get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums) { + ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + for (const KeyValue<StringName, HashMap<StringName, int>> &E : enum_data.value) { + p_enums->push_back(E.key); + } +} + +void Variant::get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations) { + ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + for (const KeyValue<StringName, HashMap<StringName, int>> &E : enum_data.value) { + for (const KeyValue<StringName, int> &V : E.value) { + p_enumerations->push_back(V.key); + } + } +} + +int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid) { + if (r_valid) { + *r_valid = false; + } + + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + HashMap<StringName, HashMap<StringName, int>>::Iterator E = enum_data.value.find(p_enum_name); + if (!E) { + return -1; + } + + HashMap<StringName, int>::Iterator V = E->value.find(p_enumeration); + if (!V) { + return -1; + } + + if (r_valid) { + *r_valid = true; + } + + return V->value; +} + #ifdef DEBUG_METHODS_ENABLED #define bind_method(m_type, m_method, m_arg_names, m_default_args) \ METHOD_CLASS(m_type, m_method, &m_type::m_method); \ @@ -1360,6 +1471,7 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va static void _register_variant_builtin_methods() { _VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX); + _VariantCall::enum_data = memnew_arr(_VariantCall::EnumData, Variant::VARIANT_MAX); builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX); builtin_method_names = memnew_arr(List<StringName>, Variant::VARIANT_MAX); @@ -1402,8 +1514,8 @@ static void _register_variant_builtin_methods() { bind_method(String, to_upper, sarray(), varray()); bind_method(String, to_lower, sarray(), varray()); - bind_method(String, left, sarray("position"), varray()); - bind_method(String, right, sarray("position"), varray()); + bind_method(String, left, sarray("length"), varray()); + bind_method(String, right, sarray("length"), varray()); bind_method(String, strip_edges, sarray("left", "right"), varray(true, true)); bind_method(String, strip_escapes, sarray(), varray()); @@ -1472,6 +1584,10 @@ static void _register_variant_builtin_methods() { bind_static_method(String, chr, sarray("char"), varray()); bind_static_method(String, humanize_size, sarray("size"), varray()); + /* StringName */ + + bind_method(StringName, hash, sarray(), varray()); + /* Vector2 */ bind_method(Vector2, angle, sarray(), varray()); @@ -1492,6 +1608,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, lerp, sarray("to", "weight"), varray()); bind_method(Vector2, slerp, sarray("to", "weight"), varray()); bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Vector2, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray()); bind_method(Vector2, max_axis_index, sarray(), varray()); bind_method(Vector2, min_axis_index, sarray(), varray()); bind_method(Vector2, move_toward, sarray("to", "delta"), varray()); @@ -1579,6 +1696,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, lerp, sarray("to", "weight"), varray()); bind_method(Vector3, slerp, sarray("to", "weight"), varray()); bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Vector3, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray()); bind_method(Vector3, move_toward, sarray("to", "delta"), varray()); bind_method(Vector3, dot, sarray("with"), varray()); bind_method(Vector3, cross, sarray("with"), varray()); @@ -1671,6 +1789,8 @@ static void _register_variant_builtin_methods() { bind_static_method(Color, get_named_color, sarray("idx"), varray()); bind_static_method(Color, from_string, sarray("str", "default"), varray()); bind_static_method(Color, from_hsv, sarray("h", "s", "v", "alpha"), varray(1.0)); + bind_static_method(Color, from_ok_hsl, sarray("h", "s", "l", "alpha"), varray(1.0)); + bind_static_method(Color, from_rgbe9995, sarray("rgbe"), varray()); /* RID */ @@ -1684,7 +1804,9 @@ static void _register_variant_builtin_methods() { bind_method(NodePath, get_name_count, sarray(), varray()); bind_method(NodePath, get_name, sarray("idx"), varray()); bind_method(NodePath, get_subname_count, sarray(), varray()); + bind_method(NodePath, hash, sarray(), varray()); bind_method(NodePath, get_subname, sarray("idx"), varray()); + bind_method(NodePath, get_concatenated_names, sarray(), varray()); bind_method(NodePath, get_concatenated_subnames, sarray(), varray()); bind_method(NodePath, get_as_property_path, sarray(), varray()); bind_method(NodePath, is_empty, sarray(), varray()); @@ -1808,6 +1930,7 @@ static void _register_variant_builtin_methods() { bind_method(Dictionary, size, sarray(), varray()); bind_method(Dictionary, is_empty, sarray(), varray()); bind_method(Dictionary, clear, sarray(), varray()); + bind_method(Dictionary, merge, sarray("dictionary", "overwrite"), varray(false)); bind_method(Dictionary, has, sarray("key"), varray()); bind_method(Dictionary, has_all, sarray("keys"), varray()); bind_method(Dictionary, erase, sarray("key"), varray()); @@ -1853,6 +1976,8 @@ static void _register_variant_builtin_methods() { bind_method(Array, filter, sarray("method"), varray()); bind_method(Array, map, sarray("method"), varray()); bind_method(Array, reduce, sarray("method", "accum"), varray(Variant())); + bind_method(Array, any, sarray("method"), varray()); + bind_method(Array, all, sarray("method"), varray()); bind_method(Array, max, sarray(), varray()); bind_method(Array, min, sarray(), varray()); @@ -2114,6 +2239,10 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y); _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z); + _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_X", Vector3::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Y", Vector3::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Z", Vector3::AXIS_Z); + _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR3, "ONE", Vector3(1, 1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(INFINITY, INFINITY, INFINITY)); @@ -2128,6 +2257,10 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y); _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3i::AXIS_Z); + _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_X", Vector3i::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Y", Vector3i::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Z", Vector3i::AXIS_Z); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0)); @@ -2140,9 +2273,15 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X); _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_X", Vector2::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2i::AXIS_X); _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2i::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_X", Vector2i::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_Y", Vector2i::AXIS_Y); + _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(INFINITY, INFINITY)); @@ -2165,6 +2304,13 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY); _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX); + _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D()); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0)); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0)); @@ -2203,4 +2349,5 @@ void Variant::_unregister_variant_methods() { memdelete_arr(builtin_method_names); memdelete_arr(builtin_method_info); memdelete_arr(_VariantCall::constant_data); + memdelete_arr(_VariantCall::enum_data); } diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 3696ffae60..e0cfb42e1e 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -304,6 +304,13 @@ public: v->_get_obj().id = ObjectID(); } + static void update_object_id(Variant *v) { + const Object *o = v->_get_obj().obj; + if (o) { + v->_get_obj().id = o->get_instance_id(); + } + } + _FORCE_INLINE_ static void *get_opaque_pointer(Variant *v) { switch (v->type) { case Variant::NIL: diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h index 3b95f0531b..bc4dc4b408 100644 --- a/core/variant/variant_setget.h +++ b/core/variant/variant_setget.h @@ -329,4 +329,8 @@ SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h) SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s) SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v) +SETGET_NUMBER_STRUCT_FUNC(Color, double, ok_hsl_h, set_ok_hsl_h, get_ok_hsl_h) +SETGET_NUMBER_STRUCT_FUNC(Color, double, ok_hsl_s, set_ok_hsl_s, get_ok_hsl_s) +SETGET_NUMBER_STRUCT_FUNC(Color, double, ok_hsl_l, set_ok_hsl_l, get_ok_hsl_l) + #endif // VARIANT_SETGET_H diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 66badce268..2bca5f8284 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -231,6 +231,10 @@ struct VariantUtilityFunctions { return Math::cubic_interpolate(from, to, pre, post, weight); } + static inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t); + } + static inline double lerp_angle(double from, double to, double weight) { return Math::lerp_angle(from, to, weight); } @@ -267,6 +271,52 @@ struct VariantUtilityFunctions { return Math::db2linear(db); } + static inline Variant wrap(const Variant &p_x, const Variant &p_min, const Variant &p_max, Callable::CallError &r_error) { + Variant::Type x_type = p_x.get_type(); + if (x_type != Variant::INT && x_type != Variant::FLOAT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = x_type; + return Variant(); + } + + Variant::Type min_type = p_min.get_type(); + if (min_type != Variant::INT && min_type != Variant::FLOAT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = x_type; + return Variant(); + } + + Variant::Type max_type = p_max.get_type(); + if (max_type != Variant::INT && max_type != Variant::FLOAT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 2; + r_error.expected = x_type; + return Variant(); + } + + Variant value; + + switch (x_type) { + case Variant::INT: { + if (x_type != min_type || x_type != max_type) { + value = wrapf((double)p_x, (double)p_min, (double)p_max); + } else { + value = wrapi((int)p_x, (int)p_min, (int)p_max); + } + } break; + case Variant::FLOAT: { + value = wrapf((double)p_x, (double)p_min, (double)p_max); + } break; + default: + break; + } + + r_error.error = Callable::CallError::CALL_OK; + return value; + } + static inline int64_t wrapi(int64_t value, int64_t min, int64_t max) { return Math::wrapi(value, min, max); } @@ -510,6 +560,22 @@ struct VariantUtilityFunctions { r_error.error = Callable::CallError::CALL_OK; } + static inline void print_rich(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + String s; + for (int i = 0; i < p_arg_count; i++) { + String os = p_args[i]->operator String(); + + if (i == 0) { + s = os; + } else { + s += os; + } + } + + print_line_rich(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 s; @@ -1204,6 +1270,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH); @@ -1216,6 +1283,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(linear2db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(db2linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR3(wrap, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); @@ -1254,6 +1322,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDVARARGS(str, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDR(error_string, sarray("error"), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(print, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(print_rich, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(printerr, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(printt, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); FUNCBINDVARARGV(prints, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); @@ -1423,17 +1492,17 @@ uint32_t Variant::get_utility_function_hash(const StringName &p_name) { const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); ERR_FAIL_COND_V(!bfi, 0); - uint32_t hash = hash_djb2_one_32(bfi->is_vararg); - hash = hash_djb2_one_32(bfi->returns_value, hash); + uint32_t hash = hash_murmur3_one_32(bfi->is_vararg); + hash = hash_murmur3_one_32(bfi->returns_value, hash); if (bfi->returns_value) { - hash = hash_djb2_one_32(bfi->return_type, hash); + hash = hash_murmur3_one_32(bfi->return_type, hash); } - hash = hash_djb2_one_32(bfi->argcount, hash); + hash = hash_murmur3_one_32(bfi->argcount, hash); for (int i = 0; i < bfi->argcount; i++) { - hash = hash_djb2_one_32(bfi->get_arg_type(i), hash); + hash = hash_murmur3_one_32(bfi->get_arg_type(i), hash); } - return hash; + return hash_fmix32(hash); } void Variant::get_utility_function_list(List<StringName> *r_functions) { |