diff options
Diffstat (limited to 'core')
78 files changed, 2293 insertions, 855 deletions
diff --git a/core/SCsub b/core/SCsub index 80a5f6b623..40ee78d3ea 100644 --- a/core/SCsub +++ b/core/SCsub @@ -149,28 +149,38 @@ env.Depends( env.CommandNoCache( "#core/io/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt", - run_in_subprocess(core_builders.make_certs_header), + env.Run(core_builders.make_certs_header, "Building ca-certificates header."), ) # Make binders env.CommandNoCache( ["method_bind.gen.inc", "method_bind_ext.gen.inc", "method_bind_free_func.gen.inc"], "make_binders.py", - run_in_subprocess(make_binders.run), + env.Run(make_binders.run, "Generating method binders."), ) # Authors env.Depends("#core/authors.gen.h", "../AUTHORS.md") -env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", run_in_subprocess(core_builders.make_authors_header)) +env.CommandNoCache( + "#core/authors.gen.h", + "../AUTHORS.md", + env.Run(core_builders.make_authors_header, "Generating authors header."), +) # Donors env.Depends("#core/donors.gen.h", "../DONORS.md") -env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", run_in_subprocess(core_builders.make_donors_header)) +env.CommandNoCache( + "#core/donors.gen.h", + "../DONORS.md", + env.Run(core_builders.make_donors_header, "Generating donors header."), +) # License env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"]) env.CommandNoCache( - "#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"], run_in_subprocess(core_builders.make_license_header) + "#core/license.gen.h", + ["../COPYRIGHT.txt", "../LICENSE.txt"], + env.Run(core_builders.make_license_header, "Generating license header."), ) # Chain load SCsubs diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 267391c4d6..489ff762c9 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -31,6 +31,7 @@ #include "core_bind.h" #include "core/crypto/crypto_core.h" +#include "core/debugger/engine_debugger.h" #include "core/io/file_access_compressed.h" #include "core/io/file_access_encrypted.h" #include "core/io/json.h" @@ -454,7 +455,7 @@ Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { } else { dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY; dayclock = unix_time_val - dayno * SECS_DAY; - date.weekday = static_cast<OS::Weekday>((dayno - 3) % 7 + 7); + date.weekday = static_cast<OS::Weekday>(((dayno % 7) + 11) % 7); do { year--; dayno += YEARSIZE(year); @@ -781,6 +782,7 @@ void _OS::_bind_methods() { // Those default values need to be specified for the docs generator, // to avoid using values from the documentation writer's own OS instance. + ADD_PROPERTY_DEFAULT("tablet_driver", ""); ADD_PROPERTY_DEFAULT("exit_code", 0); ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false); ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900); @@ -1619,12 +1621,17 @@ Error _Directory::open(const String &p_path) { memdelete(d); } d = alt; + dir_open = true; return OK; } +bool _Directory::is_open() const { + return d && dir_open; +} + Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); _list_skip_navigational = p_skip_navigational; _list_skip_hidden = p_skip_hidden; @@ -1633,7 +1640,7 @@ Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) { } String _Directory::get_next() { - ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); String next = d->get_next(); while (next != "" && ((_list_skip_navigational && (next == "." || next == "..")) || (_list_skip_hidden && d->current_is_hidden()))) { @@ -1643,42 +1650,49 @@ String _Directory::get_next() { } bool _Directory::current_is_dir() const { - ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use."); return d->current_is_dir(); } void _Directory::list_dir_end() { - ERR_FAIL_COND_MSG(!d, "Directory must be opened before use."); + ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use."); d->list_dir_end(); } int _Directory::get_drive_count() { - ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); return d->get_drive_count(); } String _Directory::get_drive(int p_drive) { - ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); return d->get_drive(p_drive); } int _Directory::get_current_drive() { - ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); return d->get_current_drive(); } Error _Directory::change_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); - return d->change_dir(p_dir); + ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly."); + Error err = d->change_dir(p_dir); + + if (err != OK) { + return err; + } + dir_open = true; + + return OK; } String _Directory::get_current_dir() { - ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); return d->get_current_dir(); } Error _Directory::make_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly."); if (!p_dir.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_dir); Error err = d->make_dir(p_dir); @@ -1689,7 +1703,7 @@ Error _Directory::make_dir(String p_dir) { } Error _Directory::make_dir_recursive(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly."); if (!p_dir.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_dir); Error err = d->make_dir_recursive(p_dir); @@ -1700,8 +1714,7 @@ Error _Directory::make_dir_recursive(String p_dir) { } bool _Directory::file_exists(String p_file) { - ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use."); - + ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly."); if (!p_file.is_rel_path()) { return FileAccess::exists(p_file); } @@ -1710,30 +1723,29 @@ bool _Directory::file_exists(String p_file) { } bool _Directory::dir_exists(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly."); if (!p_dir.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_dir); bool exists = d->dir_exists(p_dir); memdelete(d); return exists; - - } else { - return d->dir_exists(p_dir); } + + return d->dir_exists(p_dir); } int _Directory::get_space_left() { - ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); return d->get_space_left() / 1024 * 1024; //return value in megabytes, given binding is int } Error _Directory::copy(String p_from, String p_to) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); return d->copy(p_from, p_to); } Error _Directory::rename(String p_from, String p_to) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); if (!p_from.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_from); Error err = d->rename(p_from, p_to); @@ -1745,7 +1757,7 @@ Error _Directory::rename(String p_from, String p_to) { } Error _Directory::remove(String p_name) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); if (!p_name.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_name); Error err = d->remove(p_name); @@ -2456,3 +2468,154 @@ Ref<JSONParseResult> _JSON::parse(const String &p_json) { } _JSON *_JSON::singleton = nullptr; + +////// _EngineDebugger ////// + +void _EngineDebugger::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_active"), &_EngineDebugger::is_active); + + ClassDB::bind_method(D_METHOD("register_profiler", "name", "toggle", "add", "tick"), &_EngineDebugger::register_profiler); + ClassDB::bind_method(D_METHOD("unregister_profiler", "name"), &_EngineDebugger::unregister_profiler); + ClassDB::bind_method(D_METHOD("is_profiling", "name"), &_EngineDebugger::is_profiling); + ClassDB::bind_method(D_METHOD("has_profiler", "name"), &_EngineDebugger::has_profiler); + + ClassDB::bind_method(D_METHOD("profiler_add_frame_data", "name", "data"), &_EngineDebugger::profiler_add_frame_data); + ClassDB::bind_method(D_METHOD("profiler_enable", "name", "enable", "arguments"), &_EngineDebugger::profiler_enable, DEFVAL(Array())); + + ClassDB::bind_method(D_METHOD("register_message_capture", "name", "callable"), &_EngineDebugger::register_message_capture); + ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &_EngineDebugger::unregister_message_capture); + ClassDB::bind_method(D_METHOD("has_capture", "name"), &_EngineDebugger::has_capture); + + ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &_EngineDebugger::send_message); +} + +bool _EngineDebugger::is_active() { + return EngineDebugger::is_active(); +} + +void _EngineDebugger::register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) { + ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), "Profiler already registered: " + p_name); + profilers.insert(p_name, ProfilerCallable(p_toggle, p_add, p_tick)); + ProfilerCallable &p = profilers[p_name]; + EngineDebugger::Profiler profiler( + &p, + &_EngineDebugger::call_toggle, + &_EngineDebugger::call_add, + &_EngineDebugger::call_tick); + EngineDebugger::register_profiler(p_name, profiler); +} + +void _EngineDebugger::unregister_profiler(const StringName &p_name) { + ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name); + EngineDebugger::unregister_profiler(p_name); + profilers.erase(p_name); +} + +bool _EngineDebugger::_EngineDebugger::is_profiling(const StringName &p_name) { + return EngineDebugger::is_profiling(p_name); +} + +bool _EngineDebugger::has_profiler(const StringName &p_name) { + return EngineDebugger::has_profiler(p_name); +} + +void _EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) { + EngineDebugger::profiler_add_frame_data(p_name, p_data); +} + +void _EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) { + if (EngineDebugger::get_singleton()) { + EngineDebugger::get_singleton()->profiler_enable(p_name, p_enabled, p_opts); + } +} + +void _EngineDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) { + ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), "Capture already registered: " + p_name); + captures.insert(p_name, p_callable); + Callable &c = captures[p_name]; + EngineDebugger::Capture capture(&c, &_EngineDebugger::call_capture); + EngineDebugger::register_message_capture(p_name, capture); +} + +void _EngineDebugger::unregister_message_capture(const StringName &p_name) { + ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name); + EngineDebugger::unregister_message_capture(p_name); + captures.erase(p_name); +} + +bool _EngineDebugger::has_capture(const StringName &p_name) { + return EngineDebugger::has_capture(p_name); +} + +void _EngineDebugger::send_message(const String &p_msg, const Array &p_data) { + ERR_FAIL_COND_MSG(!EngineDebugger::is_active(), "Can't send message. No active debugger"); + EngineDebugger::get_singleton()->send_message(p_msg, p_data); +} + +void _EngineDebugger::call_toggle(void *p_user, bool p_enable, const Array &p_opts) { + Callable &toggle = ((ProfilerCallable *)p_user)->callable_toggle; + if (toggle.is_null()) { + return; + } + Variant enable = p_enable, opts = p_opts; + const Variant *args[2] = { &enable, &opts }; + Variant retval; + Callable::CallError err; + toggle.call(args, 2, retval, err); + ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'toggle' to callable: " + Variant::get_callable_error_text(toggle, args, 2, err)); +} + +void _EngineDebugger::call_add(void *p_user, const Array &p_data) { + Callable &add = ((ProfilerCallable *)p_user)->callable_add; + if (add.is_null()) { + return; + } + Variant data = p_data; + const Variant *args[1] = { &data }; + Variant retval; + Callable::CallError err; + add.call(args, 1, retval, err); + ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'add' to callable: " + Variant::get_callable_error_text(add, args, 1, err)); +} + +void _EngineDebugger::call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + Callable &tick = ((ProfilerCallable *)p_user)->callable_tick; + if (tick.is_null()) { + return; + } + Variant frame_time = p_frame_time, idle_time = p_idle_time, physics_time = p_physics_time, physics_frame_time = p_physics_frame_time; + const Variant *args[4] = { &frame_time, &idle_time, &physics_time, &physics_frame_time }; + Variant retval; + Callable::CallError err; + tick.call(args, 4, retval, err); + ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'tick' to callable: " + Variant::get_callable_error_text(tick, args, 4, err)); +} + +Error _EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) { + Callable &capture = *(Callable *)p_user; + if (capture.is_null()) { + return FAILED; + } + Variant cmd = p_cmd, data = p_data; + const Variant *args[2] = { &cmd, &data }; + Variant retval; + Callable::CallError err; + capture.call(args, 2, retval, err); + ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(capture, args, 2, err)); + ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, "Error calling 'capture' to callable: " + String(capture) + ". Return type is not bool."); + r_captured = retval; + return OK; +} + +_EngineDebugger::~_EngineDebugger() { + for (Map<StringName, Callable>::Element *E = captures.front(); E; E = E->next()) { + EngineDebugger::unregister_message_capture(E->key()); + } + captures.clear(); + for (Map<StringName, ProfilerCallable>::Element *E = profilers.front(); E; E = E->next()) { + EngineDebugger::unregister_profiler(E->key()); + } + profilers.clear(); +} + +_EngineDebugger *_EngineDebugger::singleton = nullptr; diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index f9f5a4e7d7..a59fcda60c 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -457,6 +457,7 @@ VARIANT_ENUM_CAST(_File::CompressionMode); class _Directory : public Reference { GDCLASS(_Directory, Reference); DirAccess *d; + bool dir_open = false; protected: static void _bind_methods(); @@ -464,6 +465,8 @@ protected: public: Error open(const String &p_path); + bool is_open() const; + Error list_dir_begin(bool p_skip_navigational = false, bool p_skip_hidden = false); // This starts dir listing. String get_next(); bool current_is_dir() const; @@ -712,4 +715,58 @@ public: _JSON() { singleton = this; } }; +class _EngineDebugger : public Object { + GDCLASS(_EngineDebugger, Object); + + class ProfilerCallable { + friend class _EngineDebugger; + + Callable callable_toggle; + Callable callable_add; + Callable callable_tick; + + public: + ProfilerCallable() {} + + ProfilerCallable(const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) { + callable_toggle = p_toggle; + callable_add = p_add; + callable_tick = p_tick; + } + }; + + Map<StringName, Callable> captures; + Map<StringName, ProfilerCallable> profilers; + +protected: + static void _bind_methods(); + static _EngineDebugger *singleton; + +public: + static _EngineDebugger *get_singleton() { return singleton; } + + bool is_active(); + + void register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick); + void unregister_profiler(const StringName &p_name); + bool is_profiling(const StringName &p_name); + bool has_profiler(const StringName &p_name); + void profiler_add_frame_data(const StringName &p_name, const Array &p_data); + void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array()); + + void register_message_capture(const StringName &p_name, const Callable &p_callable); + void unregister_message_capture(const StringName &p_name); + bool has_capture(const StringName &p_name); + + void send_message(const String &p_msg, const Array &p_data); + + static void call_toggle(void *p_user, bool p_enable, const Array &p_opts); + static void call_add(void *p_user, const Array &p_data); + static void call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time); + static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured); + + _EngineDebugger() { singleton = this; } + ~_EngineDebugger(); +}; + #endif // CORE_BIND_H diff --git a/core/callable_method_pointer.h b/core/callable_method_pointer.h index 22db7d1c82..1bb89e53e1 100644 --- a/core/callable_method_pointer.h +++ b/core/callable_method_pointer.h @@ -131,7 +131,7 @@ void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), con #ifdef DEBUG_METHODS_ENABLED (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); #else - (p_instance->*p_method)(VariantCaster<P>::cast(p_args[Is])...); + (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...); #endif } @@ -228,7 +228,7 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co #ifdef DEBUG_METHODS_ENABLED r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); #else - (p_instance->*p_method)(VariantCaster<P>::cast(p_args[Is])...); + (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...); #endif } diff --git a/core/class_db.cpp b/core/class_db.cpp index 05c9850c39..88f1df3457 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -548,6 +548,29 @@ void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherit } } +#ifdef DEBUG_METHODS_ENABLED +static MethodInfo info_from_bind(MethodBind *p_method) { + MethodInfo minfo; + minfo.name = p_method->get_name(); + minfo.id = p_method->get_method_id(); + + for (int i = 0; i < p_method->get_argument_count(); i++) { + minfo.arguments.push_back(p_method->get_argument_info(i)); + } + + minfo.return_val = p_method->get_return_info(); + minfo.flags = p_method->get_hint_flags(); + + for (int i = 0; i < p_method->get_argument_count(); i++) { + if (p_method->has_default_argument(i)) { + minfo.default_arguments.push_back(p_method->get_default_argument(i)); + } + } + + return minfo; +} +#endif + void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { OBJTYPE_RLOCK; @@ -570,29 +593,12 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b } for (List<StringName>::Element *E = type->method_order.front(); E; E = E->next()) { - MethodBind *method = type->method_map.get(E->get()); - MethodInfo minfo; - minfo.name = E->get(); - minfo.id = method->get_method_id(); - - if (p_exclude_from_properties && type->methods_in_properties.has(minfo.name)) { + if (p_exclude_from_properties && type->methods_in_properties.has(E->get())) { continue; } - for (int i = 0; i < method->get_argument_count(); i++) { - //Variant::Type t=method->get_argument_type(i); - - minfo.arguments.push_back(method->get_argument_info(i)); - } - - minfo.return_val = method->get_return_info(); - minfo.flags = method->get_hint_flags(); - - for (int i = 0; i < method->get_argument_count(); i++) { - if (method->has_default_argument(i)) { - minfo.default_arguments.push_back(method->get_default_argument(i)); - } - } + MethodBind *method = type->method_map.get(E->get()); + MethodInfo minfo = info_from_bind(method); p_methods->push_back(minfo); } @@ -618,6 +624,57 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b } } +bool ClassDB::get_method_info(StringName p_class, StringName p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) { + OBJTYPE_RLOCK; + + ClassInfo *type = classes.getptr(p_class); + + while (type) { + if (type->disabled) { + if (p_no_inheritance) { + break; + } + + type = type->inherits_ptr; + continue; + } + +#ifdef DEBUG_METHODS_ENABLED + MethodBind **method = type->method_map.getptr(p_method); + if (method && *method) { + if (r_info != nullptr) { + MethodInfo minfo = info_from_bind(*method); + *r_info = minfo; + } + return true; + } else if (type->virtual_methods_map.has(p_method)) { + if (r_info) { + *r_info = type->virtual_methods_map[p_method]; + } + return true; + } +#else + if (type->method_map.has(p_method)) { + if (r_info) { + MethodBind *m = type->method_map[p_method]; + MethodInfo mi; + mi.name = m->get_name(); + *r_info = mi; + } + return true; + } +#endif + + if (p_no_inheritance) { + break; + } + + type = type->inherits_ptr; + } + + return false; +} + MethodBind *ClassDB::get_method(StringName p_class, StringName p_name) { OBJTYPE_RLOCK; @@ -718,6 +775,25 @@ int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p return 0; } +bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { + OBJTYPE_RLOCK; + + ClassInfo *type = classes.getptr(p_class); + + while (type) { + if (type->constant_map.has(p_name)) { + return true; + } + if (p_no_inheritance) { + return false; + } + + type = type->inherits_ptr; + } + + return false; +} + StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { OBJTYPE_RLOCK; @@ -784,6 +860,25 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_ } } +bool ClassDB::has_enum(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)) { + return true; + } + if (p_no_inheritance) { + return false; + } + + type = type->inherits_ptr; + } + + return false; +} + void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) { OBJTYPE_WLOCK; @@ -825,7 +920,7 @@ void ClassDB::get_signal_list(StringName p_class, List<MethodInfo> *p_signals, b } } -bool ClassDB::has_signal(StringName p_class, StringName p_signal) { +bool ClassDB::has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance) { OBJTYPE_RLOCK; ClassInfo *type = classes.getptr(p_class); ClassInfo *check = type; @@ -833,6 +928,9 @@ bool ClassDB::has_signal(StringName p_class, StringName p_signal) { if (check->signal_map.has(p_signal)) { return true; } + if (p_no_inheritance) { + return false; + } check = check->inherits_ptr; } @@ -910,6 +1008,7 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons OBJTYPE_WLOCK type->property_list.push_back(p_pinfo); + type->property_map[p_pinfo.name] = p_pinfo; #ifdef DEBUG_METHODS_ENABLED if (mb_get) { type->methods_in_properties.insert(p_getter); @@ -959,6 +1058,30 @@ void ClassDB::get_property_list(StringName p_class, List<PropertyInfo> *p_list, } } +bool ClassDB::get_property_info(StringName p_class, StringName p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) { + OBJTYPE_RLOCK; + + ClassInfo *check = classes.getptr(p_class); + while (check) { + if (check->property_map.has(p_property)) { + PropertyInfo pinfo = check->property_map[p_property]; + if (p_validator) { + p_validator->_validate_property(pinfo); + } + if (r_info) { + *r_info = pinfo; + } + return true; + } + if (p_no_inheritance) { + break; + } + check = check->inherits_ptr; + } + + return false; +} + bool ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid) { ClassInfo *type = classes.getptr(p_object->get_class_name()); ClassInfo *check = type; @@ -1239,6 +1362,7 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_ mi.flags |= METHOD_FLAG_VIRTUAL; } classes[p_class].virtual_methods.push_back(mi); + classes[p_class].virtual_methods_map[p_method.name] = mi; #endif } diff --git a/core/class_db.h b/core/class_db.h index eae2a9afd4..86ac2aa001 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -120,11 +120,13 @@ public: HashMap<StringName, List<StringName>> enum_map; HashMap<StringName, MethodInfo> signal_map; List<PropertyInfo> property_list; + HashMap<StringName, PropertyInfo> property_map; #ifdef DEBUG_METHODS_ENABLED List<StringName> constant_order; List<StringName> method_order; Set<StringName> methods_in_properties; List<MethodInfo> virtual_methods; + Map<StringName, MethodInfo> virtual_methods_map; StringName category; #endif HashMap<StringName, PropertySetGet> property_setget; @@ -328,7 +330,7 @@ public: } static void add_signal(StringName p_class, const MethodInfo &p_signal); - static bool has_signal(StringName p_class, StringName p_signal); + static bool has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance = false); static bool get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal); static void get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false); @@ -337,6 +339,7 @@ public: static void add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1); static void set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default); static void get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr); + static bool get_property_info(StringName p_class, StringName p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr); static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr); static bool get_property(Object *p_object, const StringName &p_property, Variant &r_value); static bool has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance = false); @@ -349,6 +352,7 @@ public: static void set_method_flags(StringName p_class, StringName p_method, int p_flags); static void get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false); + static bool get_method_info(StringName p_class, StringName p_method, MethodInfo *r_info, bool p_no_inheritance = false, bool p_exclude_from_properties = false); static MethodBind *get_method(StringName p_class, StringName p_name); static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true); @@ -357,10 +361,12 @@ public: static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant); 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 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 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 Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr); diff --git a/core/color.cpp b/core/color.cpp index 27a2d0af5c..c85cd9100d 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -261,33 +261,21 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) { return Color(rd, gd, bd, 1.0f); } -static float _parse_col(const String &p_str, int p_ofs) { - int ig = 0; - - for (int i = 0; i < 2; i++) { - int c = p_str[i + p_ofs]; - int v = 0; - - if (c >= '0' && c <= '9') { - v = c - '0'; - } else if (c >= 'a' && c <= 'f') { - v = c - 'a'; - v += 10; - } else if (c >= 'A' && c <= 'F') { - v = c - 'A'; - v += 10; - } else { - return -1; - } - - if (i == 0) { - ig += v * 16; - } else { - ig += v; - } +static int _parse_col4(const String &p_str, int p_ofs) { + char character = p_str[p_ofs]; + + if (character >= '0' && character <= '9') { + return character - '0'; + } else if (character >= 'a' && character <= 'f') { + return character + (10 - 'a'); + } else if (character >= 'A' && character <= 'F') { + return character + (10 - 'A'); } + return -1; +} - return ig; +static int _parse_col8(const String &p_str, int p_ofs) { + return _parse_col4(p_str, p_ofs) * 16 + _parse_col4(p_str, p_ofs + 1); } Color Color::inverted() const { @@ -302,49 +290,54 @@ Color Color::contrasted() const { return c; } -Color Color::html(const String &p_color) { - String color = p_color; +Color Color::html(const String &p_rgba) { + String color = p_rgba; if (color.length() == 0) { return Color(); } if (color[0] == '#') { - color = color.substr(1, color.length() - 1); - } - if (color.length() == 3 || color.length() == 4) { - String exp_color; - for (int i = 0; i < color.length(); i++) { - exp_color += color[i]; - exp_color += color[i]; - } - color = exp_color; + color = color.substr(1); } + // If enabled, use 1 hex digit per channel instead of 2. + // Other sizes aren't in the HTML/CSS spec but we could add them if desired. + bool is_shorthand = color.length() < 5; bool alpha = false; if (color.length() == 8) { alpha = true; } else if (color.length() == 6) { alpha = false; + } else if (color.length() == 4) { + alpha = true; + } else if (color.length() == 3) { + alpha = false; } else { - ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_color + "."); + ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + "."); } - int a = 255; - if (alpha) { - a = _parse_col(color, 0); - ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_color + "."); + float r, g, b, a = 1.0; + if (is_shorthand) { + r = _parse_col4(color, 0) / 15.0; + g = _parse_col4(color, 1) / 15.0; + b = _parse_col4(color, 2) / 15.0; + if (alpha) { + a = _parse_col4(color, 3) / 15.0; + } + } else { + r = _parse_col8(color, 0) / 255.0; + g = _parse_col8(color, 2) / 255.0; + b = _parse_col8(color, 4) / 255.0; + if (alpha) { + a = _parse_col8(color, 6) / 255.0; + } } + ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_rgba + "."); + ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_rgba + "."); + ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_rgba + "."); + ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_rgba + "."); - int from = alpha ? 2 : 0; - - int r = _parse_col(color, from + 0); - ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_color + "."); - int g = _parse_col(color, from + 2); - ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_color + "."); - int b = _parse_col(color, from + 4); - ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_color + "."); - - return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0); + return Color(r, g, b, a); } bool Color::html_is_valid(const String &p_color) { @@ -354,41 +347,22 @@ bool Color::html_is_valid(const String &p_color) { return false; } if (color[0] == '#') { - color = color.substr(1, color.length() - 1); + color = color.substr(1); } - bool alpha = false; - - if (color.length() == 8) { - alpha = true; - } else if (color.length() == 6) { - alpha = false; - } else { + // Check if the amount of hex digits is valid. + int len = color.length(); + if (!(len == 3 || len == 4 || len == 6 || len == 8)) { return false; } - if (alpha) { - int a = _parse_col(color, 0); - if (a < 0) { + // Check if each hex digit is valid. + for (int i = 0; i < len; i++) { + if (_parse_col4(color, i) == -1) { return false; } } - int from = alpha ? 2 : 0; - - int r = _parse_col(color, from + 0); - if (r < 0) { - return false; - } - int g = _parse_col(color, from + 2); - if (g < 0) { - return false; - } - int b = _parse_col(color, from + 4); - if (b < 0) { - return false; - } - return true; } @@ -438,7 +412,7 @@ String Color::to_html(bool p_alpha) const { txt += _to_hex(g); txt += _to_hex(b); if (p_alpha) { - txt = _to_hex(a) + txt; + txt += _to_hex(a); } return txt; } diff --git a/core/color.h b/core/color.h index 258965fd16..096e97e9ae 100644 --- a/core/color.h +++ b/core/color.h @@ -185,7 +185,7 @@ struct Color { static Color hex(uint32_t p_hex); static Color hex64(uint64_t p_hex); - static Color html(const String &p_color); + static Color html(const String &p_rgba); static bool html_is_valid(const String &p_color); static Color named(const String &p_name); String to_html(bool p_alpha = true) const; diff --git a/core/compressed_translation.cpp b/core/compressed_translation.cpp index a66997aa52..a92275565d 100644 --- a/core/compressed_translation.cpp +++ b/core/compressed_translation.cpp @@ -43,6 +43,8 @@ struct _PHashTranslationCmp { }; void PHashTranslation::generate(const Ref<Translation> &p_from) { + // This method compresses a Translation instance. + // Right now it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed. #ifdef TOOLS_ENABLED List<StringName> keys; p_from->get_message_list(&keys); @@ -212,7 +214,9 @@ bool PHashTranslation::_get(const StringName &p_name, Variant &r_ret) const { return true; } -StringName PHashTranslation::get_message(const StringName &p_src_text) const { +StringName PHashTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const { + // p_context passed in is ignore. The use of context is not yet supported in PHashTranslation. + int htsize = hash_table.size(); if (htsize == 0) { @@ -267,6 +271,11 @@ StringName PHashTranslation::get_message(const StringName &p_src_text) const { } } +StringName PHashTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const { + // The use of plurals translation is not yet supported in PHashTranslation. + return get_message(p_src_text, p_context); +} + void PHashTranslation::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "hash_table")); p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "bucket_table")); diff --git a/core/compressed_translation.h b/core/compressed_translation.h index 3c029bdf58..c8b3cd2330 100644 --- a/core/compressed_translation.h +++ b/core/compressed_translation.h @@ -79,7 +79,8 @@ protected: static void _bind_methods(); public: - virtual StringName get_message(const StringName &p_src_text) const; //overridable for other implementations + virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations + virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override; void generate(const Ref<Translation> &p_from); PHashTranslation() {} diff --git a/core/container_type_validate.h b/core/container_type_validate.h index f2724e884d..8a361aa0ef 100644 --- a/core/container_type_validate.h +++ b/core/container_type_validate.h @@ -38,7 +38,7 @@ struct ContainerTypeValidate { Variant::Type type = Variant::NIL; StringName class_name; Ref<Script> script; - const char *where = "conatiner"; + const char *where = "container"; _FORCE_INLINE_ bool can_reference(const ContainerTypeValidate &p_type) const { if (type == p_type.type) { diff --git a/core/core_builders.py b/core/core_builders.py index d03874608e..004475faa7 100644 --- a/core/core_builders.py +++ b/core/core_builders.py @@ -117,14 +117,18 @@ def make_donors_header(target, source, env): sections = [ "Platinum sponsors", "Gold sponsors", + "Silver sponsors", + "Bronze sponsors", "Mini sponsors", "Gold donors", "Silver donors", "Bronze donors", ] sections_id = [ - "DONORS_SPONSOR_PLAT", + "DONORS_SPONSOR_PLATINUM", "DONORS_SPONSOR_GOLD", + "DONORS_SPONSOR_SILVER", + "DONORS_SPONSOR_BRONZE", "DONORS_SPONSOR_MINI", "DONORS_GOLD", "DONORS_SILVER", diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp index 5c9fb67de4..4bf31aa55f 100644 --- a/core/debugger/engine_debugger.cpp +++ b/core/debugger/engine_debugger.cpp @@ -169,7 +169,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Ve for (int i = 0; i < p_breakpoints.size(); i++) { String bp = p_breakpoints[i]; - int sp = bp.find_last(":"); + int sp = bp.rfind(":"); ERR_CONTINUE_MSG(sp == -1, "Invalid breakpoint: '" + bp + "', expected file:line format."); singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp)); diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 62f600c5e5..9d55e1312e 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -373,6 +373,7 @@ struct RemoteDebugger::VisualProfiler { struct RemoteDebugger::PerformanceProfiler { Object *performance = nullptr; int last_perf_time = 0; + uint64_t last_monitor_modification_time = 0; void toggle(bool p_enable, const Array &p_opts) {} void add(const Array &p_data) {} @@ -386,12 +387,31 @@ struct RemoteDebugger::PerformanceProfiler { return; } last_perf_time = pt; + + Array custom_monitor_names = performance->call("get_custom_monitor_names"); + + uint64_t monitor_modification_time = performance->call("get_monitor_modification_time"); + if (monitor_modification_time > last_monitor_modification_time) { + last_monitor_modification_time = monitor_modification_time; + EngineDebugger::get_singleton()->send_message("performance:profile_names", custom_monitor_names); + } + int max = performance->get("MONITOR_MAX"); Array arr; - arr.resize(max); + arr.resize(max + custom_monitor_names.size()); for (int i = 0; i < max; i++) { arr[i] = performance->call("get_monitor", i); } + + for (int i = 0; i < custom_monitor_names.size(); i++) { + Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]); + if (!monitor_value.is_num()) { + ERR_PRINT("Value of custom monitor '" + String(custom_monitor_names[i]) + "' is not a number"); + arr[i + max] = Variant(); + } + arr[i + max] = monitor_value; + } + EngineDebugger::get_singleton()->send_message("performance:profile_frame", arr); } diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index faa3a75fda..0ce0042f50 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -225,7 +225,7 @@ RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) { uint16_t debug_port = 6007; if (debug_host.find(":") != -1) { - int sep_pos = debug_host.find_last(":"); + int sep_pos = debug_host.rfind(":"); debug_port = debug_host.substr(sep_pos + 1).to_int(); debug_host = debug_host.substr(0, sep_pos); } diff --git a/core/engine.cpp b/core/engine.cpp index c8bfffd020..d08cf92ecb 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -158,8 +158,10 @@ Array Engine::get_copyright_info() const { Dictionary Engine::get_donor_info() const { Dictionary donors; - donors["platinum_sponsors"] = array_from_info(DONORS_SPONSOR_PLAT); + donors["platinum_sponsors"] = array_from_info(DONORS_SPONSOR_PLATINUM); donors["gold_sponsors"] = array_from_info(DONORS_SPONSOR_GOLD); + donors["silver_sponsors"] = array_from_info(DONORS_SPONSOR_SILVER); + donors["bronze_sponsors"] = array_from_info(DONORS_SPONSOR_BRONZE); donors["mini_sponsors"] = array_from_info(DONORS_SPONSOR_MINI); donors["gold_donors"] = array_from_info(DONORS_GOLD); donors["silver_donors"] = array_from_info(DONORS_SILVER); diff --git a/core/error_macros.h b/core/error_macros.h index d7366be453..6353961b04 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -476,7 +476,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * The current function returns. */ #define ERR_FAIL() \ - if (1) { \ + if (true) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \ return; \ } else \ @@ -489,7 +489,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Prints `m_msg`, and the current function returns. */ #define ERR_FAIL_MSG(m_msg) \ - if (1) { \ + if (true) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", DEBUG_STR(m_msg)); \ return; \ } else \ @@ -503,7 +503,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * The current function returns `m_retval`. */ #define ERR_FAIL_V(m_retval) \ - if (1) { \ + if (true) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \ return m_retval; \ } else \ @@ -516,7 +516,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Prints `m_msg`, and the current function returns `m_retval`. */ #define ERR_FAIL_V_MSG(m_retval, m_msg) \ - if (1) { \ + if (true) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), DEBUG_STR(m_msg)); \ return m_retval; \ } else \ @@ -536,7 +536,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Prints `m_msg` once during the application lifetime. */ #define ERR_PRINT_ONCE(m_msg) \ - if (1) { \ + if (true) { \ static bool first_print = true; \ if (first_print) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \ @@ -561,7 +561,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. */ #define WARN_PRINT_ONCE(m_msg) \ - if (1) { \ + if (true) { \ static bool first_print = true; \ if (first_print) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, ERR_HANDLER_WARNING); \ @@ -576,7 +576,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Warns that the current function is deprecated. */ #define WARN_DEPRECATED \ - if (1) { \ + if (true) { \ static volatile bool warning_shown = false; \ if (!warning_shown) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \ @@ -589,7 +589,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Warns that the current function is deprecated and prints `m_msg`. */ #define WARN_DEPRECATED_MSG(m_msg) \ - if (1) { \ + if (true) { \ static volatile bool warning_shown = false; \ if (!warning_shown) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \ @@ -605,7 +605,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * The application crashes. */ #define CRASH_NOW() \ - if (1) { \ + if (true) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \ GENERATE_TRAP(); \ } else \ @@ -617,7 +617,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Prints `m_msg`, and then the application crashes. */ #define CRASH_NOW_MSG(m_msg) \ - if (1) { \ + if (true) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", DEBUG_STR(m_msg)); \ GENERATE_TRAP(); \ } else \ diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 6281e56395..b30685539a 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -38,6 +38,7 @@ struct _GlobalConstant { #ifdef DEBUG_METHODS_ENABLED StringName enum_name; + bool ignore_value_in_docs; #endif const char *name; int value; @@ -45,8 +46,9 @@ struct _GlobalConstant { _GlobalConstant() {} #ifdef DEBUG_METHODS_ENABLED - _GlobalConstant(const StringName &p_enum_name, const char *p_name, int p_value) : + _GlobalConstant(const StringName &p_enum_name, const char *p_name, int 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) { } @@ -71,6 +73,15 @@ static Vector<_GlobalConstant> _global_constants; #define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \ _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant)); +#define BIND_GLOBAL_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(StringName(), #m_constant, m_constant, true)); + +#define BIND_GLOBAL_ENUM_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant, true)); + +#define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \ + _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant, true)); + #else #define BIND_GLOBAL_CONSTANT(m_constant) \ @@ -82,6 +93,15 @@ static Vector<_GlobalConstant> _global_constants; #define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \ _global_constants.push_back(_GlobalConstant(m_custom_name, m_constant)); +#define BIND_GLOBAL_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(#m_constant, m_constant)); + +#define BIND_GLOBAL_ENUM_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(#m_constant, m_constant)); + +#define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \ + _global_constants.push_back(_GlobalConstant(m_custom_name, m_constant)); + #endif VARIANT_ENUM_CAST(KeyList); @@ -368,7 +388,7 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_ALT); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_META); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_CTRL); - BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_CMD); + BIND_GLOBAL_ENUM_CONSTANT_NO_VAL(KEY_MASK_CMD); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_KPAD); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_GROUP_SWITCH); @@ -648,10 +668,18 @@ int GlobalConstants::get_global_constant_count() { StringName GlobalConstants::get_global_constant_enum(int p_idx) { return _global_constants[p_idx].enum_name; } + +bool GlobalConstants::get_ignore_value_in_docs(int p_idx) { + return _global_constants[p_idx].ignore_value_in_docs; +} #else StringName GlobalConstants::get_global_constant_enum(int p_idx) { return StringName(); } + +bool GlobalConstants::get_ignore_value_in_docs(int p_idx) { + return false; +} #endif const char *GlobalConstants::get_global_constant_name(int p_idx) { diff --git a/core/global_constants.h b/core/global_constants.h index a20b5ecd9a..989633a6fa 100644 --- a/core/global_constants.h +++ b/core/global_constants.h @@ -37,6 +37,7 @@ class GlobalConstants { public: static int get_global_constant_count(); 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); }; diff --git a/core/hash_map.h b/core/hash_map.h index 843430d082..10fc931e7a 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -280,13 +280,13 @@ public: const TData &get(const TKey &p_key) const { const TData *res = getptr(p_key); - ERR_FAIL_COND_V(!res, *res); + CRASH_COND_MSG(!res, "Map key not found."); return *res; } TData &get(const TKey &p_key) { TData *res = getptr(p_key); - ERR_FAIL_COND_V(!res, *res); + CRASH_COND_MSG(!res, "Map key not found."); return *res; } diff --git a/core/image.cpp b/core/image.cpp index 45f10625a9..e2f353698f 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -30,6 +30,7 @@ #include "image.h" +#include "core/error_macros.h" #include "core/hash_map.h" #include "core/io/image_loader.h" #include "core/io/resource_loader.h" @@ -1894,8 +1895,10 @@ Vector<uint8_t> Image::get_data() const { } void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) { - ERR_FAIL_INDEX(p_width - 1, MAX_WIDTH); - ERR_FAIL_INDEX(p_height - 1, MAX_HEIGHT); + ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0."); + ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0."); + ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); + ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); int mm = 0; @@ -1914,8 +1917,10 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma } void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) { - ERR_FAIL_INDEX(p_width - 1, MAX_WIDTH); - ERR_FAIL_INDEX(p_height - 1, MAX_HEIGHT); + ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0."); + ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0."); + ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); + ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); int mm; @@ -2629,6 +2634,7 @@ void Image::fill(const Color &c) { ImageMemLoadFunc Image::_png_mem_loader_func = nullptr; ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr; ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr; +ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr; void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nullptr; void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr; @@ -3058,6 +3064,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer); ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer); ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer); + ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data"); @@ -3389,6 +3396,11 @@ Error Image::load_webp_from_buffer(const Vector<uint8_t> &p_array) { return _load_from_buffer(p_array, _webp_mem_loader_func); } +Error Image::load_tga_from_buffer(const Vector<uint8_t> &p_array) { + ERR_FAIL_NULL_V_MSG(_tga_mem_loader_func, ERR_UNAVAILABLE, "TGA module was not installed."); + return _load_from_buffer(p_array, _tga_mem_loader_func); +} + void Image::convert_rg_to_ra_rgba8() { ERR_FAIL_COND(format != FORMAT_RGBA8); ERR_FAIL_COND(!data.size()); diff --git a/core/image.h b/core/image.h index 53c203998e..d2572b072e 100644 --- a/core/image.h +++ b/core/image.h @@ -135,6 +135,7 @@ public: static ImageMemLoadFunc _png_mem_loader_func; static ImageMemLoadFunc _jpg_mem_loader_func; static ImageMemLoadFunc _webp_mem_loader_func; + static ImageMemLoadFunc _tga_mem_loader_func; static void (*_image_compress_bc_func)(Image *, float, UsedChannels p_channels); static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, UsedChannels p_channels); @@ -360,6 +361,7 @@ public: Error load_png_from_buffer(const Vector<uint8_t> &p_array); Error load_jpg_from_buffer(const Vector<uint8_t> &p_array); Error load_webp_from_buffer(const Vector<uint8_t> &p_array); + Error load_tga_from_buffer(const Vector<uint8_t> &p_array); void convert_rg_to_ra_rgba8(); void convert_ra_rgba8_to_rg(); @@ -367,7 +369,7 @@ public: Image(const uint8_t *p_mem_png_jpg, int p_len = -1); Image(const char **p_xpm); - virtual Ref<Resource> duplicate(bool p_subresources = false) const; + virtual Ref<Resource> duplicate(bool p_subresources = false) const override; UsedChannels detect_used_channels(CompressSource p_source = COMPRESS_SOURCE_GENERIC); void optimize_channels(); diff --git a/core/input/SCsub b/core/input/SCsub index c641819698..f40978911b 100644 --- a/core/input/SCsub +++ b/core/input/SCsub @@ -16,7 +16,7 @@ env.Depends("#core/input/default_controller_mappings.gen.cpp", controller_databa env.CommandNoCache( "#core/input/default_controller_mappings.gen.cpp", controller_databases, - run_in_subprocess(input_builders.make_default_controller_mappings), + env.Run(input_builders.make_default_controller_mappings, "Generating default controller mappings."), ) env.add_source_files(env.core_sources, "*.cpp") diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt index 7b5abdd61b..2a3cb23202 100644 --- a/core/input/gamecontrollerdb.txt +++ b/core/input/gamecontrollerdb.txt @@ -8,6 +8,7 @@ 03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, @@ -35,6 +36,7 @@ 03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000031000000000000,8BitDo Wireless Adapter,a: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, +03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, 03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, 030000008f0e00001200000000000000,Acme GA-02,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, @@ -52,6 +54,7 @@ 03000000d6200000e557000000000000,Batarang,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows, 030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000002a79000000000000,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:Windows, 03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000bc2000000055000000000000,Betop BFM Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, @@ -83,6 +86,8 @@ 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, 030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, 03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,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:Windows, +030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,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, 03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, @@ -98,8 +103,10 @@ 03000000ac0500003d03000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00000102000000007801,GameStop Xbox 360 Wired 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, 030000009b2800003200000000000000,GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, 030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, @@ -157,6 +164,7 @@ 030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,lefttrigger:b6,righttrigger:b7,platform:Windows, 03000000380700006652000000000000,Mad Catz C.T.R.L.R,a: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, @@ -183,8 +191,11 @@ 03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows, 03000000380700006382000000000000,MLG GamePad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c62400002a89000000000000,MOGA XP5-A Plus,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:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400002b89000000000000,MOGA XP5-A 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, +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, 030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows, 03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, 03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, @@ -197,6 +208,7 @@ 030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, 03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, 03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000008f0e00000300000000000000,Piranha xtreme,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, 030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 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, @@ -232,8 +244,11 @@ 03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000321500000204000000000000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000321500000104000000000000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b13,start:b9,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:a5,lefttrigger:a3,righttrigger:a4, 03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000321500000011000000000000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +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, 030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000000d0f00006a00000000000000,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:Windows, 030000000d0f00006b00000000000000,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:Windows, @@ -248,6 +263,7 @@ 0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, 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(1/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, +030000006b140000130d000000000000,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:Windows, 030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -275,16 +291,19 @@ 03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, 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, 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, 03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,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:a4,start:b5,x:b0,y:b1,platform:Windows, 03000000d620000011a7000000000000,Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +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, 030000004f04000007d0000000000000,T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000004f0400000ab1000000000000,T.16000M,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, 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, 030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, 030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ed0000000000000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 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, 03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, @@ -306,6 +325,7 @@ 03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, 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, 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, 03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, @@ -315,28 +335,39 @@ 03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, -030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, # Mac OS X 030000008f0e00000300000009010000,2In1 USB Joystick,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +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 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000190000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, 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, +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, 030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 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, @@ -378,11 +409,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X, 03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, +03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, 030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000008f0e00000300000000000000,Piranha xtreme,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, 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, @@ -397,12 +432,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000321500000104000000010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000321500000011000000010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 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, 03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X, 03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X, @@ -418,18 +455,22 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, 03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, 03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X, +030000004f0400000ed0000000020000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, 030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X, 03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X, 030000006f0e00000302000025040000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000702000003060000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, 050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, 030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, @@ -439,8 +480,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, # Linux +03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 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, @@ -465,8 +508,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, 03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, 030000005e0400008e02000020010000,8BitDo Wireless Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c82d00000031000011010000,8BitDo Wireless Adapter,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, +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, 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, 05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, 05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, @@ -475,10 +520,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux, 05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide: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, 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, 03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, +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, 03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, 03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, 03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, @@ -513,22 +560,27 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f00006a00000011010000,HORI CO. LTD. 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 CO. LTD. 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, 030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.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: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, 03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +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, 030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, 030000000d0f00006e00000011010000,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:Linux, 030000000d0f00006600000011010000,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:Linux, 030000000d0f0000ee00000011010000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 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,idroid:con,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 PCU#0 Gamepad Interface,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 I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux, 0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000011010000,Ipega PG-9099 - Bluetooth Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,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, 03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, 03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, @@ -567,7 +619,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b: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, -03000000790000004318000010010000,Mayflash 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, +03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, 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, @@ -588,14 +640,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, 05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, 05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +03000000c62400002b89000011010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c62400002a89000000010000,MOGA XP5-A 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, 03000000250900006688000000010000,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:Linux, +030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux, 060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, -050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,platform:Linux, -030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,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, 050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, 05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, @@ -603,19 +658,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, 05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, 03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, +19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux, 030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, 05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, 05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, 03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux, +03000000790000001c18000011010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,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, 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, +030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,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: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, 030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, 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, 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 Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,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, @@ -640,18 +705,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000c01100000140000011010000,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:Linux, 050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 050000004c050000c405000000810000,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, +050000004c050000c405000001800000,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, 050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, 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, 030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, 030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000321500000104000011010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -662,11 +730,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux, 0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, 030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, -03000000a30600001005000000010000,Saitek Saitek P150,platform:Linux,a:b0,b:b1,y:b4,x:b3,leftshoulder:b7,rightshoulder:b2,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,lefttrigger:b6,righttrigger:b5, 03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, 03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, 03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, @@ -674,6 +742,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, 03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600001005000000010000,Saitek Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux, 03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux, 03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux, 03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, @@ -687,7 +756,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000de2800000211000001000000,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: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,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,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,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,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, 03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, 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:Linux, @@ -695,9 +766,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 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, 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 for USB,a:b0,b:b2,x:b1,y:b3,back:b7,start:b8,leftshoulder:b6,rightshoulder:b9,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Linux, +030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux, 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, 03000000457500002211000010010000,SZMY-POWER CO. LTD. 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, @@ -705,7 +777,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, 030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, 030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,x:b3,y:b5,back:b11,start:b1,leftstick:b10,rightstick:b0,leftshoulder:b6,rightshoulder:b8,leftx:a0,lefty:a1,lefttrigger:b7,righttrigger:b9,platform:Linux, +030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux, 030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux, 030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -722,8 +795,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, 03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, 030000006f0e00000302000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00000702000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, 03000000791d00000103000010010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +050000000d0f0000f600000001000000,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000014010000,X360 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, 030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -735,44 +810,70 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),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, 030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000005e040000ea02000000000000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000ac0500005b05000010010000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, 03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux, xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, -030000005e0400008e02000000010000,xbox360 Wireless EasySMX,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, -030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, # Android +05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +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, +05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +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, +05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android, +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, 05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,platform:Android, 64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder: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, 37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000014720000df7f3f00,NVIDIA Controller v01.04,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, 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, +030000004c050000cc09000000006800,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, 050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, 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, +050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, +30306539356238653637313730656134,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, 050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, 050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, 34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, -7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android, +050000001727000044310000ffff3f00,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, # iOS 05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, diff --git a/core/input/input.h b/core/input/input.h index 91e3b83b95..775663503b 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -255,7 +255,7 @@ protected: public: void set_mouse_mode(MouseMode p_mode); MouseMode get_mouse_mode() const; - void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; + void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; static Input *get_singleton(); diff --git a/core/input/input_event.h b/core/input/input_event.h index dd1cc11982..815ba5ae80 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -266,7 +266,7 @@ protected: public: void set_pressed(bool p_pressed); - virtual bool is_pressed() const; + virtual bool is_pressed() const override; void set_keycode(uint32_t p_keycode); uint32_t get_keycode() const; @@ -278,17 +278,17 @@ public: uint32_t get_unicode() const; void set_echo(bool p_enable); - virtual bool is_echo() const; + virtual bool is_echo() const override; uint32_t get_keycode_with_modifiers() const; uint32_t get_physical_keycode_with_modifiers() const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; + virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; - virtual bool is_action_type() const { return true; } + virtual bool is_action_type() const override { return true; } - virtual String as_text() const; + virtual String as_text() const override; InputEventKey() {} }; @@ -336,16 +336,16 @@ public: int get_button_index() const; void set_pressed(bool p_pressed); - virtual bool is_pressed() const; + virtual bool is_pressed() const override; void set_doubleclick(bool p_doubleclick); bool is_doubleclick() const; - virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; + virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; - virtual bool is_action_type() const { return true; } - virtual String as_text() const; + virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; InputEventMouseButton() {} }; @@ -374,10 +374,10 @@ public: void set_speed(const Vector2 &p_speed); Vector2 get_speed() const; - virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual String as_text() const; + virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual String as_text() const override; - virtual bool accumulate(const Ref<InputEvent> &p_event); + virtual bool accumulate(const Ref<InputEvent> &p_event) override; InputEventMouseMotion() {} }; @@ -397,12 +397,12 @@ public: void set_axis_value(float p_value); float get_axis_value() const; - virtual bool is_pressed() const; + virtual bool is_pressed() const override; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; - virtual bool is_action_type() const { return true; } - virtual String as_text() const; + virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; InputEventJoypadMotion() {} }; @@ -421,16 +421,16 @@ public: int get_button_index() const; void set_pressed(bool p_pressed); - virtual bool is_pressed() const; + virtual bool is_pressed() const override; void set_pressure(float p_pressure); float get_pressure() const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; + virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; - virtual bool is_action_type() const { return true; } - virtual String as_text() const; + virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; InputEventJoypadButton() {} }; @@ -452,10 +452,10 @@ public: Vector2 get_position() const; void set_pressed(bool p_pressed); - virtual bool is_pressed() const; + virtual bool is_pressed() const override; - virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual String as_text() const; + virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual String as_text() const override; InputEventScreenTouch() {} }; @@ -483,8 +483,8 @@ public: void set_speed(const Vector2 &p_speed); Vector2 get_speed() const; - virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual String as_text() const; + virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual String as_text() const override; InputEventScreenDrag() {} }; @@ -504,18 +504,18 @@ public: StringName get_action() const; void set_pressed(bool p_pressed); - virtual bool is_pressed() const; + virtual bool is_pressed() const override; void set_strength(float p_strength); float get_strength() const; virtual bool is_action(const StringName &p_action) const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; - virtual bool is_action_type() const { return true; } - virtual String as_text() const; + virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; + virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; InputEventAction() {} }; @@ -544,8 +544,8 @@ public: void set_factor(real_t p_factor); real_t get_factor() const; - virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual String as_text() const; + virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual String as_text() const override; InputEventMagnifyGesture() {} }; @@ -561,8 +561,8 @@ public: void set_delta(const Vector2 &p_delta); Vector2 get_delta() const; - virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual String as_text() const; + virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual String as_text() const override; InputEventPanGesture() {} }; @@ -607,7 +607,7 @@ public: void set_controller_value(const int p_controller_value); int get_controller_value() const; - virtual String as_text() const; + virtual String as_text() const override; InputEventMIDI() {} }; diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 40debae9e5..46e45500bf 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -451,7 +451,7 @@ Error HTTPClient::poll() { } } - // This is a HEAD request, we wont receive anything. + // This is a HEAD request, we won't receive anything. if (head_request) { body_size = 0; body_left = 0; diff --git a/core/io/json.cpp b/core/io/json.cpp index 1c603865ad..8bdd6385cb 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -265,7 +265,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to if (p_str[index] == '-' || (p_str[index] >= '0' && p_str[index] <= '9')) { //a number const CharType *rptr; - double number = String::to_double(&p_str[index], &rptr); + double number = String::to_float(&p_str[index], &rptr); index += (rptr - &p_str[index]); r_token.type = TK_NUMBER; r_token.value = number; @@ -371,6 +371,7 @@ Error JSON::_parse_array(Array &array, const CharType *p_str, int &index, int p_ need_comma = true; } + r_err_str = "Expected ']'"; return ERR_PARSE_ERROR; } @@ -433,6 +434,7 @@ Error JSON::_parse_object(Dictionary &object, const CharType *p_str, int &index, } } + r_err_str = "Expected '}'"; return ERR_PARSE_ERROR; } diff --git a/core/io/logger.cpp b/core/io/logger.cpp index ef78b1194e..886e5695b1 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -152,7 +152,7 @@ void RotatedFileLogger::rotate_file() { char timestamp[21]; OS::Date date = OS::get_singleton()->get_date(); OS::Time time = OS::get_singleton()->get_time(); - sprintf(timestamp, "-%04d-%02d-%02d-%02d-%02d-%02d", date.year, date.month, date.day, time.hour, time.min, time.sec); + sprintf(timestamp, "_%04d-%02d-%02d_%02d-%02d-%02d", date.year, date.month, date.day, time.hour, time.min, time.sec); String backup_name = base_path.get_basename() + timestamp; if (base_path.get_extension() != String()) { diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index f0ba50087f..92cdbc4151 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -90,11 +90,11 @@ protected: static void _bind_methods(); public: - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - virtual int get_max_packet_size() const; + virtual int get_max_packet_size() const override; void set_stream_peer(const Ref<StreamPeer> &p_peer); Ref<StreamPeer> get_stream_peer() const; diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index 862fca96fc..e633a56d54 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -31,12 +31,14 @@ #include "packet_peer_udp.h" #include "core/io/ip.h" +#include "core/io/udp_server.h" void PacketPeerUDP::set_blocking_mode(bool p_enable) { blocking = p_enable; } void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) { + ERR_FAIL_COND(udp_server); broadcast = p_enabled; if (_sock.is_valid() && _sock->is_open()) { _sock->set_broadcasting_enabled(p_enabled); @@ -44,6 +46,7 @@ void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) { } Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) { + ERR_FAIL_COND_V(udp_server, ERR_LOCKED); ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(!p_multi_address.is_valid(), ERR_INVALID_PARAMETER); @@ -58,6 +61,7 @@ Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_i } Error PacketPeerUDP::leave_multicast_group(IP_Address p_multi_address, String p_if_name) { + ERR_FAIL_COND_V(udp_server, ERR_LOCKED); ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(!_sock->is_open(), ERR_UNCONFIGURED); return _sock->leave_multicast_group(p_multi_address, p_if_name); @@ -130,7 +134,7 @@ Error PacketPeerUDP::put_packet(const uint8_t *p_buffer, int p_buffer_size) { } do { - if (connected) { + if (connected && !udp_server) { err = _sock->send(p_buffer, p_buffer_size, sent); } else { err = _sock->sendto(p_buffer, p_buffer_size, sent, peer_addr, peer_port); @@ -186,26 +190,25 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_ return OK; } -Error PacketPeerUDP::connect_socket(Ref<NetSocket> p_sock) { - Error err; - int read = 0; - uint16_t r_port; - IP_Address r_ip; - - err = p_sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, r_ip, r_port, true); - ERR_FAIL_COND_V(err != OK, err); - err = p_sock->connect_to_host(r_ip, r_port); - ERR_FAIL_COND_V(err != OK, err); +Error PacketPeerUDP::connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *p_server) { + udp_server = p_server; + connected = true; _sock = p_sock; - peer_addr = r_ip; - peer_port = r_port; + peer_addr = p_ip; + peer_port = p_port; packet_ip = peer_addr; packet_port = peer_port; - connected = true; return OK; } +void PacketPeerUDP::disconnect_shared_socket() { + udp_server = nullptr; + _sock = Ref<NetSocket>(NetSocket::create()); + close(); +} + Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) { + ERR_FAIL_COND_V(udp_server, ERR_LOCKED); ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER); @@ -243,7 +246,11 @@ bool PacketPeerUDP::is_connected_to_host() const { } void PacketPeerUDP::close() { - if (_sock.is_valid()) { + if (udp_server) { + udp_server->remove_peer(peer_addr, peer_port); + udp_server = nullptr; + _sock = Ref<NetSocket>(NetSocket::create()); + } else if (_sock.is_valid()) { _sock->close(); } rb.resize(16); @@ -262,6 +269,9 @@ Error PacketPeerUDP::_poll() { if (!_sock->is_open()) { return FAILED; } + if (udp_server) { + return OK; // Handled by UDPServer. + } Error err; int read; @@ -284,24 +294,29 @@ Error PacketPeerUDP::_poll() { return FAILED; } - if (rb.space_left() < read + 24) { + err = store_packet(ip, port, recv_buffer, read); #ifdef TOOLS_ENABLED + if (err != OK) { WARN_PRINT("Buffer full, dropping packets!"); -#endif - continue; } - - uint32_t port32 = port; - rb.write(ip.get_ipv6(), 16); - rb.write((uint8_t *)&port32, 4); - rb.write((uint8_t *)&read, 4); - rb.write(recv_buffer, read); - ++queue_count; +#endif } return OK; } +Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size) { + if (rb.space_left() < p_buf_size + 24) { + return ERR_OUT_OF_MEMORY; + } + rb.write(p_ip.get_ipv6(), 16); + rb.write((uint8_t *)&p_port, 4); + rb.write((uint8_t *)&p_buf_size, 4); + rb.write(p_buf, p_buf_size); + ++queue_count; + return OK; +} + bool PacketPeerUDP::is_listening() const { return _sock.is_valid() && _sock->is_open(); } diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index 23fc5460a6..9a44a1ebea 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -35,6 +35,8 @@ #include "core/io/net_socket.h" #include "core/io/packet_peer.h" +class UDPServer; + class PacketPeerUDP : public PacketPeer { GDCLASS(PacketPeerUDP, PacketPeer); @@ -55,6 +57,7 @@ protected: bool connected = false; bool blocking = true; bool broadcast = false; + UDPServer *udp_server = nullptr; Ref<NetSocket> _sock; static void _bind_methods(); @@ -72,7 +75,9 @@ public: Error wait(); bool is_listening() const; - Error connect_socket(Ref<NetSocket> p_sock); // Used by UDPServer + Error connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer + void disconnect_shared_socket(); // Used by UDPServer + Error store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer Error connect_to_host(const IP_Address &p_host, int p_port); bool is_connected_to_host() const; @@ -80,10 +85,10 @@ public: int get_packet_port() const; void set_dest_address(const IP_Address &p_address, int p_port); - Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - int get_available_packet_count() const; - int get_max_packet_size() const; + Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; + int get_available_packet_count() const override; + int get_max_packet_size() const override; void set_broadcast_enabled(bool p_enabled); Error join_multicast_group(IP_Address p_multi_address, String p_if_name); Error leave_multicast_group(IP_Address p_multi_address, String p_if_name); diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index f9d2c9067c..8b3a1f6637 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -865,7 +865,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem bool near_match = false; for (int i = 0; i < res_remaps.size(); i++) { - int split = res_remaps[i].find_last(":"); + int split = res_remaps[i].rfind(":"); if (split == -1) { continue; } @@ -999,6 +999,9 @@ void ResourceLoader::load_translation_remaps() { void ResourceLoader::clear_translation_remaps() { translation_remaps.clear(); + while (remapped_list.first() != nullptr) { + remapped_list.remove(remapped_list.first()); + } } void ResourceLoader::load_path_remaps() { diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index ec0b989ed8..39097a57f2 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -102,13 +102,13 @@ protected: static void _bind_methods(); public: - Error put_data(const uint8_t *p_data, int p_bytes); - Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); + Error put_data(const uint8_t *p_data, int p_bytes) override; + Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override; - Error get_data(uint8_t *p_buffer, int p_bytes); - Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); + Error get_data(uint8_t *p_buffer, int p_bytes) override; + Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override; - virtual int get_available_bytes() const; + virtual int get_available_bytes() const override; void seek(int p_pos); int get_size() const; diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h index ab98d494d6..45205866b4 100644 --- a/core/io/stream_peer_tcp.h +++ b/core/io/stream_peer_tcp.h @@ -72,7 +72,7 @@ public: uint16_t get_connected_port() const; void disconnect_from_host(); - int get_available_bytes() const; + int get_available_bytes() const override; Status get_status(); void set_no_delay(bool p_enabled); @@ -81,10 +81,10 @@ public: Error poll(NetSocket::PollType p_type, int timeout = 0); // Read/Write from StreamPeer - Error put_data(const uint8_t *p_data, int p_bytes); - Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); - Error get_data(uint8_t *p_buffer, int p_bytes); - Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); + Error put_data(const uint8_t *p_data, int p_bytes) override; + Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override; + Error get_data(uint8_t *p_buffer, int p_bytes) override; + Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override; StreamPeerTCP(); ~StreamPeerTCP(); diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 0e0a948953..d8ddb213c3 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -32,30 +32,38 @@ #include "core/os/file_access.h" #include "core/translation.h" +#include "core/translation_po.h" RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { enum Status { - STATUS_NONE, STATUS_READING_ID, STATUS_READING_STRING, + STATUS_READING_CONTEXT, + STATUS_READING_PLURAL, }; Status status = STATUS_NONE; String msg_id; String msg_str; + String msg_context; + Vector<String> msgs_plural; String config; if (r_error) { *r_error = ERR_FILE_CORRUPT; } - Ref<Translation> translation = Ref<Translation>(memnew(Translation)); + Ref<TranslationPO> translation = Ref<TranslationPO>(memnew(TranslationPO)); int line = 1; + int plural_forms = 0; + int plural_index = -1; + bool entered_context = false; bool skip_this = false; bool skip_next = false; bool is_eof = false; + const String path = f->get_path(); while (!is_eof) { String l = f->get_line().strip_edges(); @@ -63,40 +71,107 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { // If we reached last line and it's not a content line, break, otherwise let processing that last loop if (is_eof && l.empty()) { - if (status == STATUS_READING_ID) { + if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || (status == STATUS_READING_PLURAL && plural_index != plural_forms - 1)) { memdelete(f); - ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: "); + ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading PO file at: " + path + ":" + itos(line)); } else { break; } } - if (l.begins_with("msgid")) { + if (l.begins_with("msgctxt")) { + if (status != STATUS_READING_STRING && status != STATUS_READING_PLURAL) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line)); + } + + // In PO file, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read + // and set "entered_context" to true to prevent adding twice. + if (!skip_this && msg_id != "") { + if (status == STATUS_READING_STRING) { + translation->add_message(msg_id, msg_str, msg_context); + } else if (status == STATUS_READING_PLURAL) { + if (plural_index != plural_forms - 1) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); + } + translation->add_plural_message(msg_id, msgs_plural, msg_context); + } + } + msg_context = ""; + l = l.substr(7, l.length()).strip_edges(); + status = STATUS_READING_CONTEXT; + entered_context = true; + } + + if (l.begins_with("msgid_plural")) { + if (plural_forms == 0) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "PO file uses 'msgid_plural' but 'Plural-Forms' is invalid or missing in header: " + path + ":" + itos(line)); + } else if (status != STATUS_READING_ID) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line)); + } + // We don't record the message in "msgid_plural" itself as tr_n(), TTRN(), RTRN() interfaces provide the plural string already. + // We just have to reset variables related to plurals for "msgstr[]" later on. + l = l.substr(12, l.length()).strip_edges(); + plural_index = -1; + msgs_plural.clear(); + msgs_plural.resize(plural_forms); + status = STATUS_READING_PLURAL; + } else if (l.begins_with("msgid")) { if (status == STATUS_READING_ID) { memdelete(f); - ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: "); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line)); } if (msg_id != "") { - if (!skip_this) { - translation->add_message(msg_id, msg_str); + if (!skip_this && !entered_context) { + if (status == STATUS_READING_STRING) { + translation->add_message(msg_id, msg_str, msg_context); + } else if (status == STATUS_READING_PLURAL) { + if (plural_index != plural_forms - 1) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); + } + translation->add_plural_message(msg_id, msgs_plural, msg_context); + } } } else if (config == "") { config = msg_str; + // Record plural rule. + int p_start = config.find("Plural-Forms"); + if (p_start != -1) { + int p_end = config.find("\n", p_start); + translation->set_plural_rule(config.substr(p_start, p_end - p_start)); + plural_forms = translation->get_plural_forms(); + } } l = l.substr(5, l.length()).strip_edges(); status = STATUS_READING_ID; + // If we did not encounter msgctxt, we reset context to empty to reset it. + if (!entered_context) { + msg_context = ""; + } msg_id = ""; msg_str = ""; skip_this = skip_next; skip_next = false; + entered_context = false; } - if (l.begins_with("msgstr")) { + if (l.begins_with("msgstr[")) { + if (status != STATUS_READING_PLURAL) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line)); + } + plural_index++; // Increment to add to the next slot in vector msgs_plural. + l = l.substr(9, l.length()).strip_edges(); + } else if (l.begins_with("msgstr")) { if (status != STATUS_READING_ID) { memdelete(f); - ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: "); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line)); } l = l.substr(6, l.length()).strip_edges(); @@ -108,10 +183,13 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { skip_next = true; } line++; - continue; //nothing to read or comment + continue; // Nothing to read or comment. } - ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), f->get_path() + ":" + itos(line) + " Invalid line '" + l + "' while parsing: "); + if (!l.begins_with("\"") || status == STATUS_NONE) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line)); + } l = l.substr(1, l.length()); // Find final quote, ignoring escaped ones (\"). @@ -133,34 +211,49 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { escape_next = false; } - ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), f->get_path() + ":" + itos(line) + ": Expected '\"' at end of message while parsing file."); + if (end_pos == -1) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line)); + } l = l.substr(0, end_pos); l = l.c_unescape(); if (status == STATUS_READING_ID) { msg_id += l; - } else { + } else if (status == STATUS_READING_STRING) { msg_str += l; + } else if (status == STATUS_READING_CONTEXT) { + msg_context += l; + } else if (status == STATUS_READING_PLURAL && plural_index >= 0) { + msgs_plural.write[plural_index] = msgs_plural[plural_index] + l; } line++; } - f->close(); memdelete(f); + // Add the last set of data from last iteration. if (status == STATUS_READING_STRING) { if (msg_id != "") { if (!skip_this) { - translation->add_message(msg_id, msg_str); + translation->add_message(msg_id, msg_str, msg_context); } } else if (config == "") { config = msg_str; } + } else if (status == STATUS_READING_PLURAL) { + if (!skip_this && msg_id != "") { + if (plural_index != plural_forms - 1) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); + } + translation->add_plural_message(msg_id, msgs_plural, msg_context); + } } - ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + f->get_path() + "."); + ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + path + "."); Vector<String> configs = config.split("\n"); for (int i = 0; i < configs.size(); i++) { @@ -197,7 +290,6 @@ RES TranslationLoaderPO::load(const String &p_path, const String &p_original_pat void TranslationLoaderPO::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("po"); - //p_extensions->push_back("mo"); //mo in the future... } bool TranslationLoaderPO::handles_type(const String &p_type) const { diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp index 1d329daf8b..acd15aadc6 100644 --- a/core/io/udp_server.cpp +++ b/core/io/udp_server.cpp @@ -32,10 +32,58 @@ void UDPServer::_bind_methods() { ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &UDPServer::listen, DEFVAL("*")); + ClassDB::bind_method(D_METHOD("poll"), &UDPServer::poll); ClassDB::bind_method(D_METHOD("is_connection_available"), &UDPServer::is_connection_available); ClassDB::bind_method(D_METHOD("is_listening"), &UDPServer::is_listening); ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection); ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop); + ClassDB::bind_method(D_METHOD("set_max_pending_connections", "max_pending_connections"), &UDPServer::set_max_pending_connections); + ClassDB::bind_method(D_METHOD("get_max_pending_connections"), &UDPServer::get_max_pending_connections); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_pending_connections", PROPERTY_HINT_RANGE, "0,256,1"), "set_max_pending_connections", "get_max_pending_connections"); +} + +Error UDPServer::poll() { + ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); + if (!_sock->is_open()) { + return ERR_UNCONFIGURED; + } + Error err; + int read; + IP_Address ip; + uint16_t port; + while (true) { + err = _sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, ip, port); + if (err != OK) { + if (err == ERR_BUSY) { + break; + } + return FAILED; + } + Peer p; + p.ip = ip; + p.port = port; + List<Peer>::Element *E = peers.find(p); + if (!E) { + E = pending.find(p); + } + if (E) { + E->get().peer->store_packet(ip, port, recv_buffer, read); + } else { + if (pending.size() >= max_pending_connections) { + // Drop connection. + continue; + } + // It's a new peer, add it to the pending list. + Peer peer; + peer.ip = ip; + peer.port = port; + peer.peer = memnew(PacketPeerUDP); + peer.peer->connect_shared_socket(_sock, ip, port, this); + peer.peer->store_packet(ip, port, recv_buffer, read); + pending.push_back(peer); + } + } + return OK; } Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) { @@ -82,8 +130,24 @@ bool UDPServer::is_connection_available() const { return false; } - Error err = _sock->poll(NetSocket::POLL_TYPE_IN, 0); - return (err == OK); + return pending.size() > 0; +} + +void UDPServer::set_max_pending_connections(int p_max) { + ERR_FAIL_COND_MSG(p_max < 0, "Max pending connections value must be a positive number (0 means refuse new connections)."); + max_pending_connections = p_max; + while (p_max > pending.size()) { + List<Peer>::Element *E = pending.back(); + if (!E) { + break; + } + memdelete(E->get().peer); + pending.erase(E); + } +} + +int UDPServer::get_max_pending_connections() const { + return max_pending_connections; } Ref<PacketPeerUDP> UDPServer::take_connection() { @@ -92,11 +156,20 @@ Ref<PacketPeerUDP> UDPServer::take_connection() { return conn; } - conn = Ref<PacketPeerUDP>(memnew(PacketPeerUDP)); - conn->connect_socket(_sock); - _sock = Ref<NetSocket>(NetSocket::create()); - listen(bind_port, bind_address); - return conn; + Peer peer = pending[0]; + pending.pop_front(); + peers.push_back(peer); + return peer.peer; +} + +void UDPServer::remove_peer(IP_Address p_ip, int p_port) { + Peer peer; + peer.ip = p_ip; + peer.port = p_port; + List<Peer>::Element *E = peers.find(peer); + if (E) { + peers.erase(E); + } } void UDPServer::stop() { @@ -105,6 +178,19 @@ void UDPServer::stop() { } bind_port = 0; bind_address = IP_Address(); + List<Peer>::Element *E = peers.front(); + while (E) { + E->get().peer->disconnect_shared_socket(); + E = E->next(); + } + E = pending.front(); + while (E) { + E->get().peer->disconnect_shared_socket(); + memdelete(E->get().peer); + E = E->next(); + } + peers.clear(); + pending.clear(); } UDPServer::UDPServer() : diff --git a/core/io/udp_server.h b/core/io/udp_server.h index 90bb82b62b..3175b09b19 100644 --- a/core/io/udp_server.h +++ b/core/io/udp_server.h @@ -38,15 +38,40 @@ class UDPServer : public Reference { GDCLASS(UDPServer, Reference); protected: - static void _bind_methods(); - int bind_port; + enum { + PACKET_BUFFER_SIZE = 65536 + }; + + struct Peer { + PacketPeerUDP *peer; + IP_Address ip; + uint16_t port = 0; + + bool operator==(const Peer &p_other) const { + return (ip == p_other.ip && port == p_other.port); + } + }; + uint8_t recv_buffer[PACKET_BUFFER_SIZE]; + + int bind_port = 0; IP_Address bind_address; + + List<Peer> peers; + List<Peer> pending; + int max_pending_connections = 16; + Ref<NetSocket> _sock; + static void _bind_methods(); + public: + void remove_peer(IP_Address p_ip, int p_port); Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")); + Error poll(); bool is_listening() const; bool is_connection_available() const; + void set_max_pending_connections(int p_max); + int get_max_pending_connections() const; Ref<PacketPeerUDP> take_connection(); void stop(); diff --git a/core/list.h b/core/list.h index 6052a619fb..f850db5241 100644 --- a/core/list.h +++ b/core/list.h @@ -348,7 +348,7 @@ public: * erase an element in the list, by iterator pointing to it. Return true if it was found/erased. */ bool erase(const Element *p_I) { - if (_data) { + if (_data && p_I) { bool ret = _data->erase(p_I); if (_data->size_cache == 0) { diff --git a/core/local_vector.h b/core/local_vector.h index d97f3330dc..b0dbd22b29 100644 --- a/core/local_vector.h +++ b/core/local_vector.h @@ -73,10 +73,10 @@ public: void remove(U p_index) { ERR_FAIL_UNSIGNED_INDEX(p_index, count); + count--; for (U i = p_index; i < count; i++) { data[i] = data[i + 1]; } - count--; if (!__has_trivial_destructor(T) && !force_trivial) { data[count].~T(); } diff --git a/core/math/aabb.h b/core/math/aabb.h index 4106fbb93c..bd1f3a1a36 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -99,6 +99,10 @@ public: _FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const; _FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */ + _FORCE_INLINE_ AABB abs() const { + return AABB(Vector3(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0), position.z + MIN(size.z, 0)), size.abs()); + } + operator String() const; _FORCE_INLINE_ AABB() {} diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 22ab83f358..c154d57a13 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -278,7 +278,7 @@ Vector2 CameraMatrix::get_viewport_half_extents() const { return Vector2(res.x, res.y); } -void CameraMatrix::get_far_plane_size(real_t &r_width, real_t &r_height) const { +Vector2 CameraMatrix::get_far_plane_half_extents() const { const real_t *matrix = (const real_t *)this->matrix; ///////--- Far Plane ---/////// Plane far_plane = Plane(matrix[3] - matrix[2], @@ -303,8 +303,7 @@ void CameraMatrix::get_far_plane_size(real_t &r_width, real_t &r_height) const { Vector3 res; far_plane.intersect_3(right_plane, top_plane, &res); - r_width = res.x; - r_height = res.y; + return Vector2(res.x, res.y); } bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const { diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 49fdecae02..c5cdd98377 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -74,7 +74,7 @@ struct CameraMatrix { bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const; Vector2 get_viewport_half_extents() const; - void get_far_plane_size(real_t &r_width, real_t &r_height) const; + Vector2 get_far_plane_half_extents() const; void invert(); CameraMatrix inverse() const; diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 6421606ca2..735a30f6cc 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -1062,9 +1062,9 @@ Error Expression::_get_token(Token &r_token) { r_token.type = TK_CONSTANT; if (is_float) { - r_token.value = num.to_double(); + r_token.value = num.to_float(); } else { - r_token.value = num.to_int64(); + r_token.value = num.to_int(); } return OK; diff --git a/core/math/expression.h b/core/math/expression.h index 59a9a2f4ed..f2cfe6b1a6 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -343,7 +343,7 @@ protected: public: Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>()); - Variant execute(Array p_inputs, 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 has_execute_failed() const; String get_error_text() const; diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp index 7807ab19a7..2c19fe2085 100644 --- a/core/math/geometry_3d.cpp +++ b/core/math/geometry_3d.cpp @@ -648,7 +648,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes Vector<Vector3> vertices; - Vector3 center = p.get_any_point(); + Vector3 center = p.center(); // make a quad clockwise vertices.push_back(center - up * subplane_size + right * subplane_size); vertices.push_back(center - up * subplane_size - right * subplane_size); diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 7a9fd60e23..9f8d4da5b3 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -231,19 +231,19 @@ public: static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } - static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_weight) { + static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) { if (is_equal_approx(p_from, p_to)) { return p_from; } - double x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0, 1.0); - return x * x * (3.0 - 2.0 * x); + double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0); + return s * s * (3.0 - 2.0 * s); } - static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_weight) { + static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) { if (is_equal_approx(p_from, p_to)) { return p_from; } - float x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f); - return x * x * (3.0f - 2.0f * x); + float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); + return s * s * (3.0f - 2.0f * s); } static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; } static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; } diff --git a/core/math/plane.cpp b/core/math/plane.cpp index df37ceb0e5..4200484c59 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -52,10 +52,6 @@ Plane Plane::normalized() const { return p; } -Vector3 Plane::get_any_point() const { - return get_normal() * d; -} - Vector3 Plane::get_any_perpendicular_normal() const { static const Vector3 p1 = Vector3(1, 0, 0); static const Vector3 p2 = Vector3(0, 1, 0); diff --git a/core/math/plane.h b/core/math/plane.h index 9a3e5a485f..70a6111edd 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -47,7 +47,6 @@ public: /* Plane-Point operations */ _FORCE_INLINE_ Vector3 center() const { return normal * d; } - Vector3 get_any_point() const; Vector3 get_any_perpendicular_normal() const; _FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h index 775e17fdb5..6061366ab3 100644 --- a/core/oa_hash_map.h +++ b/core/oa_hash_map.h @@ -48,7 +48,7 @@ * * Only used keys and values are constructed. For free positions there's space * in the arrays for each, but that memory is kept uninitialized. - * + * * The assignment operator copy the pairs from one map to the other. */ template <class TKey, class TValue, diff --git a/core/object.cpp b/core/object.cpp index 8abea9ca7e..67c605c39b 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -675,89 +675,11 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call StringName method = *p_args[0]; - MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1); + MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1, true); return Variant(); } -#ifdef DEBUG_ENABLED -static void _test_call_error(const StringName &p_func, const Callable::CallError &error) { - switch (error.error) { - case Callable::CallError::CALL_OK: - case Callable::CallError::CALL_ERROR_INVALID_METHOD: - break; - case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(Variant::Type(error.expected)) + "."); - break; - } - case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + "."); - break; - } - case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + "."); - break; - } - case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: - break; - } -} -#else - -#define _test_call_error(m_str, m_err) - -#endif - -void Object::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (p_method == CoreStringNames::get_singleton()->_free) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(Object::cast_to<Reference>(this), "Can't 'free' a reference."); - - ERR_FAIL_COND_MSG(_lock_index.get() > 1, "Object is locked and can't be freed."); -#endif - - //must be here, must be before everything, - memdelete(this); - return; - } - - //Variant ret; - OBJ_DEBUG_LOCK - - Callable::CallError error; - - if (script_instance) { - script_instance->call_multilevel(p_method, p_args, p_argcount); - //_test_call_error(p_method,error); - } - - MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - - if (method) { - method->call(this, p_args, p_argcount, error); - _test_call_error(p_method, error); - } -} - -void Object::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - - Callable::CallError error; - OBJ_DEBUG_LOCK - - if (method) { - method->call(this, p_args, p_argcount, error); - _test_call_error(p_method, error); - } - - //Variant ret; - - if (script_instance) { - script_instance->call_multilevel_reversed(p_method, p_args, p_argcount); - //_test_call_error(p_method,error); - } -} - bool Object::has_method(const StringName &p_method) const { if (p_method == CoreStringNames::get_singleton()->_free) { return true; @@ -820,21 +742,6 @@ Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) { return ret; } -void Object::call_multilevel(const StringName &p_name, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - //Callable::CallError error; - call_multilevel(p_name, argptr, argc); -} - Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_OK; @@ -1525,12 +1432,22 @@ void Object::initialize_class() { initialized = true; } -StringName Object::tr(const StringName &p_message) const { +String Object::tr(const StringName &p_message, const StringName &p_context) const { if (!_can_translate || !TranslationServer::get_singleton()) { return p_message; } + return TranslationServer::get_singleton()->translate(p_message, p_context); +} - return TranslationServer::get_singleton()->translate(p_message); +String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + if (!_can_translate || !TranslationServer::get_singleton()) { + // Return message based on English plural rule if translation is not possible. + if (p_n == 1) { + return p_message; + } + return p_message_plural; + } + return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context); } void Object::_clear_internal_resource_paths(const Variant &p_var) { @@ -1671,7 +1588,8 @@ void Object::_bind_methods() { ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation); ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages); - ClassDB::bind_method(D_METHOD("tr", "message"), &Object::tr); + ClassDB::bind_method(D_METHOD("tr", "message", "context"), &Object::tr, DEFVAL("")); + ClassDB::bind_method(D_METHOD("tr_n", "message", "plural_message", "n", "context"), &Object::tr_n, DEFVAL("")); ClassDB::bind_method(D_METHOD("is_queued_for_deletion"), &Object::is_queued_for_deletion); diff --git a/core/object.h b/core/object.h index 5b46a0f93a..f9a12da8f6 100644 --- a/core/object.h +++ b/core/object.h @@ -250,142 +250,142 @@ public: \ \ private: -#define GDCLASS(m_class, m_inherits) \ -private: \ - void operator=(const m_class &p_rval) {} \ - mutable StringName _class_name; \ - friend class ClassDB; \ - \ -public: \ - virtual String get_class() const { \ - return String(#m_class); \ - } \ - virtual const StringName *_get_class_namev() const { \ - if (!_class_name) { \ - _class_name = get_class_static(); \ - } \ - return &_class_name; \ - } \ - static _FORCE_INLINE_ void *get_class_ptr_static() { \ - static int ptr; \ - return &ptr; \ - } \ - static _FORCE_INLINE_ String get_class_static() { \ - return String(#m_class); \ - } \ - static _FORCE_INLINE_ String get_parent_class_static() { \ - return m_inherits::get_class_static(); \ - } \ - static void get_inheritance_list_static(List<String> *p_inheritance_list) { \ - m_inherits::get_inheritance_list_static(p_inheritance_list); \ - p_inheritance_list->push_back(String(#m_class)); \ - } \ - static String get_category_static() { \ - String category = m_inherits::get_category_static(); \ - if (_get_category != m_inherits::_get_category) { \ - if (category != "") { \ - category += "/"; \ - } \ - category += _get_category(); \ - } \ - return category; \ - } \ - static String inherits_static() { \ - return String(#m_inherits); \ - } \ - virtual bool is_class(const String &p_class) const { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \ - virtual bool is_class_ptr(void *p_ptr) const { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \ - \ - static void get_valid_parents_static(List<String> *p_parents) { \ - if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \ - m_class::_get_valid_parents_static(p_parents); \ - } \ - \ - m_inherits::get_valid_parents_static(p_parents); \ - } \ - \ -protected: \ - _FORCE_INLINE_ static void (*_get_bind_methods())() { \ - return &m_class::_bind_methods; \ - } \ - \ -public: \ - static void initialize_class() { \ - static bool initialized = false; \ - if (initialized) { \ - return; \ - } \ - m_inherits::initialize_class(); \ - ClassDB::_add_class<m_class>(); \ - if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ - _bind_methods(); \ - } \ - initialized = true; \ - } \ - \ -protected: \ - virtual void _initialize_classv() { \ - initialize_class(); \ - } \ - _FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \ - return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \ - } \ - virtual bool _getv(const StringName &p_name, Variant &r_ret) const { \ - if (m_class::_get_get() != m_inherits::_get_get()) { \ - if (_get(p_name, r_ret)) { \ - return true; \ - } \ - } \ - return m_inherits::_getv(p_name, r_ret); \ - } \ - _FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \ - return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \ - } \ - virtual bool _setv(const StringName &p_name, const Variant &p_property) { \ - if (m_inherits::_setv(p_name, p_property)) { \ - return true; \ - } \ - if (m_class::_get_set() != m_inherits::_get_set()) { \ - return _set(p_name, p_property); \ - } \ - return false; \ - } \ - _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> * p_list) const { \ - return (void (Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \ - } \ - virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const { \ - if (!p_reversed) { \ - m_inherits::_get_property_listv(p_list, p_reversed); \ - } \ - p_list->push_back(PropertyInfo(Variant::NIL, get_class_static(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); \ - if (!_is_gpl_reversed()) { \ - ClassDB::get_property_list(#m_class, p_list, true, this); \ - } \ - if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ - _get_property_list(p_list); \ - } \ - if (_is_gpl_reversed()) { \ - ClassDB::get_property_list(#m_class, p_list, true, this); \ - } \ - if (p_reversed) { \ - m_inherits::_get_property_listv(p_list, p_reversed); \ - } \ - } \ - _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \ - return (void (Object::*)(int)) & m_class::_notification; \ - } \ - virtual void _notificationv(int p_notification, bool p_reversed) { \ - if (!p_reversed) { \ - m_inherits::_notificationv(p_notification, p_reversed); \ - } \ - if (m_class::_get_notification() != m_inherits::_get_notification()) { \ - _notification(p_notification); \ - } \ - if (p_reversed) { \ - m_inherits::_notificationv(p_notification, p_reversed); \ - } \ - } \ - \ +#define GDCLASS(m_class, m_inherits) \ +private: \ + void operator=(const m_class &p_rval) {} \ + mutable StringName _class_name; \ + friend class ClassDB; \ + \ +public: \ + virtual String get_class() const override { \ + return String(#m_class); \ + } \ + virtual const StringName *_get_class_namev() const override { \ + if (!_class_name) { \ + _class_name = get_class_static(); \ + } \ + return &_class_name; \ + } \ + static _FORCE_INLINE_ void *get_class_ptr_static() { \ + static int ptr; \ + return &ptr; \ + } \ + static _FORCE_INLINE_ String get_class_static() { \ + return String(#m_class); \ + } \ + static _FORCE_INLINE_ String get_parent_class_static() { \ + return m_inherits::get_class_static(); \ + } \ + static void get_inheritance_list_static(List<String> *p_inheritance_list) { \ + m_inherits::get_inheritance_list_static(p_inheritance_list); \ + p_inheritance_list->push_back(String(#m_class)); \ + } \ + static String get_category_static() { \ + String category = m_inherits::get_category_static(); \ + if (_get_category != m_inherits::_get_category) { \ + if (category != "") { \ + category += "/"; \ + } \ + category += _get_category(); \ + } \ + return category; \ + } \ + static String inherits_static() { \ + return String(#m_inherits); \ + } \ + virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \ + virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \ + \ + static void get_valid_parents_static(List<String> *p_parents) { \ + if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \ + m_class::_get_valid_parents_static(p_parents); \ + } \ + \ + m_inherits::get_valid_parents_static(p_parents); \ + } \ + \ +protected: \ + _FORCE_INLINE_ static void (*_get_bind_methods())() { \ + return &m_class::_bind_methods; \ + } \ + \ +public: \ + static void initialize_class() { \ + static bool initialized = false; \ + if (initialized) { \ + return; \ + } \ + m_inherits::initialize_class(); \ + ClassDB::_add_class<m_class>(); \ + if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ + _bind_methods(); \ + } \ + initialized = true; \ + } \ + \ +protected: \ + virtual void _initialize_classv() override { \ + initialize_class(); \ + } \ + _FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \ + return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \ + } \ + virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \ + if (m_class::_get_get() != m_inherits::_get_get()) { \ + if (_get(p_name, r_ret)) { \ + return true; \ + } \ + } \ + return m_inherits::_getv(p_name, r_ret); \ + } \ + _FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \ + return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \ + } \ + virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \ + if (m_inherits::_setv(p_name, p_property)) { \ + return true; \ + } \ + if (m_class::_get_set() != m_inherits::_get_set()) { \ + return _set(p_name, p_property); \ + } \ + return false; \ + } \ + _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> * p_list) const { \ + return (void (Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \ + } \ + virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const override { \ + if (!p_reversed) { \ + m_inherits::_get_property_listv(p_list, p_reversed); \ + } \ + p_list->push_back(PropertyInfo(Variant::NIL, get_class_static(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); \ + if (!_is_gpl_reversed()) { \ + ClassDB::get_property_list(#m_class, p_list, true, this); \ + } \ + if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ + _get_property_list(p_list); \ + } \ + if (_is_gpl_reversed()) { \ + ClassDB::get_property_list(#m_class, p_list, true, this); \ + } \ + if (p_reversed) { \ + m_inherits::_get_property_listv(p_list, p_reversed); \ + } \ + } \ + _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \ + return (void (Object::*)(int)) & m_class::_notification; \ + } \ + virtual void _notificationv(int p_notification, bool p_reversed) override { \ + if (!p_reversed) { \ + m_inherits::_notificationv(p_notification, p_reversed); \ + } \ + if (m_class::_get_notification() != m_inherits::_get_notification()) { \ + _notification(p_notification); \ + } \ + if (p_reversed) { \ + m_inherits::_notificationv(p_notification, p_reversed); \ + } \ + } \ + \ private: #define OBJ_CATEGORY(m_category) \ @@ -394,10 +394,10 @@ protected: \ \ private: -#define OBJ_SAVE_TYPE(m_class) \ -public: \ - virtual String get_save_class() const { return #m_class; } \ - \ +#define OBJ_SAVE_TYPE(m_class) \ +public: \ + virtual String get_save_class() const override { return #m_class; } \ + \ private: class ScriptInstance; @@ -655,10 +655,7 @@ public: void get_method_list(List<MethodInfo> *p_list) const; Variant callv(const StringName &p_method, const Array &p_args); virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper - void call_multilevel(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper void notification(int p_notification, bool p_reversed = false); String to_string(); @@ -722,7 +719,8 @@ public: virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; - StringName tr(const StringName &p_message) const; // translate message (internationalization) + String tr(const StringName &p_message, const StringName &p_context = "") const; // translate message (internationalization) + String tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; bool _is_queued_for_deletion = false; // set to true by SceneTree::queue_delete() bool is_queued_for_deletion() const; diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index dc68c2a9f9..434f6fa300 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -48,8 +48,10 @@ void MainLoop::_bind_methods() { BIND_CONSTANT(NOTIFICATION_WM_ABOUT); BIND_CONSTANT(NOTIFICATION_CRASH); BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE); - BIND_CONSTANT(NOTIFICATION_APP_RESUMED); - BIND_CONSTANT(NOTIFICATION_APP_PAUSED); + BIND_CONSTANT(NOTIFICATION_APPLICATION_RESUMED); + BIND_CONSTANT(NOTIFICATION_APPLICATION_PAUSED); + BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_IN); + BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT); ADD_SIGNAL(MethodInfo("on_request_permissions_result", PropertyInfo(Variant::STRING, "permission"), PropertyInfo(Variant::BOOL, "granted"))); }; diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 90790a45a1..2c34cf193c 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -52,8 +52,10 @@ public: NOTIFICATION_WM_ABOUT = 2011, NOTIFICATION_CRASH = 2012, NOTIFICATION_OS_IME_UPDATE = 2013, - NOTIFICATION_APP_RESUMED = 2014, - NOTIFICATION_APP_PAUSED = 2015, + NOTIFICATION_APPLICATION_RESUMED = 2014, + NOTIFICATION_APPLICATION_PAUSED = 2015, + NOTIFICATION_APPLICATION_FOCUS_IN = 2016, + NOTIFICATION_APPLICATION_FOCUS_OUT = 2017, }; virtual void init(); diff --git a/core/os/os.cpp b/core/os/os.cpp index c842be333c..dc8bd5ee69 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -41,6 +41,7 @@ #include <stdarg.h> OS *OS::singleton = nullptr; +uint64_t OS::target_ticks = 0; OS *OS::get_singleton() { return singleton; @@ -162,6 +163,10 @@ bool OS::is_stdout_verbose() const { return _verbose_stdout; } +bool OS::is_stdout_debug_enabled() const { + return _debug_stdout; +} + void OS::dump_memory_to_file(const char *p_file) { //Memory::dump_static_mem_to_file(p_file); } @@ -468,6 +473,41 @@ void OS::close_midi_inputs() { } } +void OS::add_frame_delay(bool p_can_draw) { + const uint32_t frame_delay = Engine::get_singleton()->get_frame_delay(); + if (frame_delay) { + // Add fixed frame delay to decrease CPU/GPU usage. This doesn't take + // the actual frame time into account. + // Due to the high fluctuation of the actual sleep duration, it's not recommended + // to use this as a FPS limiter. + delay_usec(frame_delay * 1000); + } + + // Add a dynamic frame delay to decrease CPU/GPU usage. This takes the + // previous frame time into account for a smoother result. + uint64_t dynamic_delay = 0; + if (is_in_low_processor_usage_mode() || !p_can_draw) { + dynamic_delay = get_low_processor_usage_mode_sleep_usec(); + } + const int target_fps = Engine::get_singleton()->get_target_fps(); + if (target_fps > 0 && !Engine::get_singleton()->is_editor_hint()) { + // Override the low processor usage mode sleep delay if the target FPS is lower. + dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / target_fps)); + } + + if (dynamic_delay > 0) { + target_ticks += dynamic_delay; + uint64_t current_ticks = get_ticks_usec(); + + if (current_ticks < target_ticks) { + delay_usec(target_ticks - current_ticks); + } + + current_ticks = get_ticks_usec(); + target_ticks = MIN(MAX(target_ticks, current_ticks - dynamic_delay), current_ticks + dynamic_delay); + } +} + OS::OS() { void *volatile stack_bottom; diff --git a/core/os/os.h b/core/os/os.h index 04e10518dc..8e5c0c26e0 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -43,12 +43,14 @@ class OS { static OS *singleton; + static uint64_t target_ticks; String _execpath; List<String> _cmdline; bool _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0. bool low_processor_usage_mode = false; int low_processor_usage_mode_sleep_usec = 10000; bool _verbose_stdout = false; + bool _debug_stdout = false; String _local_clipboard; uint64_t _msec_splash; bool _no_window = false; @@ -84,11 +86,13 @@ public: protected: friend class Main; + // Needed by tests to setup command-line args. + friend int test_main(int argc, char *argv[]); HasServerFeatureCallback has_server_feature_callback = nullptr; RenderThreadMode _render_thread_mode = RENDER_THREAD_SAFE; - // functions used by main to initialize/deinitialize the OS + // Functions used by Main to initialize/deinitialize the OS. void add_logger(Logger *p_logger); virtual void initialize() = 0; @@ -212,6 +216,8 @@ public: virtual double get_unix_time() const; virtual void delay_usec(uint32_t p_usec) const = 0; + virtual void add_frame_delay(bool p_can_draw); + virtual uint64_t get_ticks_usec() const = 0; uint32_t get_ticks_msec() const; uint64_t get_splash_tick_msec() const; @@ -219,6 +225,7 @@ public: virtual bool is_userfs_persistent() const { return true; } bool is_stdout_verbose() const; + bool is_stdout_debug_enabled() const; virtual void disable_crash_handler() {} virtual bool is_disable_crash_handler() const { return false; } diff --git a/core/packed_data_container.h b/core/packed_data_container.h index b41e9aaefc..28ec9cc87c 100644 --- a/core/packed_data_container.h +++ b/core/packed_data_container.h @@ -72,7 +72,7 @@ protected: static void _bind_methods(); public: - virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const; + virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const override; Error pack(const Variant &p_data); int size() const; @@ -97,7 +97,7 @@ public: bool _is_dictionary() const; int size() const; - virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const; + virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const override; PackedDataContainerRef() {} }; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 9b1c146a06..efe13e740d 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -93,7 +93,7 @@ String ProjectSettings::localize_path(const String &p_path) const { } else { memdelete(dir); - int sep = path.find_last("/"); + int sep = path.rfind("/"); if (sep == -1) { return "res://" + path; } @@ -122,6 +122,22 @@ void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restar props[p_name].restart_if_changed = p_restart; } +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 + props[p_name].ignore_value_in_docs = p_ignore; +#endif +} + +bool ProjectSettings::get_ignore_value_in_docs(const String &p_name) const { + ERR_FAIL_COND_V_MSG(!props.has(p_name), false, "Request for nonexistent project setting: " + p_name + "."); +#ifdef DEBUG_METHODS_ENABLED + return props[p_name].ignore_value_in_docs; +#else + return false; +#endif +} + String ProjectSettings::globalize_path(const String &p_path) const { if (p_path.begins_with("res://")) { if (resource_path != "") { @@ -144,6 +160,12 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { if (p_value.get_type() == Variant::NIL) { props.erase(p_name); + if (p_name.operator String().begins_with("autoload/")) { + String node_name = p_name.operator String().split("/")[1]; + if (autoloads.has(node_name)) { + remove_autoload(node_name); + } + } } else { if (p_name == CoreStringNames::get_singleton()->_custom_features) { Vector<String> custom_feature_array = String(p_value).split(","); @@ -181,6 +203,19 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { } else { props[p_name] = VariantContainer(p_value, last_order++); } + if (p_name.operator String().begins_with("autoload/")) { + String node_name = p_name.operator String().split("/")[1]; + AutoloadInfo autoload; + autoload.name = node_name; + String path = p_value; + if (path.begins_with("*")) { + autoload.is_singleton = true; + autoload.path = path.substr(1); + } else { + autoload.path = path; + } + add_autoload(autoload); + } } return true; @@ -469,6 +504,14 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo _load_settings_text(custom_settings); } } + // Using GLOBAL_GET on every block for compressing can be slow, so assigning here. + Compression::zstd_long_distance_matching = GLOBAL_GET("compression/formats/zstd/long_distance_matching"); + Compression::zstd_level = GLOBAL_GET("compression/formats/zstd/compression_level"); + Compression::zstd_window_log_size = GLOBAL_GET("compression/formats/zstd/window_log_size"); + + Compression::zlib_level = GLOBAL_GET("compression/formats/zlib/compression_level"); + + Compression::gzip_level = GLOBAL_GET("compression/formats/gzip/compression_level"); return err; } @@ -616,6 +659,12 @@ void ProjectSettings::set_builtin_order(const String &p_name) { } } +bool ProjectSettings::is_builtin_setting(const String &p_name) const { + // Return true because a false negative is worse than a false positive. + ERR_FAIL_COND_V_MSG(!props.has(p_name), true, "Request for nonexistent project setting: " + p_name + "."); + return props[p_name].order < NO_BUILTIN_ORDER_BASE; +} + void ProjectSettings::clear(const String &p_name) { ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); props.erase(p_name); @@ -849,7 +898,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) { +Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs) { Variant ret; if (!ProjectSettings::get_singleton()->has_setting(p_var)) { ProjectSettings::get_singleton()->set(p_var, p_default); @@ -859,6 +908,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar ProjectSettings::get_singleton()->set_initial_value(p_var, p_default); ProjectSettings::get_singleton()->set_builtin_order(p_var); 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); return ret; } @@ -945,6 +995,29 @@ bool ProjectSettings::has_custom_feature(const String &p_feature) const { return custom_features.has(p_feature); } +Map<StringName, ProjectSettings::AutoloadInfo> ProjectSettings::get_autoload_list() const { + return autoloads; +} + +void ProjectSettings::add_autoload(const AutoloadInfo &p_autoload) { + ERR_FAIL_COND_MSG(p_autoload.name == StringName(), "Trying to add autoload with no name."); + autoloads[p_autoload.name] = p_autoload; +} + +void ProjectSettings::remove_autoload(const StringName &p_autoload) { + ERR_FAIL_COND_MSG(!autoloads.has(p_autoload), "Trying to remove non-existent autoload."); + autoloads.erase(p_autoload); +} + +bool ProjectSettings::has_autoload(const StringName &p_autoload) const { + return autoloads.has(p_autoload); +} + +ProjectSettings::AutoloadInfo ProjectSettings::get_autoload(const StringName &p_name) const { + ERR_FAIL_COND_V_MSG(!autoloads.has(p_name), AutoloadInfo(), "Trying to get non-existent autoload."); + return autoloads[p_name]; +} + void ProjectSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting); ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting); @@ -965,6 +1038,9 @@ void ProjectSettings::_bind_methods() { } ProjectSettings::ProjectSettings() { + // Initialization of engine variables should be done in the setup() method, + // so that the values can be overridden from project.godot or project.binary. + singleton = this; Array events; @@ -1164,18 +1240,17 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("debug/settings/profiler/max_functions", 16384); custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"); - //assigning here, because using GLOBAL_GET on every block for compressing can be slow - Compression::zstd_long_distance_matching = GLOBAL_DEF("compression/formats/zstd/long_distance_matching", false); + GLOBAL_DEF("compression/formats/zstd/long_distance_matching", Compression::zstd_long_distance_matching); custom_prop_info["compression/formats/zstd/long_distance_matching"] = PropertyInfo(Variant::BOOL, "compression/formats/zstd/long_distance_matching"); - Compression::zstd_level = GLOBAL_DEF("compression/formats/zstd/compression_level", 3); + GLOBAL_DEF("compression/formats/zstd/compression_level", Compression::zstd_level); custom_prop_info["compression/formats/zstd/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zstd/compression_level", PROPERTY_HINT_RANGE, "1,22,1"); - Compression::zstd_window_log_size = GLOBAL_DEF("compression/formats/zstd/window_log_size", 27); + GLOBAL_DEF("compression/formats/zstd/window_log_size", Compression::zstd_window_log_size); custom_prop_info["compression/formats/zstd/window_log_size"] = PropertyInfo(Variant::INT, "compression/formats/zstd/window_log_size", PROPERTY_HINT_RANGE, "10,30,1"); - Compression::zlib_level = GLOBAL_DEF("compression/formats/zlib/compression_level", Z_DEFAULT_COMPRESSION); + GLOBAL_DEF("compression/formats/zlib/compression_level", Compression::zlib_level); custom_prop_info["compression/formats/zlib/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zlib/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"); - Compression::gzip_level = GLOBAL_DEF("compression/formats/gzip/compression_level", Z_DEFAULT_COMPRESSION); + 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"); } diff --git a/core/project_settings.h b/core/project_settings.h index d579d44039..29b2406dd2 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -47,6 +47,12 @@ public: NO_BUILTIN_ORDER_BASE = 1 << 16 }; + struct AutoloadInfo { + StringName name; + String path; + bool is_singleton = false; + }; + protected: struct VariantContainer { int order = 0; @@ -56,6 +62,9 @@ protected: bool hide_from_editor = false; bool overridden = false; bool restart_if_changed = false; +#ifdef DEBUG_METHODS_ENABLED + bool ignore_value_in_docs = false; +#endif VariantContainer() {} @@ -67,8 +76,8 @@ protected: }; bool registering_order = true; - int last_order = 0; - int last_builtin_order = NO_BUILTIN_ORDER_BASE; + int last_order = NO_BUILTIN_ORDER_BASE; + int last_builtin_order = 0; Map<StringName, VariantContainer> props; String resource_path; Map<StringName, PropertyInfo> custom_prop_info; @@ -79,6 +88,8 @@ protected: Set<String> custom_features; Map<StringName, StringName> feature_overrides; + Map<StringName, AutoloadInfo> autoloads; + bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; @@ -117,6 +128,9 @@ public: void set_initial_value(const String &p_name, const Variant &p_value); 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; + bool property_can_revert(const String &p_name); Variant property_get_revert(const String &p_name); @@ -128,6 +142,7 @@ public: int get_order(const String &p_name) const; void set_order(const String &p_name, int p_order); void set_builtin_order(const String &p_name); + bool is_builtin_setting(const String &p_name) const; Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false); @@ -148,14 +163,22 @@ public: bool has_custom_feature(const String &p_feature) const; + Map<StringName, AutoloadInfo> get_autoload_list() const; + void add_autoload(const AutoloadInfo &p_autoload); + void remove_autoload(const StringName &p_autoload); + bool has_autoload(const StringName &p_autoload) const; + AutoloadInfo get_autoload(const StringName &p_name) const; + ProjectSettings(); ~ProjectSettings(); }; //not a macro any longer -Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false); +Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = 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) +#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true) #define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) #endif // PROJECT_SETTINGS_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 5dac42cacb..4f094dd6c6 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -86,6 +86,7 @@ static _Engine *_engine = nullptr; static _ClassDB *_classdb = nullptr; static _Marshalls *_marshalls = nullptr; static _JSON *_json = nullptr; +static _EngineDebugger *_engine_debugger = nullptr; static IP *ip = nullptr; @@ -227,6 +228,7 @@ void register_core_types() { _classdb = memnew(_ClassDB); _marshalls = memnew(_Marshalls); _json = memnew(_JSON); + _engine_debugger = memnew(_EngineDebugger); } void register_core_settings() { @@ -256,6 +258,7 @@ void register_core_singletons() { ClassDB::register_class<InputMap>(); ClassDB::register_class<_JSON>(); ClassDB::register_class<Expression>(); + ClassDB::register_class<_EngineDebugger>(); Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton())); @@ -271,6 +274,7 @@ void register_core_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton())); } void unregister_core_types() { @@ -281,6 +285,7 @@ void unregister_core_types() { memdelete(_classdb); memdelete(_marshalls); memdelete(_json); + memdelete(_engine_debugger); memdelete(_geometry_2d); memdelete(_geometry_3d); diff --git a/core/resource.h b/core/resource.h index ad2f3ce913..7699d48735 100644 --- a/core/resource.h +++ b/core/resource.h @@ -40,15 +40,19 @@ #define RES_BASE_EXTENSION(m_ext) \ public: \ static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension(m_ext, get_class_static()); } \ - virtual String get_base_extension() const { return m_ext; } \ + virtual String get_base_extension() const override { return m_ext; } \ \ private: class Resource : public Reference { GDCLASS(Resource, Reference); OBJ_CATEGORY("Resources"); - RES_BASE_EXTENSION("res"); +public: + static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension("res", get_class_static()); } + virtual String get_base_extension() const { return "res"; } + +private: Set<ObjectID> owners; friend class ResBase; diff --git a/core/rid_owner.h b/core/rid_owner.h index 2489475c68..30f1e41733 100644 --- a/core/rid_owner.h +++ b/core/rid_owner.h @@ -236,7 +236,7 @@ public: } _FORCE_INLINE_ T *get_ptr_by_index(uint32_t p_index) { - ERR_FAIL_INDEX_V(p_index, alloc_count, nullptr); + ERR_FAIL_UNSIGNED_INDEX_V(p_index, alloc_count, nullptr); if (THREAD_SAFE) { spin_lock.lock(); } diff --git a/core/script_language.cpp b/core/script_language.cpp index 38a970f3c6..b63aeb952c 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -308,16 +308,6 @@ Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) { return call(p_method, argptr, argc, error); } -void ScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - Callable::CallError ce; - call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls -} - -void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - Callable::CallError ce; - call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls -} - void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) { if (r_valid) { *r_valid = false; @@ -331,19 +321,6 @@ Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid) return Variant(); } -void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - call_multilevel(p_method, argptr, argc); -} - ScriptInstance::~ScriptInstance() { } @@ -352,6 +329,39 @@ ScriptCodeCompletionCache::ScriptCodeCompletionCache() { singleton = this; } +void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const { + p_core_type_words->push_back("String"); + p_core_type_words->push_back("Vector2"); + p_core_type_words->push_back("Vector2i"); + p_core_type_words->push_back("Rect2"); + p_core_type_words->push_back("Rect2i"); + p_core_type_words->push_back("Vector3"); + p_core_type_words->push_back("Vector3i"); + p_core_type_words->push_back("Transform2D"); + p_core_type_words->push_back("Plane"); + p_core_type_words->push_back("Quat"); + p_core_type_words->push_back("AABB"); + p_core_type_words->push_back("Basis"); + p_core_type_words->push_back("Transform"); + p_core_type_words->push_back("Color"); + p_core_type_words->push_back("StringName"); + p_core_type_words->push_back("NodePath"); + p_core_type_words->push_back("RID"); + p_core_type_words->push_back("Callable"); + p_core_type_words->push_back("Signal"); + p_core_type_words->push_back("Dictionary"); + p_core_type_words->push_back("Array"); + p_core_type_words->push_back("PackedByteArray"); + p_core_type_words->push_back("PackedInt32Array"); + p_core_type_words->push_back("PackedInt64Array"); + p_core_type_words->push_back("PackedFloat32Array"); + p_core_type_words->push_back("PackedFloat64Array"); + p_core_type_words->push_back("PackedStringArray"); + p_core_type_words->push_back("PackedVector2Array"); + p_core_type_words->push_back("PackedVector3Array"); + p_core_type_words->push_back("PackedColorArray"); +} + void ScriptLanguage::frame() { } diff --git a/core/script_language.h b/core/script_language.h index b6c2a47245..aa7014ed3e 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -116,7 +116,7 @@ class Script : public Resource { OBJ_SAVE_TYPE(Script); protected: - virtual bool editor_can_reload_from_file() { return false; } // this is handled by editor better + virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better void _notification(int p_what); static void _bind_methods(); @@ -199,9 +199,6 @@ public: virtual bool has_method(const StringName &p_method) const = 0; virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST); virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0; - virtual void call_multilevel(const StringName &p_method, VARIANT_ARG_LIST); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void notification(int p_notification) = 0; virtual String to_string(bool *r_valid) { if (r_valid) { @@ -256,6 +253,7 @@ struct ScriptCodeCompletionOption { Kind kind = KIND_PLAIN_TEXT; String display; String insert_text; + Color font_color; RES icon; ScriptCodeCompletionOption() {} @@ -293,12 +291,14 @@ public: /* EDITOR FUNCTIONS */ struct Warning { - int line; + int start_line = -1, end_line = -1; + int leftmost_column = -1, rightmost_column = -1; int code; String string_code; String message; }; + void get_core_type_words(List<String> *p_core_type_words) const; virtual void get_reserved_words(List<String> *p_words) const = 0; virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0; virtual void get_string_delimiters(List<String> *p_delimiters) const = 0; @@ -425,8 +425,6 @@ public: r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } - //virtual void call_multilevel(const StringName& p_method,VARIANT_ARG_LIST) { return Variant(); } - //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount,Callable::CallError &r_error) { return Variant(); } virtual void notification(int p_notification) {} virtual Ref<Script> get_script() const { return script; } diff --git a/core/string_buffer.h b/core/string_buffer.h index 956a6333d9..f9cf31075a 100644 --- a/core/string_buffer.h +++ b/core/string_buffer.h @@ -150,7 +150,7 @@ String StringBuffer<SHORT_BUFFER_SIZE>::as_string() { template <int SHORT_BUFFER_SIZE> double StringBuffer<SHORT_BUFFER_SIZE>::as_double() { current_buffer_ptr()[string_length] = '\0'; - return String::to_double(current_buffer_ptr()); + return String::to_float(current_buffer_ptr()); } template <int SHORT_BUFFER_SIZE> diff --git a/core/string_name.h b/core/string_name.h index df6b458581..886ddd0ee7 100644 --- a/core/string_name.h +++ b/core/string_name.h @@ -35,6 +35,8 @@ #include "core/safe_refcount.h" #include "core/ustring.h" +class Main; + struct StaticCString { const char *ptr; static StaticCString create(const char *p_ptr); @@ -73,7 +75,7 @@ class StringName { void unref(); friend void register_core_types(); friend void unregister_core_types(); - + friend class Main; static Mutex mutex; static void setup(); static void cleanup(); diff --git a/core/translation.cpp b/core/translation.cpp index 4f835bd7b4..8c8ca06740 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -794,17 +794,12 @@ static const char *locale_renames[][2] = { /////////////////////////////////////////////// -Vector<String> Translation::_get_messages() const { - Vector<String> msgs; - msgs.resize(translation_map.size() * 2); - int idx = 0; +Dictionary Translation::_get_messages() const { + Dictionary d; for (const Map<StringName, StringName>::Element *E = translation_map.front(); E; E = E->next()) { - msgs.set(idx + 0, E->key()); - msgs.set(idx + 1, E->get()); - idx += 2; + d[E->key()] = E->value(); } - - return msgs; + return d; } Vector<String> Translation::_get_message_list() const { @@ -819,14 +814,11 @@ Vector<String> Translation::_get_message_list() const { return msgs; } -void Translation::_set_messages(const Vector<String> &p_messages) { - int msg_count = p_messages.size(); - ERR_FAIL_COND(msg_count % 2); - - const String *r = p_messages.ptr(); - - for (int i = 0; i < msg_count; i += 2) { - add_message(r[i + 0], r[i + 1]); +void Translation::_set_messages(const Dictionary &p_messages) { + List<Variant> keys; + p_messages.get_key_list(&keys); + for (auto E = keys.front(); E; E = E->next()) { + translation_map[E->get()] = p_messages[E->get()]; } } @@ -848,11 +840,21 @@ void Translation::set_locale(const String &p_locale) { } } -void Translation::add_message(const StringName &p_src_text, const StringName &p_xlated_text) { +void Translation::add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context) { translation_map[p_src_text] = p_xlated_text; } -StringName Translation::get_message(const StringName &p_src_text) const { +void Translation::add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context) { + WARN_PRINT("Translation class doesn't handle plural messages. Calling add_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class"); + ERR_FAIL_COND_MSG(p_plural_xlated_texts.empty(), "Parameter vector p_plural_xlated_texts passed in is empty."); + translation_map[p_src_text] = p_plural_xlated_texts[0]; +} + +StringName Translation::get_message(const StringName &p_src_text, const StringName &p_context) const { + if (p_context != StringName()) { + WARN_PRINT("Translation class doesn't handle context. Using context in get_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class"); + } + const Map<StringName, StringName>::Element *E = translation_map.find(p_src_text); if (!E) { return StringName(); @@ -861,7 +863,16 @@ StringName Translation::get_message(const StringName &p_src_text) const { return E->get(); } -void Translation::erase_message(const StringName &p_src_text) { +StringName Translation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const { + WARN_PRINT("Translation class doesn't handle plural messages. Calling get_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class"); + return get_message(p_src_text); +} + +void Translation::erase_message(const StringName &p_src_text, const StringName &p_context) { + if (p_context != StringName()) { + WARN_PRINT("Translation class doesn't handle context. Using context in erase_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class"); + } + translation_map.erase(p_src_text); } @@ -878,15 +889,17 @@ int Translation::get_message_count() const { void Translation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_locale", "locale"), &Translation::set_locale); ClassDB::bind_method(D_METHOD("get_locale"), &Translation::get_locale); - ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message"), &Translation::add_message); - ClassDB::bind_method(D_METHOD("get_message", "src_message"), &Translation::get_message); - ClassDB::bind_method(D_METHOD("erase_message", "src_message"), &Translation::erase_message); + ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message", "context"), &Translation::add_message, DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_plural_message", "src_message", "xlated_messages", "context"), &Translation::add_plural_message, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_message", "src_message", "context"), &Translation::get_message, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL("")); + ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list); ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count); ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages); ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "locale"), "set_locale", "get_locale"); } @@ -1020,11 +1033,35 @@ void TranslationServer::remove_translation(const Ref<Translation> &p_translation translations.erase(p_translation); } +Ref<Translation> TranslationServer::get_translation_object(const String &p_locale) { + Ref<Translation> res; + String lang = get_language_code(p_locale); + bool near_match_found = false; + + for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) { + const Ref<Translation> &t = E->get(); + ERR_FAIL_COND_V(t.is_null(), nullptr); + String l = t->get_locale(); + + // Exact match. + if (l == p_locale) { + return t; + } + + // If near match found, keep that match, but keep looking to try to look for perfect match. + if (get_language_code(l) == lang && !near_match_found) { + res = t; + near_match_found = true; + } + } + return res; +} + void TranslationServer::clear() { translations.clear(); } -StringName TranslationServer::translate(const StringName &p_message) const { +StringName TranslationServer::translate(const StringName &p_message, const StringName &p_context) const { // Match given message against the translation catalog for the project locale. if (!enabled) { @@ -1033,6 +1070,46 @@ StringName TranslationServer::translate(const StringName &p_message) const { ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid."); + StringName res = _get_message_from_translations(p_message, p_context, locale, false); + + if (!res && fallback.length() >= 2) { + res = _get_message_from_translations(p_message, p_context, fallback, false); + } + + if (!res) { + return p_message; + } + + return res; +} + +StringName TranslationServer::translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + if (!enabled) { + if (p_n == 1) { + return p_message; + } + return p_message_plural; + } + + ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid."); + + StringName res = _get_message_from_translations(p_message, p_context, locale, true, p_message_plural, p_n); + + if (!res && fallback.length() >= 2) { + res = _get_message_from_translations(p_message, p_context, fallback, true, p_message_plural, p_n); + } + + if (!res) { + if (p_n == 1) { + return p_message; + } + return p_message_plural; + } + + return res; +} + +StringName TranslationServer::_get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural, int p_n) const { // Locale can be of the form 'll_CC', i.e. language code and regional code, // e.g. 'en_US', 'en_GB', etc. It might also be simply 'll', e.g. 'en'. // To find the relevant translation, we look for those with locale starting @@ -1044,7 +1121,7 @@ StringName TranslationServer::translate(const StringName &p_message) const { // logic, so be sure to propagate changes there when changing things here. StringName res; - String lang = get_language_code(locale); + String lang = get_language_code(p_locale); bool near_match = false; for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) { @@ -1052,7 +1129,7 @@ StringName TranslationServer::translate(const StringName &p_message) const { ERR_FAIL_COND_V(t.is_null(), p_message); String l = t->get_locale(); - bool exact_match = (l == locale); + bool exact_match = (l == p_locale); if (!exact_match) { if (near_match) { continue; // Only near-match once, but keep looking for exact matches. @@ -1062,7 +1139,13 @@ StringName TranslationServer::translate(const StringName &p_message) const { } } - StringName r = t->get_message(p_message); + StringName r; + if (!plural) { + r = t->get_message(p_message, p_context); + } else { + r = t->get_plural_message(p_message, p_message_plural, p_n, p_context); + } + if (!r) { continue; } @@ -1075,44 +1158,6 @@ StringName TranslationServer::translate(const StringName &p_message) const { } } - if (!res && fallback.length() >= 2) { - // Try again with the fallback locale. - String fallback_lang = get_language_code(fallback); - near_match = false; - - for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) { - const Ref<Translation> &t = E->get(); - ERR_FAIL_COND_V(t.is_null(), p_message); - String l = t->get_locale(); - - bool exact_match = (l == fallback); - if (!exact_match) { - if (near_match) { - continue; // Only near-match once, but keep looking for exact matches. - } - if (get_language_code(l) != fallback_lang) { - continue; // Language code does not match. - } - } - - StringName r = t->get_message(p_message); - if (!r) { - continue; - } - res = r; - - if (exact_match) { - break; - } else { - near_match = true; - } - } - } - - if (!res) { - return p_message; - } - return res; } @@ -1169,9 +1214,9 @@ void TranslationServer::set_tool_translation(const Ref<Translation> &p_translati tool_translation = p_translation; } -StringName TranslationServer::tool_translate(const StringName &p_message) const { +StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const { if (tool_translation.is_valid()) { - StringName r = tool_translation->get_message(p_message); + StringName r = tool_translation->get_message(p_message, p_context); if (r) { return r; } @@ -1179,13 +1224,27 @@ StringName TranslationServer::tool_translate(const StringName &p_message) const return p_message; } +StringName TranslationServer::tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + if (tool_translation.is_valid()) { + StringName r = tool_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); + if (r) { + return r; + } + } + + if (p_n == 1) { + return p_message; + } + return p_message_plural; +} + void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) { doc_translation = p_translation; } -StringName TranslationServer::doc_translate(const StringName &p_message) const { +StringName TranslationServer::doc_translate(const StringName &p_message, const StringName &p_context) const { if (doc_translation.is_valid()) { - StringName r = doc_translation->get_message(p_message); + StringName r = doc_translation->get_message(p_message, p_context); if (r) { return r; } @@ -1193,16 +1252,32 @@ StringName TranslationServer::doc_translate(const StringName &p_message) const { return p_message; } +StringName TranslationServer::doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + if (doc_translation.is_valid()) { + StringName r = doc_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); + if (r) { + return r; + } + } + + if (p_n == 1) { + return p_message; + } + return p_message_plural; +} + void TranslationServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_locale", "locale"), &TranslationServer::set_locale); ClassDB::bind_method(D_METHOD("get_locale"), &TranslationServer::get_locale); ClassDB::bind_method(D_METHOD("get_locale_name", "locale"), &TranslationServer::get_locale_name); - ClassDB::bind_method(D_METHOD("translate", "message"), &TranslationServer::translate); + ClassDB::bind_method(D_METHOD("translate", "message", "context"), &TranslationServer::translate, DEFVAL("")); + ClassDB::bind_method(D_METHOD("translate_plural", "message", "plural_message", "n", "context"), &TranslationServer::translate_plural, DEFVAL("")); ClassDB::bind_method(D_METHOD("add_translation", "translation"), &TranslationServer::add_translation); ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationServer::remove_translation); + ClassDB::bind_method(D_METHOD("get_translation_object", "locale"), &TranslationServer::get_translation_object); ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear); diff --git a/core/translation.h b/core/translation.h index 4f50a1a4bc..cba25a434f 100644 --- a/core/translation.h +++ b/core/translation.h @@ -41,10 +41,9 @@ class Translation : public Resource { String locale = "en"; Map<StringName, StringName> translation_map; - Vector<String> _get_message_list() const; - - Vector<String> _get_messages() const; - void _set_messages(const Vector<String> &p_messages); + virtual Vector<String> _get_message_list() const; + virtual Dictionary _get_messages() const; + virtual void _set_messages(const Dictionary &p_messages); protected: static void _bind_methods(); @@ -53,12 +52,13 @@ public: void set_locale(const String &p_locale); _FORCE_INLINE_ String get_locale() const { return locale; } - void add_message(const StringName &p_src_text, const StringName &p_xlated_text); - virtual StringName get_message(const StringName &p_src_text) const; //overridable for other implementations - void erase_message(const StringName &p_src_text); - - void get_message_list(List<StringName> *r_messages) const; - int get_message_count() const; + virtual void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = ""); + virtual void add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context = ""); + virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const; //overridable for other implementations + virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const; + virtual void erase_message(const StringName &p_src_text, const StringName &p_context = ""); + virtual void get_message_list(List<StringName> *r_messages) const; + virtual int get_message_count() const; Translation() {} }; @@ -80,6 +80,8 @@ class TranslationServer : public Object { static TranslationServer *singleton; bool _load_translations(const String &p_from); + StringName _get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const; + static void _bind_methods(); public: @@ -90,6 +92,7 @@ public: void set_locale(const String &p_locale); String get_locale() const; + Ref<Translation> get_translation_object(const String &p_locale); String get_locale_name(const String &p_locale) const; @@ -98,7 +101,8 @@ public: void add_translation(const Ref<Translation> &p_translation); void remove_translation(const Ref<Translation> &p_translation); - StringName translate(const StringName &p_message) const; + StringName translate(const StringName &p_message, const StringName &p_context = "") const; + StringName translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; static Vector<String> get_all_locales(); static Vector<String> get_all_locale_names(); @@ -107,9 +111,11 @@ public: static String get_language_code(const String &p_locale); void set_tool_translation(const Ref<Translation> &p_translation); - StringName tool_translate(const StringName &p_message) const; + StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const; + StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; void set_doc_translation(const Ref<Translation> &p_translation); - StringName doc_translate(const StringName &p_message) const; + StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const; + StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; void setup(); diff --git a/core/translation_po.cpp b/core/translation_po.cpp new file mode 100644 index 0000000000..203f29026b --- /dev/null +++ b/core/translation_po.cpp @@ -0,0 +1,312 @@ +/*************************************************************************/ +/* translation_po.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "translation_po.h" + +#include "core/os/file_access.h" + +#ifdef DEBUG_TRANSLATION_PO +void TranslationPO::print_translation_map() { + Error err; + FileAccess *file = FileAccess::open("translation_map_print_test.txt", FileAccess::WRITE, &err); + if (err != OK) { + ERR_PRINT("Failed to open translation_map_print_test.txt"); + return; + } + + file->store_line("NPlural : " + String::num_int64(this->get_plural_forms())); + file->store_line("Plural rule : " + this->get_plural_rule()); + file->store_line(""); + + List<StringName> context_l; + translation_map.get_key_list(&context_l); + for (auto E = context_l.front(); E; E = E->next()) { + StringName ctx = E->get(); + file->store_line(" ===== Context: " + String::utf8(String(ctx).utf8()) + " ===== "); + const HashMap<StringName, Vector<StringName>> &inner_map = translation_map[ctx]; + + List<StringName> id_l; + inner_map.get_key_list(&id_l); + for (auto E2 = id_l.front(); E2; E2 = E2->next()) { + StringName id = E2->get(); + file->store_line("msgid: " + String::utf8(String(id).utf8())); + for (int i = 0; i < inner_map[id].size(); i++) { + file->store_line("msgstr[" + String::num_int64(i) + "]: " + String::utf8(String(inner_map[id][i]).utf8())); + } + file->store_line(""); + } + } + file->close(); +} +#endif + +Dictionary TranslationPO::_get_messages() const { + // Return translation_map as a Dictionary. + + Dictionary d; + + List<StringName> context_l; + translation_map.get_key_list(&context_l); + for (auto E = context_l.front(); E; E = E->next()) { + StringName ctx = E->get(); + const HashMap<StringName, Vector<StringName>> &id_str_map = translation_map[ctx]; + + Dictionary d2; + List<StringName> id_l; + id_str_map.get_key_list(&id_l); + // Save list of id and strs associated with a context in a temporary dictionary. + for (auto E2 = id_l.front(); E2; E2 = E2->next()) { + StringName id = E2->get(); + d2[id] = id_str_map[id]; + } + + d[ctx] = d2; + } + + return d; +} + +void TranslationPO::_set_messages(const Dictionary &p_messages) { + // Construct translation_map from a Dictionary. + + List<Variant> context_l; + p_messages.get_key_list(&context_l); + for (auto E = context_l.front(); E; E = E->next()) { + StringName ctx = E->get(); + const Dictionary &id_str_map = p_messages[ctx]; + + HashMap<StringName, Vector<StringName>> temp_map; + List<Variant> id_l; + id_str_map.get_key_list(&id_l); + for (auto E2 = id_l.front(); E2; E2 = E2->next()) { + StringName id = E2->get(); + temp_map[id] = id_str_map[id]; + } + + translation_map[ctx] = temp_map; + } +} + +Vector<String> TranslationPO::_get_message_list() const { + // Return all keys in translation_map. + + List<StringName> msgs; + get_message_list(&msgs); + + Vector<String> v; + for (auto E = msgs.front(); E; E = E->next()) { + v.push_back(E->get()); + } + + return v; +} + +int TranslationPO::_get_plural_index(int p_n) const { + // Get a number between [0;number of plural forms). + + input_val.clear(); + input_val.push_back(p_n); + + Variant result; + for (int i = 0; i < equi_tests.size(); i++) { + Error err = expr->parse(equi_tests[i], input_name); + ERR_FAIL_COND_V_MSG(err != OK, 0, "Cannot parse expression. Error: " + expr->get_error_text()); + + result = expr->execute(input_val); + ERR_FAIL_COND_V_MSG(expr->has_execute_failed(), 0, "Cannot evaluate expression."); + + // Last expression. Variant result will either map to a bool or an integer, in both cases returning it will give the correct plural index. + if (i + 1 == equi_tests.size()) { + return result; + } + + if (bool(result)) { + return i; + } + } + + ERR_FAIL_V_MSG(0, "Unexpected. Function should have returned. Please report this bug."); +} + +void TranslationPO::_cache_plural_tests(const String &p_plural_rule) { + // Some examples of p_plural_rule passed in can have the form: + // "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5" (Arabic) + // "n >= 2" (French) // When evaluating the last, esp careful with this one. + // "n != 1" (English) + int first_ques_mark = p_plural_rule.find("?"); + if (first_ques_mark == -1) { + equi_tests.push_back(p_plural_rule.strip_edges()); + return; + } + + String equi_test = p_plural_rule.substr(0, first_ques_mark).strip_edges(); + equi_tests.push_back(equi_test); + + String after_colon = p_plural_rule.substr(p_plural_rule.find(":") + 1, p_plural_rule.length()); + _cache_plural_tests(after_colon); +} + +void TranslationPO::set_plural_rule(const String &p_plural_rule) { + // Set plural_forms and plural_rule. + // p_plural_rule passed in has the form "Plural-Forms: nplurals=2; plural=(n >= 2);". + + int first_semi_col = p_plural_rule.find(";"); + plural_forms = p_plural_rule.substr(p_plural_rule.find("=") + 1, first_semi_col - (p_plural_rule.find("=") + 1)).to_int(); + + int expression_start = p_plural_rule.find("=", first_semi_col) + 1; + int second_semi_col = p_plural_rule.rfind(";"); + plural_rule = p_plural_rule.substr(expression_start, second_semi_col - expression_start); + + // Setup the cache to make evaluating plural rule faster later on. + plural_rule = plural_rule.replacen("(", ""); + plural_rule = plural_rule.replacen(")", ""); + _cache_plural_tests(plural_rule); + expr.instance(); + input_name.push_back("n"); +} + +void TranslationPO::add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context) { + HashMap<StringName, Vector<StringName>> &map_id_str = translation_map[p_context]; + + if (map_id_str.has(p_src_text)) { + WARN_PRINT("Double translations for \"" + String(p_src_text) + "\" under the same context \"" + String(p_context) + "\" for locale \"" + get_locale() + "\".\nThere should only be one unique translation for a given string under the same context."); + map_id_str[p_src_text].set(0, p_xlated_text); + } else { + map_id_str[p_src_text].push_back(p_xlated_text); + } +} + +void TranslationPO::add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context) { + ERR_FAIL_COND_MSG(p_plural_xlated_texts.size() != plural_forms, "Trying to add plural texts that don't match the required number of plural forms for locale \"" + get_locale() + "\""); + + HashMap<StringName, Vector<StringName>> &map_id_str = translation_map[p_context]; + + if (map_id_str.has(p_src_text)) { + WARN_PRINT("Double translations for \"" + p_src_text + "\" under the same context \"" + p_context + "\" for locale " + get_locale() + ".\nThere should only be one unique translation for a given string under the same context."); + map_id_str[p_src_text].clear(); + } + + for (int i = 0; i < p_plural_xlated_texts.size(); i++) { + map_id_str[p_src_text].push_back(p_plural_xlated_texts[i]); + } +} + +int TranslationPO::get_plural_forms() const { + return plural_forms; +} + +String TranslationPO::get_plural_rule() const { + return plural_rule; +} + +StringName TranslationPO::get_message(const StringName &p_src_text, const StringName &p_context) const { + if (!translation_map.has(p_context) || !translation_map[p_context].has(p_src_text)) { + return StringName(); + } + ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug."); + + return translation_map[p_context][p_src_text][0]; +} + +StringName TranslationPO::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const { + ERR_FAIL_COND_V_MSG(p_n < 0, StringName(), "N passed into translation to get a plural message should not be negative. For negative numbers, use singular translation please. Search \"gettext PO Plural Forms\" online for the documentation on translating negative numbers."); + + // If the query is the same as last time, return the cached result. + if (p_n == last_plural_n && p_context == last_plural_context && p_src_text == last_plural_key) { + return translation_map[p_context][p_src_text][last_plural_mapped_index]; + } + + if (!translation_map.has(p_context) || !translation_map[p_context].has(p_src_text)) { + return StringName(); + } + ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug."); + + if (translation_map[p_context][p_src_text].size() == 1) { + WARN_PRINT("Source string \"" + String(p_src_text) + "\" doesn't have plural translations. Use singular translation API for such as tr(), TTR() to translate \"" + String(p_src_text) + "\""); + return translation_map[p_context][p_src_text][0]; + } + + int plural_index = _get_plural_index(p_n); + ERR_FAIL_COND_V_MSG(plural_index < 0 || translation_map[p_context][p_src_text].size() < plural_index + 1, StringName(), "Plural index returned or number of plural translations is not valid. Please report this bug."); + + // Cache result so that if the next entry is the same, we can return directly. + // _get_plural_index(p_n) can get very costly, especially when evaluating long plural-rule (Arabic) + last_plural_key = p_src_text; + last_plural_context = p_context; + last_plural_n = p_n; + last_plural_mapped_index = plural_index; + + return translation_map[p_context][p_src_text][plural_index]; +} + +void TranslationPO::erase_message(const StringName &p_src_text, const StringName &p_context) { + if (!translation_map.has(p_context)) { + return; + } + + translation_map[p_context].erase(p_src_text); +} + +void TranslationPO::get_message_list(List<StringName> *r_messages) const { + // PHashTranslation uses this function to get the list of msgid. + // Return all the keys of translation_map under "" context. + + List<StringName> context_l; + translation_map.get_key_list(&context_l); + + for (auto E = context_l.front(); E; E = E->next()) { + if (String(E->get()) != "") { + continue; + } + + List<StringName> msgid_l; + translation_map[E->get()].get_key_list(&msgid_l); + + for (auto E2 = msgid_l.front(); E2; E2 = E2->next()) { + r_messages->push_back(E2->get()); + } + } +} + +int TranslationPO::get_message_count() const { + List<StringName> context_l; + translation_map.get_key_list(&context_l); + + int count = 0; + for (auto E = context_l.front(); E; E = E->next()) { + count += translation_map[E->get()].size(); + } + return count; +} + +void TranslationPO::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_plural_forms"), &TranslationPO::get_plural_forms); + ClassDB::bind_method(D_METHOD("get_plural_rule"), &TranslationPO::get_plural_rule); +} diff --git a/core/translation_po.h b/core/translation_po.h new file mode 100644 index 0000000000..730635f63d --- /dev/null +++ b/core/translation_po.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* translation_po.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 TRANSLATION_PO_H +#define TRANSLATION_PO_H + +//#define DEBUG_TRANSLATION_PO + +#include "core/math/expression.h" +#include "core/translation.h" + +class TranslationPO : public Translation { + GDCLASS(TranslationPO, Translation); + + // TLDR: Maps context to a list of source strings and translated strings. In PO terms, maps msgctxt to a list of msgid and msgstr. + // The first key corresponds to context, and the second key (of the contained HashMap) corresponds to source string. + // The value Vector<StringName> in the second map stores the translated strings. Index 0, 1, 2 matches msgstr[0], msgstr[1], msgstr[2]... in the case of plurals. + // Otherwise index 0 mathes to msgstr in a singular translation. + // Strings without context have "" as first key. + HashMap<StringName, HashMap<StringName, Vector<StringName>>> translation_map; + + int plural_forms = 0; // 0 means no "Plural-Forms" is given in the PO header file. The min for all languages is 1. + String plural_rule; + + // Cache temporary variables related to _get_plural_index() to make it faster + Vector<String> equi_tests; + Vector<String> input_name; + mutable Ref<Expression> expr; + mutable Array input_val; + mutable StringName last_plural_key; + mutable StringName last_plural_context; + mutable int last_plural_n = -1; // Set it to an impossible value at the beginning. + mutable int last_plural_mapped_index = 0; + + void _cache_plural_tests(const String &p_plural_rule); + int _get_plural_index(int p_n) const; + + Vector<String> _get_message_list() const override; + Dictionary _get_messages() const override; + void _set_messages(const Dictionary &p_messages) override; + +protected: + static void _bind_methods(); + +public: + void get_message_list(List<StringName> *r_messages) const override; + int get_message_count() const override; + void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "") override; + void add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context = "") override; + StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; + StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override; + void erase_message(const StringName &p_src_text, const StringName &p_context = "") override; + + void set_plural_rule(const String &p_plural_rule); + int get_plural_forms() const; + String get_plural_rule() const; + +#ifdef DEBUG_TRANSLATION_PO + void print_translation_map(); +#endif + + TranslationPO() {} +}; + +#endif // TRANSLATION_PO_H diff --git a/core/ustring.cpp b/core/ustring.cpp index 444338d5ae..9d2d938eaf 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -851,7 +851,7 @@ Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty) end = len; } if (p_allow_empty || (end > from)) { - ret.push_back(String::to_double(&c_str()[from])); + ret.push_back(String::to_float(&c_str()[from])); } if (end == len) { @@ -880,7 +880,7 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters, bool p_ } if (p_allow_empty || (end > from)) { - ret.push_back(String::to_double(&c_str()[from])); + ret.push_back(String::to_float(&c_str()[from])); } if (end == len) { @@ -1025,6 +1025,9 @@ String String::chr(CharType p_char) { } String String::num(double p_num, int p_decimals) { + if (Math::is_nan(p_num)) { + return "nan"; + } #ifndef NO_USE_STDLIB if (p_decimals > 16) { @@ -1313,6 +1316,9 @@ String String::num_real(double p_num) { } String String::num_scientific(double p_num) { + if (Math::is_nan(p_num)) { + return "nan"; + } #ifndef NO_USE_STDLIB char buf[256]; @@ -1618,49 +1624,7 @@ String::String(const StrRange &p_range) { copy_from(p_range.c_str, p_range.len); } -int String::hex_to_int(bool p_with_prefix) const { - if (p_with_prefix && length() < 3) { - return 0; - } - - const CharType *s = ptr(); - - int sign = s[0] == '-' ? -1 : 1; - - if (sign < 0) { - s++; - } - - if (p_with_prefix) { - if (s[0] != '0' || s[1] != 'x') { - return 0; - } - s += 2; - } - - int hex = 0; - - while (*s) { - CharType c = LOWERCASE(*s); - int n; - if (c >= '0' && c <= '9') { - n = c - '0'; - } else if (c >= 'a' && c <= 'f') { - n = (c - 'a') + 10; - } else { - return 0; - } - - ERR_FAIL_COND_V_MSG(hex > INT32_MAX / 16, sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + *this + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); - hex *= 16; - hex += n; - s++; - } - - return hex * sign; -} - -int64_t String::hex_to_int64(bool p_with_prefix) const { +int64_t String::hex_to_int(bool p_with_prefix) const { if (p_with_prefix && length() < 3) { return 0; } @@ -1692,8 +1656,9 @@ int64_t String::hex_to_int64(bool p_with_prefix) const { } else { return 0; } - - ERR_FAIL_COND_V_MSG(hex > INT64_MAX / 16, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); + // Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error + bool overflow = ((hex > INT64_MAX / 16) && (sign == 1 || (sign == -1 && hex != (INT64_MAX >> 4) + 1))) || (sign == -1 && hex == (INT64_MAX >> 4) + 1 && c > '0'); + ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); hex *= 16; hex += n; s++; @@ -1702,7 +1667,7 @@ int64_t String::hex_to_int64(bool p_with_prefix) const { return hex * sign; } -int64_t String::bin_to_int64(bool p_with_prefix) const { +int64_t String::bin_to_int(bool p_with_prefix) const { if (p_with_prefix && length() < 3) { return 0; } @@ -1732,8 +1697,9 @@ int64_t String::bin_to_int64(bool p_with_prefix) const { } else { return 0; } - - ERR_FAIL_COND_V_MSG(binary > INT64_MAX / 2, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); + // Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error + bool overflow = ((binary > INT64_MAX / 2) && (sign == 1 || (sign == -1 && binary != (INT64_MAX >> 1) + 1))) || (sign == -1 && binary == (INT64_MAX >> 1) + 1 && c > '0'); + ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); binary *= 2; binary += n; s++; @@ -1742,32 +1708,7 @@ int64_t String::bin_to_int64(bool p_with_prefix) const { return binary * sign; } -int String::to_int() const { - if (length() == 0) { - return 0; - } - - int to = (find(".") >= 0) ? find(".") : length(); - - int integer = 0; - int sign = 1; - - for (int i = 0; i < to; i++) { - CharType c = operator[](i); - if (c >= '0' && c <= '9') { - ERR_FAIL_COND_V_MSG(integer > INT32_MAX / 10, sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + *this + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); - integer *= 10; - integer += c - '0'; - - } else if (integer == 0 && c == '-') { - sign = -sign; - } - } - - return integer * sign; -} - -int64_t String::to_int64() const { +int64_t String::to_int() const { if (length() == 0) { return 0; } @@ -1780,7 +1721,8 @@ int64_t String::to_int64() const { for (int i = 0; i < to; i++) { CharType c = operator[](i); if (c >= '0' && c <= '9') { - ERR_FAIL_COND_V_MSG(integer > INT64_MAX / 10, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); + bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8'))); + ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); integer *= 10; integer += c - '0'; @@ -1792,7 +1734,7 @@ int64_t String::to_int64() const { return integer * sign; } -int String::to_int(const char *p_str, int p_len) { +int64_t String::to_int(const char *p_str, int p_len) { int to = 0; if (p_len >= 0) { to = p_len; @@ -1802,13 +1744,14 @@ int String::to_int(const char *p_str, int p_len) { } } - int integer = 0; - int sign = 1; + int64_t integer = 0; + int64_t sign = 1; for (int i = 0; i < to; i++) { char c = p_str[i]; if (c >= '0' && c <= '9') { - ERR_FAIL_COND_V_MSG(integer > INT32_MAX / 10, sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); + bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8'))); + ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); integer *= 10; integer += c - '0'; @@ -2063,7 +2006,7 @@ done: #define READING_EXP 3 #define READING_DONE 4 -double String::to_double(const char *p_str) { +double String::to_float(const char *p_str) { #ifndef NO_USE_STDLIB return built_in_strtod<char>(p_str); //return atof(p_str); DOES NOT WORK ON ANDROID(??) @@ -2072,11 +2015,7 @@ double String::to_double(const char *p_str) { #endif } -float String::to_float() const { - return to_double(); -} - -double String::to_double(const CharType *p_str, const CharType **r_end) { +double String::to_float(const CharType *p_str, const CharType **r_end) { return built_in_strtod<CharType>(p_str, (CharType **)r_end); } @@ -2144,7 +2083,7 @@ int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) { return sign * integer; } -double String::to_double() const { +double String::to_float() const { if (empty()) { return 0; } @@ -2343,18 +2282,6 @@ String String::substr(int p_from, int p_chars) const { return s; } -int String::find_last(const String &p_str) const { - int pos = -1; - int findfrom = 0; - int findres = -1; - while ((findres = find(p_str, findfrom)) != -1) { - pos = findres; - findfrom = pos + 1; - } - - return pos; -} - int String::find(const String &p_str, int p_from) const { if (p_from < 0) { return -1; @@ -2645,7 +2572,7 @@ int String::rfindn(const String &p_str, int p_from) const { } bool String::ends_with(const String &p_string) const { - int pos = find_last(p_string); + int pos = rfind(p_string); if (pos == -1) { return false; } @@ -3838,7 +3765,7 @@ bool String::is_valid_ip_address() const { continue; } if (n.is_valid_hex_number(false)) { - int nint = n.hex_to_int(false); + int64_t nint = n.hex_to_int(false); if (nint < 0 || nint > 0xffff) { return false; } @@ -3894,7 +3821,7 @@ String String::get_base_dir() const { } } - int sep = MAX(rs.find_last("/"), rs.find_last("\\")); + int sep = MAX(rs.rfind("/"), rs.rfind("\\")); if (sep == -1) { return base; } @@ -3903,7 +3830,7 @@ String String::get_base_dir() const { } String String::get_file() const { - int sep = MAX(find_last("/"), find_last("\\")); + int sep = MAX(rfind("/"), rfind("\\")); if (sep == -1) { return *this; } @@ -3912,8 +3839,8 @@ String String::get_file() const { } String String::get_extension() const { - int pos = find_last("."); - if (pos < 0 || pos < MAX(find_last("/"), find_last("\\"))) { + int pos = rfind("."); + if (pos < 0 || pos < MAX(rfind("/"), rfind("\\"))) { return ""; } @@ -4001,8 +3928,8 @@ String String::property_name_encode() const { } String String::get_basename() const { - int pos = find_last("."); - if (pos < 0 || pos < MAX(find_last("/"), find_last("\\"))) { + int pos = rfind("."); + if (pos < 0 || pos < MAX(rfind("/"), rfind("\\"))) { return *this; } @@ -4342,31 +4269,58 @@ String String::unquote() const { } #ifdef TOOLS_ENABLED -String TTR(const String &p_text) { +String TTR(const String &p_text, const String &p_context) { if (TranslationServer::get_singleton()) { - return TranslationServer::get_singleton()->tool_translate(p_text); + return TranslationServer::get_singleton()->tool_translate(p_text, p_context); } return p_text; } -String DTR(const String &p_text) { +String TTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) { + if (TranslationServer::get_singleton()) { + return TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context); + } + + // Return message based on English plural rule if translation is not possible. + if (p_n == 1) { + return p_text; + } + return p_text_plural; +} + +String DTR(const String &p_text, const String &p_context) { // Comes straight from the XML, so remove indentation and any trailing whitespace. const String text = p_text.dedent().strip_edges(); if (TranslationServer::get_singleton()) { - return TranslationServer::get_singleton()->doc_translate(text); + return TranslationServer::get_singleton()->doc_translate(text, p_context); } return text; } + +String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) { + const String text = p_text.dedent().strip_edges(); + const String text_plural = p_text_plural.dedent().strip_edges(); + + if (TranslationServer::get_singleton()) { + return TranslationServer::get_singleton()->doc_translate_plural(text, text_plural, p_n, p_context); + } + + // Return message based on English plural rule if translation is not possible. + if (p_n == 1) { + return text; + } + return text_plural; +} #endif -String RTR(const String &p_text) { +String RTR(const String &p_text, const String &p_context) { if (TranslationServer::get_singleton()) { - String rtr = TranslationServer::get_singleton()->tool_translate(p_text); + String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context); if (rtr == String() || rtr == p_text) { - return TranslationServer::get_singleton()->translate(p_text); + return TranslationServer::get_singleton()->translate(p_text, p_context); } else { return rtr; } @@ -4374,3 +4328,20 @@ String RTR(const String &p_text) { return p_text; } + +String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) { + if (TranslationServer::get_singleton()) { + String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context); + if (rtr == String() || rtr == p_text || rtr == p_text_plural) { + return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context); + } else { + return rtr; + } + } + + // Return message based on English plural rule if translation is not possible. + if (p_n == 1) { + return p_text; + } + return p_text_plural; +} diff --git a/core/ustring.h b/core/ustring.h index 5b13a1c704..7a1c1a5232 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -202,7 +202,6 @@ public: int find(const String &p_str, int p_from = 0) const; ///< return <0 if failed int find(const char *p_str, int p_from = 0) const; ///< return <0 if failed int find_char(const CharType &p_char, int p_from = 0) const; ///< return <0 if failed - int find_last(const String &p_str) const; ///< return <0 if failed int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed int rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive @@ -243,17 +242,14 @@ public: static String md5(const uint8_t *p_md5); static String hex_encode_buffer(const uint8_t *p_buffer, int p_len); bool is_numeric() const; - double to_double() const; - float to_float() const; - int hex_to_int(bool p_with_prefix = true) const; - int to_int() const; - - int64_t hex_to_int64(bool p_with_prefix = true) const; - int64_t bin_to_int64(bool p_with_prefix = true) const; - int64_t to_int64() const; - static int to_int(const char *p_str, int p_len = -1); - static double to_double(const char *p_str); - static double to_double(const CharType *p_str, const CharType **r_end = nullptr); + double to_float() const; + + int64_t hex_to_int(bool p_with_prefix = true) const; + int64_t bin_to_int(bool p_with_prefix = true) const; + int64_t to_int() const; + static int64_t to_int(const char *p_str, int p_len = -1); + static double to_float(const char *p_str); + static double to_float(const CharType *p_str, const CharType **r_end = nullptr); static int64_t to_int(const CharType *p_str, int p_len = -1, bool p_clamp = false); String capitalize() const; String camelcase_to_underscore(bool lowercase = true) const; @@ -414,8 +410,10 @@ _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) { // and doc translate for the class reference (DTR). #ifdef TOOLS_ENABLED // Gets parsed. -String TTR(const String &); -String DTR(const String &); +String TTR(const String &p_text, const String &p_context = ""); +String TTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = ""); +String DTR(const String &p_text, const String &p_context = ""); +String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = ""); // Use for C strings. #define TTRC(m_value) (m_value) // Use to avoid parsing (for use later with C strings). @@ -423,13 +421,16 @@ String DTR(const String &); #else #define TTR(m_value) (String()) +#define TTRN(m_value) (String()) #define DTR(m_value) (String()) +#define DTRN(m_value) (String()) #define TTRC(m_value) (m_value) #define TTRGET(m_value) (m_value) #endif // Runtime translate for the public node API. -String RTR(const String &); +String RTR(const String &p_text, const String &p_context = ""); +String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = ""); bool is_symbol(CharType c); bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end); diff --git a/core/variant.cpp b/core/variant.cpp index 21aaa0fe9e..c19ce79e64 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1409,7 +1409,7 @@ Variant::operator int64_t() const { case FLOAT: return _data._float; case STRING: - return operator String().to_int64(); + return operator String().to_int(); default: { return 0; } @@ -1454,7 +1454,7 @@ Variant::operator signed long() const { case INT: return _data._int; case FLOAT: - return _data._real; + return _data._float; case STRING: return operator String().to_int(); default: { @@ -1474,7 +1474,7 @@ Variant::operator unsigned long() const { case INT: return _data._int; case FLOAT: - return _data._real; + return _data._float; case STRING: return operator String().to_int(); default: { @@ -1573,7 +1573,7 @@ Variant::operator float() const { case FLOAT: return _data._float; case STRING: - return operator String().to_double(); + return operator String().to_float(); default: { return 0; } @@ -1591,7 +1591,7 @@ Variant::operator double() const { case FLOAT: return _data._float; case STRING: - return operator String().to_double(); + return operator String().to_float(); default: { return 0; } diff --git a/core/variant.h b/core/variant.h index 50b7a21eda..27a709b473 100644 --- a/core/variant.h +++ b/core/variant.h @@ -120,6 +120,7 @@ public: private: friend struct _VariantCall; + friend class VariantInternal; // Variant takes 20 bytes when real_t is float, and 36 if double // it only allocates extra memory for aabb/matrix. diff --git a/core/variant_call.cpp b/core/variant_call.cpp index a8beac1e44..91af127d32 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -244,7 +244,6 @@ struct _VariantCall { VCALL_LOCALMEM3R(String, countn); VCALL_LOCALMEM2R(String, substr); VCALL_LOCALMEM2R(String, find); - VCALL_LOCALMEM1R(String, find_last); VCALL_LOCALMEM2R(String, findn); VCALL_LOCALMEM2R(String, rfind); VCALL_LOCALMEM2R(String, rfindn); @@ -456,7 +455,6 @@ struct _VariantCall { VCALL_LOCALMEM0R(Plane, normalized); VCALL_LOCALMEM0R(Plane, center); - VCALL_LOCALMEM0R(Plane, get_any_point); VCALL_LOCALMEM1R(Plane, is_equal_approx); VCALL_LOCALMEM1R(Plane, is_point_over); VCALL_LOCALMEM1R(Plane, distance_to); @@ -702,6 +700,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedByteArray, uint8_t, remove); VCALL_PARRMEM1(PackedByteArray, uint8_t, append); VCALL_PARRMEM1(PackedByteArray, uint8_t, append_array); + VCALL_PARRMEM1R(PackedByteArray, uint8_t, has); + VCALL_PARRMEM0(PackedByteArray, uint8_t, sort); VCALL_PARRMEM0(PackedByteArray, uint8_t, invert); VCALL_PARRMEM2R(PackedByteArray, uint8_t, subarray); @@ -715,6 +715,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedInt32Array, int32_t, remove); VCALL_PARRMEM1(PackedInt32Array, int32_t, append); VCALL_PARRMEM1(PackedInt32Array, int32_t, append_array); + VCALL_PARRMEM1R(PackedInt32Array, int32_t, has); + VCALL_PARRMEM0(PackedInt32Array, int32_t, sort); VCALL_PARRMEM0(PackedInt32Array, int32_t, invert); VCALL_PARRMEM0R(PackedInt64Array, int64_t, size); @@ -727,6 +729,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedInt64Array, int64_t, remove); VCALL_PARRMEM1(PackedInt64Array, int64_t, append); VCALL_PARRMEM1(PackedInt64Array, int64_t, append_array); + VCALL_PARRMEM1R(PackedInt64Array, int64_t, has); + VCALL_PARRMEM0(PackedInt64Array, int64_t, sort); VCALL_PARRMEM0(PackedInt64Array, int64_t, invert); VCALL_PARRMEM0R(PackedFloat32Array, float, size); @@ -739,6 +743,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedFloat32Array, float, remove); VCALL_PARRMEM1(PackedFloat32Array, float, append); VCALL_PARRMEM1(PackedFloat32Array, float, append_array); + VCALL_PARRMEM1R(PackedFloat32Array, float, has); + VCALL_PARRMEM0(PackedFloat32Array, float, sort); VCALL_PARRMEM0(PackedFloat32Array, float, invert); VCALL_PARRMEM0R(PackedFloat64Array, double, size); @@ -751,6 +757,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedFloat64Array, double, remove); VCALL_PARRMEM1(PackedFloat64Array, double, append); VCALL_PARRMEM1(PackedFloat64Array, double, append_array); + VCALL_PARRMEM1R(PackedFloat64Array, double, has); + VCALL_PARRMEM0(PackedFloat64Array, double, sort); VCALL_PARRMEM0(PackedFloat64Array, double, invert); VCALL_PARRMEM0R(PackedStringArray, String, size); @@ -763,6 +771,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedStringArray, String, remove); VCALL_PARRMEM1(PackedStringArray, String, append); VCALL_PARRMEM1(PackedStringArray, String, append_array); + VCALL_PARRMEM1R(PackedStringArray, String, has); + VCALL_PARRMEM0(PackedStringArray, String, sort); VCALL_PARRMEM0(PackedStringArray, String, invert); VCALL_PARRMEM0R(PackedVector2Array, Vector2, size); @@ -775,6 +785,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedVector2Array, Vector2, remove); VCALL_PARRMEM1(PackedVector2Array, Vector2, append); VCALL_PARRMEM1(PackedVector2Array, Vector2, append_array); + VCALL_PARRMEM1R(PackedVector2Array, Vector2, has); + VCALL_PARRMEM0(PackedVector2Array, Vector2, sort); VCALL_PARRMEM0(PackedVector2Array, Vector2, invert); VCALL_PARRMEM0R(PackedVector3Array, Vector3, size); @@ -787,6 +799,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedVector3Array, Vector3, remove); VCALL_PARRMEM1(PackedVector3Array, Vector3, append); VCALL_PARRMEM1(PackedVector3Array, Vector3, append_array); + VCALL_PARRMEM1R(PackedVector3Array, Vector3, has); + VCALL_PARRMEM0(PackedVector3Array, Vector3, sort); VCALL_PARRMEM0(PackedVector3Array, Vector3, invert); VCALL_PARRMEM0R(PackedColorArray, Color, size); @@ -799,6 +813,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedColorArray, Color, remove); VCALL_PARRMEM1(PackedColorArray, Color, append); VCALL_PARRMEM1(PackedColorArray, Color, append_array); + VCALL_PARRMEM1R(PackedColorArray, Color, has); + VCALL_PARRMEM0(PackedColorArray, Color, sort); VCALL_PARRMEM0(PackedColorArray, Color, invert); #define VCALL_PTR0(m_type, m_method) \ @@ -826,6 +842,7 @@ struct _VariantCall { #define VCALL_PTR5R(m_type, m_method) \ static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); } + VCALL_PTR0R(AABB, abs); VCALL_PTR0R(AABB, get_area); VCALL_PTR0R(AABB, has_no_area); VCALL_PTR0R(AABB, has_no_surface); @@ -1388,7 +1405,7 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i return (int64_t(*p_args[0])); } case FLOAT: { - return real_t(*p_args[0]); + return double(*p_args[0]); } case STRING: { return String(*p_args[0]); @@ -1780,7 +1797,6 @@ void register_variant_methods() { ADDFUNC3R(STRING, INT, String, count, STRING, "what", INT, "from", INT, "to", varray(0, 0)); ADDFUNC3R(STRING, INT, String, countn, STRING, "what", INT, "from", INT, "to", varray(0, 0)); - ADDFUNC1R(STRING, INT, String, find_last, STRING, "what", varray()); ADDFUNC2R(STRING, INT, String, findn, STRING, "what", INT, "from", varray(0)); ADDFUNC2R(STRING, INT, String, rfind, STRING, "what", INT, "from", varray(-1)); ADDFUNC2R(STRING, INT, String, rfindn, STRING, "what", INT, "from", varray(-1)); @@ -1964,7 +1980,6 @@ void register_variant_methods() { ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray()); ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray()); - ADDFUNC0R(PLANE, VECTOR3, Plane, get_any_point, varray()); ADDFUNC1R(PLANE, BOOL, Plane, is_equal_approx, PLANE, "plane", varray()); ADDFUNC1R(PLANE, BOOL, Plane, is_point_over, VECTOR3, "point", varray()); ADDFUNC1R(PLANE, FLOAT, Plane, distance_to, VECTOR3, "point", varray()); @@ -2087,6 +2102,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_BYTE_ARRAY, INT, PackedByteArray, insert, INT, "idx", INT, "byte", varray()); ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_BYTE_ARRAY, BOOL, PackedByteArray, has, INT, "value", varray()); + ADDFUNC0(PACKED_BYTE_ARRAY, NIL, PackedByteArray, sort, varray()); ADDFUNC0(PACKED_BYTE_ARRAY, NIL, PackedByteArray, invert, varray()); ADDFUNC2R(PACKED_BYTE_ARRAY, PACKED_BYTE_ARRAY, PackedByteArray, subarray, INT, "from", INT, "to", varray()); @@ -2105,6 +2122,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_INT32_ARRAY, INT, PackedInt32Array, insert, INT, "idx", INT, "integer", varray()); ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_INT32_ARRAY, BOOL, PackedInt32Array, has, INT, "value", varray()); + ADDFUNC0(PACKED_INT32_ARRAY, NIL, PackedInt32Array, sort, varray()); ADDFUNC0(PACKED_INT32_ARRAY, NIL, PackedInt32Array, invert, varray()); ADDFUNC0R(PACKED_INT64_ARRAY, INT, PackedInt64Array, size, varray()); @@ -2116,6 +2135,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_INT64_ARRAY, INT, PackedInt64Array, insert, INT, "idx", INT, "integer", varray()); ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_INT64_ARRAY, BOOL, PackedInt64Array, has, INT, "value", varray()); + ADDFUNC0(PACKED_INT64_ARRAY, NIL, PackedInt64Array, sort, varray()); ADDFUNC0(PACKED_INT64_ARRAY, NIL, PackedInt64Array, invert, varray()); ADDFUNC0R(PACKED_FLOAT32_ARRAY, INT, PackedFloat32Array, size, varray()); @@ -2127,6 +2148,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_FLOAT32_ARRAY, INT, PackedFloat32Array, insert, INT, "idx", FLOAT, "value", varray()); ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_FLOAT32_ARRAY, BOOL, PackedFloat32Array, has, FLOAT, "value", varray()); + ADDFUNC0(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, sort, varray()); ADDFUNC0(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, invert, varray()); ADDFUNC0R(PACKED_FLOAT64_ARRAY, INT, PackedFloat64Array, size, varray()); @@ -2138,6 +2161,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_FLOAT64_ARRAY, INT, PackedFloat64Array, insert, INT, "idx", FLOAT, "value", varray()); ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_FLOAT64_ARRAY, BOOL, PackedFloat64Array, has, FLOAT, "value", varray()); + ADDFUNC0(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, sort, varray()); ADDFUNC0(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, invert, varray()); ADDFUNC0R(PACKED_STRING_ARRAY, INT, PackedStringArray, size, varray()); @@ -2149,6 +2174,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_STRING_ARRAY, INT, PackedStringArray, insert, INT, "idx", STRING, "string", varray()); ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_STRING_ARRAY, BOOL, PackedStringArray, has, STRING, "value", varray()); + ADDFUNC0(PACKED_STRING_ARRAY, NIL, PackedStringArray, sort, varray()); ADDFUNC0(PACKED_STRING_ARRAY, NIL, PackedStringArray, invert, varray()); ADDFUNC0R(PACKED_VECTOR2_ARRAY, INT, PackedVector2Array, size, varray()); @@ -2160,6 +2187,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_VECTOR2_ARRAY, INT, PackedVector2Array, insert, INT, "idx", VECTOR2, "vector2", varray()); ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_VECTOR2_ARRAY, BOOL, PackedVector2Array, has, VECTOR2, "value", varray()); + ADDFUNC0(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, sort, varray()); ADDFUNC0(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, invert, varray()); ADDFUNC0R(PACKED_VECTOR3_ARRAY, INT, PackedVector3Array, size, varray()); @@ -2171,6 +2200,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_VECTOR3_ARRAY, INT, PackedVector3Array, insert, INT, "idx", VECTOR3, "vector3", varray()); ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_VECTOR3_ARRAY, BOOL, PackedVector3Array, has, VECTOR3, "value", varray()); + ADDFUNC0(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, sort, varray()); ADDFUNC0(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, invert, varray()); ADDFUNC0R(PACKED_COLOR_ARRAY, INT, PackedColorArray, size, varray()); @@ -2182,10 +2213,13 @@ void register_variant_methods() { ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_COLOR_ARRAY, INT, PackedColorArray, insert, INT, "idx", COLOR, "color", varray()); ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_COLOR_ARRAY, BOOL, PackedColorArray, has, COLOR, "value", varray()); + ADDFUNC0(PACKED_COLOR_ARRAY, NIL, PackedColorArray, sort, varray()); ADDFUNC0(PACKED_COLOR_ARRAY, NIL, PackedColorArray, invert, varray()); //pointerbased + ADDFUNC0R(AABB, AABB, AABB, abs, varray()); ADDFUNC0R(AABB, FLOAT, AABB, get_area, varray()); ADDFUNC0R(AABB, BOOL, AABB, has_no_area, varray()); ADDFUNC0R(AABB, BOOL, AABB, has_no_surface, varray()); @@ -2316,9 +2350,9 @@ void register_variant_methods() { _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1)); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3::AXIS_Z); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3i::AXIS_X); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y); + _VariantCall::add_constant(Variant::VECTOR3I, "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)); @@ -2332,8 +2366,8 @@ void register_variant_methods() { _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X); _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR2I, "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_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1)); diff --git a/core/variant_internal.h b/core/variant_internal.h new file mode 100644 index 0000000000..0e0a1e398f --- /dev/null +++ b/core/variant_internal.h @@ -0,0 +1,118 @@ +/*************************************************************************/ +/* variant_internal.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 VARIANT_INTERNAL_H +#define VARIANT_INTERNAL_H + +#include "variant.h" + +// For use when you want to access the internal pointer of a Variant directly. +// Use with caution. You need to be sure that the type is correct. +class VariantInternal { +public: + // Set type. + _FORCE_INLINE_ static void initialize(Variant *v, Variant::Type p_type) { v->type = p_type; } + + // Atomic types. + _FORCE_INLINE_ static bool *get_bool(Variant *v) { return &v->_data._bool; } + _FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return &v->_data._bool; } + _FORCE_INLINE_ static int64_t *get_int(Variant *v) { return &v->_data._int; } + _FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return &v->_data._int; } + _FORCE_INLINE_ static double *get_float(Variant *v) { return &v->_data._float; } + _FORCE_INLINE_ static const double *get_float(const Variant *v) { return &v->_data._float; } + _FORCE_INLINE_ static String *get_string(Variant *v) { return reinterpret_cast<String *>(v->_data._mem); } + _FORCE_INLINE_ static const String *get_string(const Variant *v) { return reinterpret_cast<const String *>(v->_data._mem); } + + // Math types. + _FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return reinterpret_cast<Vector2 *>(v->_data._mem); } + _FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return reinterpret_cast<const Vector2 *>(v->_data._mem); } + _FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return reinterpret_cast<Vector2i *>(v->_data._mem); } + _FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return reinterpret_cast<const Vector2i *>(v->_data._mem); } + _FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return reinterpret_cast<Rect2 *>(v->_data._mem); } + _FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return reinterpret_cast<const Rect2 *>(v->_data._mem); } + _FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return reinterpret_cast<Rect2i *>(v->_data._mem); } + _FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return reinterpret_cast<const Rect2i *>(v->_data._mem); } + _FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return reinterpret_cast<Vector3 *>(v->_data._mem); } + _FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return reinterpret_cast<const Vector3 *>(v->_data._mem); } + _FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return reinterpret_cast<Vector3i *>(v->_data._mem); } + _FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return reinterpret_cast<const Vector3i *>(v->_data._mem); } + _FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return v->_data._transform2d; } + _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; } + _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); } + _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); } + _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); } + _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); } + _FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; } + _FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; } + _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; } + _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; } + _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; } + _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; } + + // Misc types. + _FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); } + _FORCE_INLINE_ static const Color *get_color(const Variant *v) { return reinterpret_cast<const Color *>(v->_data._mem); } + _FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return reinterpret_cast<StringName *>(v->_data._mem); } + _FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return reinterpret_cast<const StringName *>(v->_data._mem); } + _FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return reinterpret_cast<NodePath *>(v->_data._mem); } + _FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return reinterpret_cast<const NodePath *>(v->_data._mem); } + _FORCE_INLINE_ static RID *get_rid(Variant *v) { return reinterpret_cast<RID *>(v->_data._mem); } + _FORCE_INLINE_ static const RID *get_rid(const Variant *v) { return reinterpret_cast<const RID *>(v->_data._mem); } + _FORCE_INLINE_ static Callable *get_callable(Variant *v) { return reinterpret_cast<Callable *>(v->_data._mem); } + _FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return reinterpret_cast<const Callable *>(v->_data._mem); } + _FORCE_INLINE_ static Signal *get_signal(Variant *v) { return reinterpret_cast<Signal *>(v->_data._mem); } + _FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return reinterpret_cast<const Signal *>(v->_data._mem); } + _FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return reinterpret_cast<Dictionary *>(v->_data._mem); } + _FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return reinterpret_cast<const Dictionary *>(v->_data._mem); } + _FORCE_INLINE_ static Array *get_array(Variant *v) { return reinterpret_cast<Array *>(v->_data._mem); } + _FORCE_INLINE_ static const Array *get_array(const Variant *v) { return reinterpret_cast<const Array *>(v->_data._mem); } + + // Typed arrays. + _FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; } + _FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; } +}; + +#endif // VARIANT_INTERNAL_H diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 0c9a4a992a..0cb2fe29a1 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -118,32 +118,32 @@ /* clang-format on */ -#define CASES(PREFIX) static const void *switch_table_##PREFIX[25][Variant::VARIANT_MAX] = { \ - TYPES(PREFIX, OP_EQUAL), \ - TYPES(PREFIX, OP_NOT_EQUAL), \ - TYPES(PREFIX, OP_LESS), \ - TYPES(PREFIX, OP_LESS_EQUAL), \ - TYPES(PREFIX, OP_GREATER), \ - TYPES(PREFIX, OP_GREATER_EQUAL), \ - TYPES(PREFIX, OP_ADD), \ - TYPES(PREFIX, OP_SUBTRACT), \ - TYPES(PREFIX, OP_MULTIPLY), \ - TYPES(PREFIX, OP_DIVIDE), \ - TYPES(PREFIX, OP_NEGATE), \ - TYPES(PREFIX, OP_POSITIVE), \ - TYPES(PREFIX, OP_MODULE), \ - TYPES(PREFIX, OP_STRING_CONCAT), \ - TYPES(PREFIX, OP_SHIFT_LEFT), \ - TYPES(PREFIX, OP_SHIFT_RIGHT), \ - TYPES(PREFIX, OP_BIT_AND), \ - TYPES(PREFIX, OP_BIT_OR), \ - TYPES(PREFIX, OP_BIT_XOR), \ - TYPES(PREFIX, OP_BIT_NEGATE), \ - TYPES(PREFIX, OP_AND), \ - TYPES(PREFIX, OP_OR), \ - TYPES(PREFIX, OP_XOR), \ - TYPES(PREFIX, OP_NOT), \ - TYPES(PREFIX, OP_IN), \ +#define CASES(PREFIX) static const void *switch_table_##PREFIX[Variant::OP_MAX][Variant::VARIANT_MAX] = { \ + TYPES(PREFIX, OP_EQUAL), \ + TYPES(PREFIX, OP_NOT_EQUAL), \ + TYPES(PREFIX, OP_LESS), \ + TYPES(PREFIX, OP_LESS_EQUAL), \ + TYPES(PREFIX, OP_GREATER), \ + TYPES(PREFIX, OP_GREATER_EQUAL), \ + TYPES(PREFIX, OP_ADD), \ + TYPES(PREFIX, OP_SUBTRACT), \ + TYPES(PREFIX, OP_MULTIPLY), \ + TYPES(PREFIX, OP_DIVIDE), \ + TYPES(PREFIX, OP_NEGATE), \ + TYPES(PREFIX, OP_POSITIVE), \ + TYPES(PREFIX, OP_MODULE), \ + TYPES(PREFIX, OP_STRING_CONCAT), \ + TYPES(PREFIX, OP_SHIFT_LEFT), \ + TYPES(PREFIX, OP_SHIFT_RIGHT), \ + TYPES(PREFIX, OP_BIT_AND), \ + TYPES(PREFIX, OP_BIT_OR), \ + TYPES(PREFIX, OP_BIT_XOR), \ + TYPES(PREFIX, OP_BIT_NEGATE), \ + TYPES(PREFIX, OP_AND), \ + TYPES(PREFIX, OP_OR), \ + TYPES(PREFIX, OP_XOR), \ + TYPES(PREFIX, OP_NOT), \ + TYPES(PREFIX, OP_IN), \ } #define SWITCH(PREFIX, op, val) goto *switch_table_##PREFIX[op][val]; diff --git a/core/vector.h b/core/vector.h index 4c152fb084..5fb630c21c 100644 --- a/core/vector.h +++ b/core/vector.h @@ -92,6 +92,10 @@ public: void append_array(Vector<T> p_other); + bool has(const T &p_val) { + return find(p_val, 0) != -1; + } + template <class C> void sort_custom() { int len = _cowdata.size(); |