diff options
| author | 2022-07-15 19:45:35 +0200 | |
|---|---|---|
| committer | 2022-07-25 21:59:30 +0200 | |
| commit | 6c8e45618578de1406c0bf4a7f976bd4903c339c (patch) | |
| tree | 25b959db6f30fe75bf5c6fa667ed92af71117986 | |
| parent | Fix compilation on linux gcc (diff) | |
| download | yuzu-6c8e45618578de1406c0bf4a7f976bd4903c339c.tar.gz yuzu-6c8e45618578de1406c0bf4a7f976bd4903c339c.tar.xz yuzu-6c8e45618578de1406c0bf4a7f976bd4903c339c.zip | |
Address first part of review comments
Diffstat (limited to '')
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | externals/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | src/input_common/helpers/udp_protocol.h | 2 | ||||
| -rw-r--r-- | src/network/room.h | 2 | ||||
| -rw-r--r-- | src/web_service/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/web_service/verify_user_jwt.cpp | 60 | ||||
| -rw-r--r-- | src/web_service/verify_user_jwt.h | 25 | ||||
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 148 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/chat_room.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/direct_connect.cpp | 20 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/host_room.cpp | 45 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby.cpp | 18 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/state.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/uisettings.h | 22 |
16 files changed, 239 insertions, 133 deletions
diff --git a/.gitmodules b/.gitmodules index d8e04923a..26c6735cd 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -46,3 +46,6 @@ | |||
| 46 | [submodule "vcpkg"] | 46 | [submodule "vcpkg"] |
| 47 | path = externals/vcpkg | 47 | path = externals/vcpkg |
| 48 | url = https://github.com/Microsoft/vcpkg.git | 48 | url = https://github.com/Microsoft/vcpkg.git |
| 49 | [submodule "cpp-jwt"] | ||
| 50 | path = externals/cpp-jwt | ||
| 51 | url = https://github.com/arun11299/cpp-jwt.git | ||
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index b4570bb69..5b74a1773 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt | |||
| @@ -116,6 +116,11 @@ if (ENABLE_WEB_SERVICE) | |||
| 116 | if (WIN32) | 116 | if (WIN32) |
| 117 | target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32) | 117 | target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32) |
| 118 | endif() | 118 | endif() |
| 119 | |||
| 120 | # cpp-jwt | ||
| 121 | add_library(cpp-jwt INTERFACE) | ||
| 122 | target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include) | ||
| 123 | target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON) | ||
| 119 | endif() | 124 | endif() |
| 120 | 125 | ||
| 121 | # Opus | 126 | # Opus |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 48f5c1ee0..c1cc62a45 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -716,6 +716,11 @@ add_library(core STATIC | |||
| 716 | hle/service/vi/vi_u.h | 716 | hle/service/vi/vi_u.h |
| 717 | hle/service/wlan/wlan.cpp | 717 | hle/service/wlan/wlan.cpp |
| 718 | hle/service/wlan/wlan.h | 718 | hle/service/wlan/wlan.h |
| 719 | internal_network/network.cpp | ||
| 720 | internal_network/network.h | ||
| 721 | internal_network/network_interface.cpp | ||
| 722 | internal_network/network_interface.h | ||
| 723 | internal_network/sockets.h | ||
| 719 | loader/deconstructed_rom_directory.cpp | 724 | loader/deconstructed_rom_directory.cpp |
| 720 | loader/deconstructed_rom_directory.h | 725 | loader/deconstructed_rom_directory.h |
| 721 | loader/elf.cpp | 726 | loader/elf.cpp |
| @@ -743,11 +748,6 @@ add_library(core STATIC | |||
| 743 | memory/dmnt_cheat_vm.h | 748 | memory/dmnt_cheat_vm.h |
| 744 | memory.cpp | 749 | memory.cpp |
| 745 | memory.h | 750 | memory.h |
| 746 | internal_network/network.cpp | ||
| 747 | internal_network/network.h | ||
| 748 | internal_network/network_interface.cpp | ||
| 749 | internal_network/network_interface.h | ||
| 750 | internal_network/sockets.h | ||
| 751 | perf_stats.cpp | 751 | perf_stats.cpp |
| 752 | perf_stats.h | 752 | perf_stats.h |
| 753 | reporter.cpp | 753 | reporter.cpp |
diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h index 597f51cd3..889693e73 100644 --- a/src/input_common/helpers/udp_protocol.h +++ b/src/input_common/helpers/udp_protocol.h | |||
| @@ -85,7 +85,7 @@ enum RegisterFlags : u8 { | |||
| 85 | struct Version {}; | 85 | struct Version {}; |
| 86 | /** | 86 | /** |
| 87 | * Requests the server to send information about what controllers are plugged into the ports | 87 | * Requests the server to send information about what controllers are plugged into the ports |
| 88 | * In citra's case, we only have one controller, so for simplicity's sake, we can just send a | 88 | * In yuzu's case, we only have one controller, so for simplicity's sake, we can just send a |
| 89 | * request explicitly for the first controller port and leave it at that. In the future it would be | 89 | * request explicitly for the first controller port and leave it at that. In the future it would be |
| 90 | * nice to make this configurable | 90 | * nice to make this configurable |
| 91 | */ | 91 | */ |
diff --git a/src/network/room.h b/src/network/room.h index 5d4371c16..df2253bf8 100644 --- a/src/network/room.h +++ b/src/network/room.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace Network { | 14 | namespace Network { |
| 15 | 15 | ||
| 16 | constexpr u32 network_version = 4; ///< The version of this Room and RoomMember | 16 | constexpr u32 network_version = 1; ///< The version of this Room and RoomMember |
| 17 | 17 | ||
| 18 | constexpr u16 DefaultRoomPort = 24872; | 18 | constexpr u16 DefaultRoomPort = 24872; |
| 19 | 19 | ||
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index aff81f26d..753fb6e7a 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt | |||
| @@ -5,10 +5,12 @@ add_library(web_service STATIC | |||
| 5 | telemetry_json.h | 5 | telemetry_json.h |
| 6 | verify_login.cpp | 6 | verify_login.cpp |
| 7 | verify_login.h | 7 | verify_login.h |
| 8 | verify_user_jwt.cpp | ||
| 9 | verify_user_jwt.h | ||
| 8 | web_backend.cpp | 10 | web_backend.cpp |
| 9 | web_backend.h | 11 | web_backend.h |
| 10 | web_result.h | 12 | web_result.h |
| 11 | ) | 13 | ) |
| 12 | 14 | ||
| 13 | create_target_directory_groups(web_service) | 15 | create_target_directory_groups(web_service) |
| 14 | target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib) | 16 | target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib cpp-jwt) |
diff --git a/src/web_service/verify_user_jwt.cpp b/src/web_service/verify_user_jwt.cpp new file mode 100644 index 000000000..78fe7bed5 --- /dev/null +++ b/src/web_service/verify_user_jwt.cpp | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <system_error> | ||
| 6 | #include <jwt/jwt.hpp> | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "web_service/verify_user_jwt.h" | ||
| 9 | #include "web_service/web_backend.h" | ||
| 10 | #include "web_service/web_result.h" | ||
| 11 | |||
| 12 | namespace WebService { | ||
| 13 | |||
| 14 | static std::string public_key; | ||
| 15 | std::string GetPublicKey(const std::string& host) { | ||
| 16 | if (public_key.empty()) { | ||
| 17 | Client client(host, "", ""); // no need for credentials here | ||
| 18 | public_key = client.GetPlain("/jwt/external/key.pem", true).returned_data; | ||
| 19 | if (public_key.empty()) { | ||
| 20 | LOG_ERROR(WebService, "Could not fetch external JWT public key, verification may fail"); | ||
| 21 | } else { | ||
| 22 | LOG_INFO(WebService, "Fetched external JWT public key (size={})", public_key.size()); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | return public_key; | ||
| 26 | } | ||
| 27 | |||
| 28 | VerifyUserJWT::VerifyUserJWT(const std::string& host) : pub_key(GetPublicKey(host)) {} | ||
| 29 | |||
| 30 | Network::VerifyUser::UserData VerifyUserJWT::LoadUserData(const std::string& verify_UID, | ||
| 31 | const std::string& token) { | ||
| 32 | const std::string audience = fmt::format("external-{}", verify_UID); | ||
| 33 | using namespace jwt::params; | ||
| 34 | std::error_code error; | ||
| 35 | auto decoded = | ||
| 36 | jwt::decode(token, algorithms({"rs256"}), error, secret(pub_key), issuer("yuzu-core"), | ||
| 37 | aud(audience), validate_iat(true), validate_jti(true)); | ||
| 38 | if (error) { | ||
| 39 | LOG_INFO(WebService, "Verification failed: category={}, code={}, message={}", | ||
| 40 | error.category().name(), error.value(), error.message()); | ||
| 41 | return {}; | ||
| 42 | } | ||
| 43 | Network::VerifyUser::UserData user_data{}; | ||
| 44 | if (decoded.payload().has_claim("username")) { | ||
| 45 | user_data.username = decoded.payload().get_claim_value<std::string>("username"); | ||
| 46 | } | ||
| 47 | if (decoded.payload().has_claim("displayName")) { | ||
| 48 | user_data.display_name = decoded.payload().get_claim_value<std::string>("displayName"); | ||
| 49 | } | ||
| 50 | if (decoded.payload().has_claim("avatarUrl")) { | ||
| 51 | user_data.avatar_url = decoded.payload().get_claim_value<std::string>("avatarUrl"); | ||
| 52 | } | ||
| 53 | if (decoded.payload().has_claim("roles")) { | ||
| 54 | auto roles = decoded.payload().get_claim_value<std::vector<std::string>>("roles"); | ||
| 55 | user_data.moderator = std::find(roles.begin(), roles.end(), "moderator") != roles.end(); | ||
| 56 | } | ||
| 57 | return user_data; | ||
| 58 | } | ||
| 59 | |||
| 60 | } // namespace WebService | ||
diff --git a/src/web_service/verify_user_jwt.h b/src/web_service/verify_user_jwt.h new file mode 100644 index 000000000..826e01eed --- /dev/null +++ b/src/web_service/verify_user_jwt.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <fmt/format.h> | ||
| 8 | #include "network/verify_user.h" | ||
| 9 | #include "web_service/web_backend.h" | ||
| 10 | |||
| 11 | namespace WebService { | ||
| 12 | |||
| 13 | class VerifyUserJWT final : public Network::VerifyUser::Backend { | ||
| 14 | public: | ||
| 15 | VerifyUserJWT(const std::string& host); | ||
| 16 | ~VerifyUserJWT() = default; | ||
| 17 | |||
| 18 | Network::VerifyUser::UserData LoadUserData(const std::string& verify_UID, | ||
| 19 | const std::string& token) override; | ||
| 20 | |||
| 21 | private: | ||
| 22 | std::string pub_key; | ||
| 23 | }; | ||
| 24 | |||
| 25 | } // namespace WebService | ||
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f3cad8f31..66873143e 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -326,6 +326,10 @@ if (USE_DISCORD_PRESENCE) | |||
| 326 | target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) | 326 | target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) |
| 327 | endif() | 327 | endif() |
| 328 | 328 | ||
| 329 | if (ENABLE_WEB_SERVICE) | ||
| 330 | target_compile_definitions(yuzu PRIVATE -DENABLE_WEB_SERVICE) | ||
| 331 | endif() | ||
| 332 | |||
| 329 | if (YUZU_USE_QT_WEB_ENGINE) | 333 | if (YUZU_USE_QT_WEB_ENGINE) |
| 330 | target_link_libraries(yuzu PRIVATE Qt::WebEngineCore Qt::WebEngineWidgets) | 334 | target_link_libraries(yuzu PRIVATE Qt::WebEngineCore Qt::WebEngineWidgets) |
| 331 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) | 335 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7c11e2c03..3b22102a8 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -585,48 +585,6 @@ void Config::ReadMiscellaneousValues() { | |||
| 585 | qt_config->endGroup(); | 585 | qt_config->endGroup(); |
| 586 | } | 586 | } |
| 587 | 587 | ||
| 588 | void Config::ReadMultiplayerValues() { | ||
| 589 | qt_config->beginGroup(QStringLiteral("Multiplayer")); | ||
| 590 | |||
| 591 | UISettings::values.nickname = ReadSetting(QStringLiteral("nickname"), QString{}).toString(); | ||
| 592 | UISettings::values.ip = ReadSetting(QStringLiteral("ip"), QString{}).toString(); | ||
| 593 | UISettings::values.port = | ||
| 594 | ReadSetting(QStringLiteral("port"), Network::DefaultRoomPort).toString(); | ||
| 595 | UISettings::values.room_nickname = | ||
| 596 | ReadSetting(QStringLiteral("room_nickname"), QString{}).toString(); | ||
| 597 | UISettings::values.room_name = ReadSetting(QStringLiteral("room_name"), QString{}).toString(); | ||
| 598 | UISettings::values.room_port = | ||
| 599 | ReadSetting(QStringLiteral("room_port"), QStringLiteral("24872")).toString(); | ||
| 600 | bool ok; | ||
| 601 | UISettings::values.host_type = ReadSetting(QStringLiteral("host_type"), 0).toUInt(&ok); | ||
| 602 | if (!ok) { | ||
| 603 | UISettings::values.host_type = 0; | ||
| 604 | } | ||
| 605 | UISettings::values.max_player = ReadSetting(QStringLiteral("max_player"), 8).toUInt(); | ||
| 606 | UISettings::values.game_id = ReadSetting(QStringLiteral("game_id"), 0).toULongLong(); | ||
| 607 | UISettings::values.room_description = | ||
| 608 | ReadSetting(QStringLiteral("room_description"), QString{}).toString(); | ||
| 609 | // Read ban list back | ||
| 610 | int size = qt_config->beginReadArray(QStringLiteral("username_ban_list")); | ||
| 611 | UISettings::values.ban_list.first.resize(size); | ||
| 612 | for (int i = 0; i < size; ++i) { | ||
| 613 | qt_config->setArrayIndex(i); | ||
| 614 | UISettings::values.ban_list.first[i] = | ||
| 615 | ReadSetting(QStringLiteral("username")).toString().toStdString(); | ||
| 616 | } | ||
| 617 | qt_config->endArray(); | ||
| 618 | size = qt_config->beginReadArray(QStringLiteral("ip_ban_list")); | ||
| 619 | UISettings::values.ban_list.second.resize(size); | ||
| 620 | for (int i = 0; i < size; ++i) { | ||
| 621 | qt_config->setArrayIndex(i); | ||
| 622 | UISettings::values.ban_list.second[i] = | ||
| 623 | ReadSetting(QStringLiteral("ip")).toString().toStdString(); | ||
| 624 | } | ||
| 625 | qt_config->endArray(); | ||
| 626 | |||
| 627 | qt_config->endGroup(); | ||
| 628 | } | ||
| 629 | |||
| 630 | void Config::ReadPathValues() { | 588 | void Config::ReadPathValues() { |
| 631 | qt_config->beginGroup(QStringLiteral("Paths")); | 589 | qt_config->beginGroup(QStringLiteral("Paths")); |
| 632 | 590 | ||
| @@ -904,6 +862,42 @@ void Config::ReadWebServiceValues() { | |||
| 904 | qt_config->endGroup(); | 862 | qt_config->endGroup(); |
| 905 | } | 863 | } |
| 906 | 864 | ||
| 865 | void Config::ReadMultiplayerValues() { | ||
| 866 | qt_config->beginGroup(QStringLiteral("Multiplayer")); | ||
| 867 | |||
| 868 | ReadBasicSetting(UISettings::values.multiplayer_nickname); | ||
| 869 | ReadBasicSetting(UISettings::values.multiplayer_ip); | ||
| 870 | ReadBasicSetting(UISettings::values.multiplayer_port); | ||
| 871 | ReadBasicSetting(UISettings::values.multiplayer_room_nickname); | ||
| 872 | ReadBasicSetting(UISettings::values.multiplayer_room_name); | ||
| 873 | ReadBasicSetting(UISettings::values.multiplayer_room_port); | ||
| 874 | ReadBasicSetting(UISettings::values.multiplayer_host_type); | ||
| 875 | ReadBasicSetting(UISettings::values.multiplayer_port); | ||
| 876 | ReadBasicSetting(UISettings::values.multiplayer_max_player); | ||
| 877 | ReadBasicSetting(UISettings::values.multiplayer_game_id); | ||
| 878 | ReadBasicSetting(UISettings::values.multiplayer_room_description); | ||
| 879 | |||
| 880 | // Read ban list back | ||
| 881 | int size = qt_config->beginReadArray(QStringLiteral("username_ban_list")); | ||
| 882 | UISettings::values.multiplayer_ban_list.first.resize(size); | ||
| 883 | for (int i = 0; i < size; ++i) { | ||
| 884 | qt_config->setArrayIndex(i); | ||
| 885 | UISettings::values.multiplayer_ban_list.first[i] = | ||
| 886 | ReadSetting(QStringLiteral("username")).toString().toStdString(); | ||
| 887 | } | ||
| 888 | qt_config->endArray(); | ||
| 889 | size = qt_config->beginReadArray(QStringLiteral("ip_ban_list")); | ||
| 890 | UISettings::values.multiplayer_ban_list.second.resize(size); | ||
| 891 | for (int i = 0; i < size; ++i) { | ||
| 892 | qt_config->setArrayIndex(i); | ||
| 893 | UISettings::values.multiplayer_ban_list.second[i] = | ||
| 894 | ReadSetting(QStringLiteral("ip")).toString().toStdString(); | ||
| 895 | } | ||
| 896 | qt_config->endArray(); | ||
| 897 | |||
| 898 | qt_config->endGroup(); | ||
| 899 | } | ||
| 900 | |||
| 907 | void Config::ReadValues() { | 901 | void Config::ReadValues() { |
| 908 | if (global) { | 902 | if (global) { |
| 909 | ReadControlValues(); | 903 | ReadControlValues(); |
| @@ -920,6 +914,7 @@ void Config::ReadValues() { | |||
| 920 | ReadRendererValues(); | 914 | ReadRendererValues(); |
| 921 | ReadAudioValues(); | 915 | ReadAudioValues(); |
| 922 | ReadSystemValues(); | 916 | ReadSystemValues(); |
| 917 | ReadMultiplayerValues(); | ||
| 923 | } | 918 | } |
| 924 | 919 | ||
| 925 | void Config::SavePlayerValue(std::size_t player_index) { | 920 | void Config::SavePlayerValue(std::size_t player_index) { |
| @@ -1069,6 +1064,7 @@ void Config::SaveValues() { | |||
| 1069 | SaveRendererValues(); | 1064 | SaveRendererValues(); |
| 1070 | SaveAudioValues(); | 1065 | SaveAudioValues(); |
| 1071 | SaveSystemValues(); | 1066 | SaveSystemValues(); |
| 1067 | SaveMultiplayerValues(); | ||
| 1072 | } | 1068 | } |
| 1073 | 1069 | ||
| 1074 | void Config::SaveAudioValues() { | 1070 | void Config::SaveAudioValues() { |
| @@ -1205,40 +1201,6 @@ void Config::SaveMiscellaneousValues() { | |||
| 1205 | qt_config->endGroup(); | 1201 | qt_config->endGroup(); |
| 1206 | } | 1202 | } |
| 1207 | 1203 | ||
| 1208 | void Config::SaveMultiplayerValues() { | ||
| 1209 | qt_config->beginGroup(QStringLiteral("Multiplayer")); | ||
| 1210 | |||
| 1211 | WriteSetting(QStringLiteral("nickname"), UISettings::values.nickname, QString{}); | ||
| 1212 | WriteSetting(QStringLiteral("ip"), UISettings::values.ip, QString{}); | ||
| 1213 | WriteSetting(QStringLiteral("port"), UISettings::values.port, Network::DefaultRoomPort); | ||
| 1214 | WriteSetting(QStringLiteral("room_nickname"), UISettings::values.room_nickname, QString{}); | ||
| 1215 | WriteSetting(QStringLiteral("room_name"), UISettings::values.room_name, QString{}); | ||
| 1216 | WriteSetting(QStringLiteral("room_port"), UISettings::values.room_port, | ||
| 1217 | QStringLiteral("24872")); | ||
| 1218 | WriteSetting(QStringLiteral("host_type"), UISettings::values.host_type, 0); | ||
| 1219 | WriteSetting(QStringLiteral("max_player"), UISettings::values.max_player, 8); | ||
| 1220 | WriteSetting(QStringLiteral("game_id"), UISettings::values.game_id, 0); | ||
| 1221 | WriteSetting(QStringLiteral("room_description"), UISettings::values.room_description, | ||
| 1222 | QString{}); | ||
| 1223 | // Write ban list | ||
| 1224 | qt_config->beginWriteArray(QStringLiteral("username_ban_list")); | ||
| 1225 | for (std::size_t i = 0; i < UISettings::values.ban_list.first.size(); ++i) { | ||
| 1226 | qt_config->setArrayIndex(static_cast<int>(i)); | ||
| 1227 | WriteSetting(QStringLiteral("username"), | ||
| 1228 | QString::fromStdString(UISettings::values.ban_list.first[i])); | ||
| 1229 | } | ||
| 1230 | qt_config->endArray(); | ||
| 1231 | qt_config->beginWriteArray(QStringLiteral("ip_ban_list")); | ||
| 1232 | for (std::size_t i = 0; i < UISettings::values.ban_list.second.size(); ++i) { | ||
| 1233 | qt_config->setArrayIndex(static_cast<int>(i)); | ||
| 1234 | WriteSetting(QStringLiteral("ip"), | ||
| 1235 | QString::fromStdString(UISettings::values.ban_list.second[i])); | ||
| 1236 | } | ||
| 1237 | qt_config->endArray(); | ||
| 1238 | |||
| 1239 | qt_config->endGroup(); | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | void Config::SavePathValues() { | 1204 | void Config::SavePathValues() { |
| 1243 | qt_config->beginGroup(QStringLiteral("Paths")); | 1205 | qt_config->beginGroup(QStringLiteral("Paths")); |
| 1244 | 1206 | ||
| @@ -1490,6 +1452,40 @@ void Config::SaveWebServiceValues() { | |||
| 1490 | qt_config->endGroup(); | 1452 | qt_config->endGroup(); |
| 1491 | } | 1453 | } |
| 1492 | 1454 | ||
| 1455 | void Config::SaveMultiplayerValues() { | ||
| 1456 | qt_config->beginGroup(QStringLiteral("Multiplayer")); | ||
| 1457 | |||
| 1458 | WriteBasicSetting(UISettings::values.multiplayer_nickname); | ||
| 1459 | WriteBasicSetting(UISettings::values.multiplayer_ip); | ||
| 1460 | WriteBasicSetting(UISettings::values.multiplayer_port); | ||
| 1461 | WriteBasicSetting(UISettings::values.multiplayer_room_nickname); | ||
| 1462 | WriteBasicSetting(UISettings::values.multiplayer_room_name); | ||
| 1463 | WriteBasicSetting(UISettings::values.multiplayer_room_port); | ||
| 1464 | WriteBasicSetting(UISettings::values.multiplayer_host_type); | ||
| 1465 | WriteBasicSetting(UISettings::values.multiplayer_port); | ||
| 1466 | WriteBasicSetting(UISettings::values.multiplayer_max_player); | ||
| 1467 | WriteBasicSetting(UISettings::values.multiplayer_game_id); | ||
| 1468 | WriteBasicSetting(UISettings::values.multiplayer_room_description); | ||
| 1469 | |||
| 1470 | // Write ban list | ||
| 1471 | qt_config->beginWriteArray(QStringLiteral("username_ban_list")); | ||
| 1472 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { | ||
| 1473 | qt_config->setArrayIndex(static_cast<int>(i)); | ||
| 1474 | WriteSetting(QStringLiteral("username"), | ||
| 1475 | QString::fromStdString(UISettings::values.multiplayer_ban_list.first[i])); | ||
| 1476 | } | ||
| 1477 | qt_config->endArray(); | ||
| 1478 | qt_config->beginWriteArray(QStringLiteral("ip_ban_list")); | ||
| 1479 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { | ||
| 1480 | qt_config->setArrayIndex(static_cast<int>(i)); | ||
| 1481 | WriteSetting(QStringLiteral("ip"), | ||
| 1482 | QString::fromStdString(UISettings::values.multiplayer_ban_list.second[i])); | ||
| 1483 | } | ||
| 1484 | qt_config->endArray(); | ||
| 1485 | |||
| 1486 | qt_config->endGroup(); | ||
| 1487 | } | ||
| 1488 | |||
| 1493 | QVariant Config::ReadSetting(const QString& name) const { | 1489 | QVariant Config::ReadSetting(const QString& name) const { |
| 1494 | return qt_config->value(name); | 1490 | return qt_config->value(name); |
| 1495 | } | 1491 | } |
diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp index 6dd4bc36d..7048ee1fc 100644 --- a/src/yuzu/multiplayer/chat_room.cpp +++ b/src/yuzu/multiplayer/chat_room.cpp | |||
| @@ -390,7 +390,7 @@ void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list) | |||
| 390 | return; | 390 | return; |
| 391 | QPixmap pixmap; | 391 | QPixmap pixmap; |
| 392 | if (!pixmap.loadFromData(reinterpret_cast<const u8*>(result.data()), | 392 | if (!pixmap.loadFromData(reinterpret_cast<const u8*>(result.data()), |
| 393 | result.size())) | 393 | static_cast<uint>(result.size()))) |
| 394 | return; | 394 | return; |
| 395 | icon_cache[avatar_url] = | 395 | icon_cache[avatar_url] = |
| 396 | pixmap.scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); | 396 | pixmap.scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); |
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index 27741d657..837baf85c 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp | |||
| @@ -32,15 +32,15 @@ DirectConnectWindow::DirectConnectWindow(QWidget* parent) | |||
| 32 | connect(watcher, &QFutureWatcher<void>::finished, this, &DirectConnectWindow::OnConnection); | 32 | connect(watcher, &QFutureWatcher<void>::finished, this, &DirectConnectWindow::OnConnection); |
| 33 | 33 | ||
| 34 | ui->nickname->setValidator(validation.GetNickname()); | 34 | ui->nickname->setValidator(validation.GetNickname()); |
| 35 | ui->nickname->setText(UISettings::values.nickname); | 35 | ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue()); |
| 36 | if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { | 36 | if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { |
| 37 | // Use yuzu Web Service user name as nickname by default | 37 | // Use yuzu Web Service user name as nickname by default |
| 38 | ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); | 38 | ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); |
| 39 | } | 39 | } |
| 40 | ui->ip->setValidator(validation.GetIP()); | 40 | ui->ip->setValidator(validation.GetIP()); |
| 41 | ui->ip->setText(UISettings::values.ip); | 41 | ui->ip->setText(UISettings::values.multiplayer_ip.GetValue()); |
| 42 | ui->port->setValidator(validation.GetPort()); | 42 | ui->port->setValidator(validation.GetPort()); |
| 43 | ui->port->setText(UISettings::values.port); | 43 | ui->port->setText(QString::number(UISettings::values.multiplayer_port.GetValue())); |
| 44 | 44 | ||
| 45 | // TODO(jroweboy): Show or hide the connection options based on the current value of the combo | 45 | // TODO(jroweboy): Show or hide the connection options based on the current value of the combo |
| 46 | // box. Add this back in when the traversal server support is added. | 46 | // box. Add this back in when the traversal server support is added. |
| @@ -86,16 +86,18 @@ void DirectConnectWindow::Connect() { | |||
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | // Store settings | 88 | // Store settings |
| 89 | UISettings::values.nickname = ui->nickname->text(); | 89 | UISettings::values.multiplayer_nickname = ui->nickname->text(); |
| 90 | UISettings::values.ip = ui->ip->text(); | 90 | UISettings::values.multiplayer_ip = ui->ip->text(); |
| 91 | UISettings::values.port = (ui->port->isModified() && !ui->port->text().isEmpty()) | 91 | if (ui->port->isModified() && !ui->port->text().isEmpty()) { |
| 92 | ? ui->port->text() | 92 | UISettings::values.multiplayer_port = ui->port->text().toInt(); |
| 93 | : UISettings::values.port; | 93 | } else { |
| 94 | UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault(); | ||
| 95 | } | ||
| 94 | 96 | ||
| 95 | // attempt to connect in a different thread | 97 | // attempt to connect in a different thread |
| 96 | QFuture<void> f = QtConcurrent::run([&] { | 98 | QFuture<void> f = QtConcurrent::run([&] { |
| 97 | if (auto room_member = Network::GetRoomMember().lock()) { | 99 | if (auto room_member = Network::GetRoomMember().lock()) { |
| 98 | auto port = UISettings::values.port.toUInt(); | 100 | auto port = UISettings::values.multiplayer_port.GetValue(); |
| 99 | room_member->Join(ui->nickname->text().toStdString(), "", | 101 | room_member->Join(ui->nickname->text().toStdString(), "", |
| 100 | ui->ip->text().toStdString().c_str(), port, 0, | 102 | ui->ip->text().toStdString().c_str(), port, 0, |
| 101 | Network::NoPreferredMac, ui->password->text().toStdString().c_str()); | 103 | Network::NoPreferredMac, ui->password->text().toStdString().c_str()); |
diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index 1b73e2bec..5470b8b86 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp | |||
| @@ -51,23 +51,24 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list, | |||
| 51 | connect(ui->host, &QPushButton::clicked, this, &HostRoomWindow::Host); | 51 | connect(ui->host, &QPushButton::clicked, this, &HostRoomWindow::Host); |
| 52 | 52 | ||
| 53 | // Restore the settings: | 53 | // Restore the settings: |
| 54 | ui->username->setText(UISettings::values.room_nickname); | 54 | ui->username->setText(UISettings::values.multiplayer_room_nickname.GetValue()); |
| 55 | if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { | 55 | if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { |
| 56 | // Use yuzu Web Service user name as nickname by default | 56 | // Use yuzu Web Service user name as nickname by default |
| 57 | ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); | 57 | ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); |
| 58 | } | 58 | } |
| 59 | ui->room_name->setText(UISettings::values.room_name); | 59 | ui->room_name->setText(UISettings::values.multiplayer_room_name.GetValue()); |
| 60 | ui->port->setText(UISettings::values.room_port); | 60 | ui->port->setText(QString::number(UISettings::values.multiplayer_room_port.GetValue())); |
| 61 | ui->max_player->setValue(UISettings::values.max_player); | 61 | ui->max_player->setValue(UISettings::values.multiplayer_max_player.GetValue()); |
| 62 | int index = UISettings::values.host_type; | 62 | int index = UISettings::values.multiplayer_host_type.GetValue(); |
| 63 | if (index < ui->host_type->count()) { | 63 | if (index < ui->host_type->count()) { |
| 64 | ui->host_type->setCurrentIndex(index); | 64 | ui->host_type->setCurrentIndex(index); |
| 65 | } | 65 | } |
| 66 | index = ui->game_list->findData(UISettings::values.game_id, GameListItemPath::ProgramIdRole); | 66 | index = ui->game_list->findData(UISettings::values.multiplayer_game_id.GetValue(), |
| 67 | GameListItemPath::ProgramIdRole); | ||
| 67 | if (index != -1) { | 68 | if (index != -1) { |
| 68 | ui->game_list->setCurrentIndex(index); | 69 | ui->game_list->setCurrentIndex(index); |
| 69 | } | 70 | } |
| 70 | ui->room_description->setText(UISettings::values.room_description); | 71 | ui->room_description->setText(UISettings::values.multiplayer_room_description.GetValue()); |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | HostRoomWindow::~HostRoomWindow() = default; | 74 | HostRoomWindow::~HostRoomWindow() = default; |
| @@ -91,7 +92,8 @@ std::unique_ptr<Network::VerifyUser::Backend> HostRoomWindow::CreateVerifyBacken | |||
| 91 | std::unique_ptr<Network::VerifyUser::Backend> verify_backend; | 92 | std::unique_ptr<Network::VerifyUser::Backend> verify_backend; |
| 92 | if (use_validation) { | 93 | if (use_validation) { |
| 93 | #ifdef ENABLE_WEB_SERVICE | 94 | #ifdef ENABLE_WEB_SERVICE |
| 94 | verify_backend = std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url); | 95 | verify_backend = |
| 96 | std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url.GetValue()); | ||
| 95 | #else | 97 | #else |
| 96 | verify_backend = std::make_unique<Network::VerifyUser::NullBackend>(); | 98 | verify_backend = std::make_unique<Network::VerifyUser::NullBackend>(); |
| 97 | #endif | 99 | #endif |
| @@ -137,7 +139,7 @@ void HostRoomWindow::Host() { | |||
| 137 | const bool is_public = ui->host_type->currentIndex() == 0; | 139 | const bool is_public = ui->host_type->currentIndex() == 0; |
| 138 | Network::Room::BanList ban_list{}; | 140 | Network::Room::BanList ban_list{}; |
| 139 | if (ui->load_ban_list->isChecked()) { | 141 | if (ui->load_ban_list->isChecked()) { |
| 140 | ban_list = UISettings::values.ban_list; | 142 | ban_list = UISettings::values.multiplayer_ban_list; |
| 141 | } | 143 | } |
| 142 | if (auto room = Network::GetRoom().lock()) { | 144 | if (auto room = Network::GetRoom().lock()) { |
| 143 | bool created = room->Create( | 145 | bool created = room->Create( |
| @@ -181,8 +183,9 @@ void HostRoomWindow::Host() { | |||
| 181 | std::string token; | 183 | std::string token; |
| 182 | #ifdef ENABLE_WEB_SERVICE | 184 | #ifdef ENABLE_WEB_SERVICE |
| 183 | if (is_public) { | 185 | if (is_public) { |
| 184 | WebService::Client client(Settings::values.web_api_url, Settings::values.yuzu_username, | 186 | WebService::Client client(Settings::values.web_api_url.GetValue(), |
| 185 | Settings::values.yuzu_token); | 187 | Settings::values.yuzu_username.GetValue(), |
| 188 | Settings::values.yuzu_token.GetValue()); | ||
| 186 | if (auto room = Network::GetRoom().lock()) { | 189 | if (auto room = Network::GetRoom().lock()) { |
| 187 | token = client.GetExternalJWT(room->GetVerifyUID()).returned_data; | 190 | token = client.GetExternalJWT(room->GetVerifyUID()).returned_data; |
| 188 | } | 191 | } |
| @@ -198,17 +201,19 @@ void HostRoomWindow::Host() { | |||
| 198 | Network::NoPreferredMac, password, token); | 201 | Network::NoPreferredMac, password, token); |
| 199 | 202 | ||
| 200 | // Store settings | 203 | // Store settings |
| 201 | UISettings::values.room_nickname = ui->username->text(); | 204 | UISettings::values.multiplayer_room_nickname = ui->username->text(); |
| 202 | UISettings::values.room_name = ui->room_name->text(); | 205 | UISettings::values.multiplayer_room_name = ui->room_name->text(); |
| 203 | UISettings::values.game_id = | 206 | UISettings::values.multiplayer_game_id = |
| 204 | ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong(); | 207 | ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong(); |
| 205 | UISettings::values.max_player = ui->max_player->value(); | 208 | UISettings::values.multiplayer_max_player = ui->max_player->value(); |
| 206 | 209 | ||
| 207 | UISettings::values.host_type = ui->host_type->currentIndex(); | 210 | UISettings::values.multiplayer_host_type = ui->host_type->currentIndex(); |
| 208 | UISettings::values.room_port = (ui->port->isModified() && !ui->port->text().isEmpty()) | 211 | if (ui->port->isModified() && !ui->port->text().isEmpty()) { |
| 209 | ? ui->port->text() | 212 | UISettings::values.multiplayer_room_port = ui->port->text().toInt(); |
| 210 | : QString::number(Network::DefaultRoomPort); | 213 | } else { |
| 211 | UISettings::values.room_description = ui->room_description->toPlainText(); | 214 | UISettings::values.multiplayer_room_port = Network::DefaultRoomPort; |
| 215 | } | ||
| 216 | UISettings::values.multiplayer_room_description = ui->room_description->toPlainText(); | ||
| 212 | ui->host->setEnabled(true); | 217 | ui->host->setEnabled(true); |
| 213 | close(); | 218 | close(); |
| 214 | } | 219 | } |
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index fcaa7b517..364b4605e 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp | |||
| @@ -56,7 +56,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list, | |||
| 56 | ui->room_list->setContextMenuPolicy(Qt::CustomContextMenu); | 56 | ui->room_list->setContextMenuPolicy(Qt::CustomContextMenu); |
| 57 | 57 | ||
| 58 | ui->nickname->setValidator(validation.GetNickname()); | 58 | ui->nickname->setValidator(validation.GetNickname()); |
| 59 | ui->nickname->setText(UISettings::values.nickname); | 59 | ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue()); |
| 60 | if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { | 60 | if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { |
| 61 | // Use yuzu Web Service user name as nickname by default | 61 | // Use yuzu Web Service user name as nickname by default |
| 62 | ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); | 62 | ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); |
| @@ -154,9 +154,11 @@ void Lobby::OnJoinRoom(const QModelIndex& source) { | |||
| 154 | QFuture<void> f = QtConcurrent::run([nickname, ip, port, password, verify_UID] { | 154 | QFuture<void> f = QtConcurrent::run([nickname, ip, port, password, verify_UID] { |
| 155 | std::string token; | 155 | std::string token; |
| 156 | #ifdef ENABLE_WEB_SERVICE | 156 | #ifdef ENABLE_WEB_SERVICE |
| 157 | if (!Settings::values.yuzu_username.empty() && !Settings::values.yuzu_token.empty()) { | 157 | if (!Settings::values.yuzu_username.GetValue().empty() && |
| 158 | WebService::Client client(Settings::values.web_api_url, Settings::values.yuzu_username, | 158 | !Settings::values.yuzu_token.GetValue().empty()) { |
| 159 | Settings::values.yuzu_token); | 159 | WebService::Client client(Settings::values.web_api_url.GetValue(), |
| 160 | Settings::values.yuzu_username.GetValue(), | ||
| 161 | Settings::values.yuzu_token.GetValue()); | ||
| 160 | token = client.GetExternalJWT(verify_UID).returned_data; | 162 | token = client.GetExternalJWT(verify_UID).returned_data; |
| 161 | if (token.empty()) { | 163 | if (token.empty()) { |
| 162 | LOG_ERROR(WebService, "Could not get external JWT, verification may fail"); | 164 | LOG_ERROR(WebService, "Could not get external JWT, verification may fail"); |
| @@ -175,9 +177,11 @@ void Lobby::OnJoinRoom(const QModelIndex& source) { | |||
| 175 | // TODO(jroweboy): disable widgets and display a connecting while we wait | 177 | // TODO(jroweboy): disable widgets and display a connecting while we wait |
| 176 | 178 | ||
| 177 | // Save settings | 179 | // Save settings |
| 178 | UISettings::values.nickname = ui->nickname->text(); | 180 | UISettings::values.multiplayer_nickname = ui->nickname->text(); |
| 179 | UISettings::values.ip = proxy->data(connection_index, LobbyItemHost::HostIPRole).toString(); | 181 | UISettings::values.multiplayer_ip = |
| 180 | UISettings::values.port = proxy->data(connection_index, LobbyItemHost::HostPortRole).toString(); | 182 | proxy->data(connection_index, LobbyItemHost::HostIPRole).toString(); |
| 183 | UISettings::values.multiplayer_port = | ||
| 184 | proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt(); | ||
| 181 | } | 185 | } |
| 182 | 186 | ||
| 183 | void Lobby::ResetModel() { | 187 | void Lobby::ResetModel() { |
diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index e96b03e5d..ee138739b 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp | |||
| @@ -232,7 +232,7 @@ bool MultiplayerState::OnCloseRoom() { | |||
| 232 | return true; | 232 | return true; |
| 233 | } | 233 | } |
| 234 | // Save ban list | 234 | // Save ban list |
| 235 | UISettings::values.ban_list = std::move(room->GetBanList()); | 235 | UISettings::values.multiplayer_ban_list = std::move(room->GetBanList()); |
| 236 | 236 | ||
| 237 | room->Destroy(); | 237 | room->Destroy(); |
| 238 | announce_multiplayer_session->Stop(); | 238 | announce_multiplayer_session->Stop(); |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index aca1a28e1..83a6cffa3 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -103,17 +103,17 @@ struct Values { | |||
| 103 | Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"}; | 103 | Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"}; |
| 104 | 104 | ||
| 105 | // multiplayer settings | 105 | // multiplayer settings |
| 106 | QString nickname; | 106 | Settings::Setting<QString> multiplayer_nickname{QStringLiteral("yuzu"), "nickname"}; |
| 107 | QString ip; | 107 | Settings::Setting<QString> multiplayer_ip{{}, "ip"}; |
| 108 | QString port; | 108 | Settings::SwitchableSetting<uint> multiplayer_port{24872, 0, 65535, "port"}; |
| 109 | QString room_nickname; | 109 | Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"}; |
| 110 | QString room_name; | 110 | Settings::Setting<QString> multiplayer_room_name{{}, "room_name"}; |
| 111 | quint32 max_player; | 111 | Settings::SwitchableSetting<uint> multiplayer_max_player{8, 0, 8, "max_player"}; |
| 112 | QString room_port; | 112 | Settings::SwitchableSetting<uint> multiplayer_room_port{24872, 0, 65535, "room_port"}; |
| 113 | uint host_type; | 113 | Settings::SwitchableSetting<uint> multiplayer_host_type{0, 0, 1, "host_type"}; |
| 114 | qulonglong game_id; | 114 | Settings::Setting<qulonglong> multiplayer_game_id{{}, "game_id"}; |
| 115 | QString room_description; | 115 | Settings::Setting<QString> multiplayer_room_description{{}, "room_description"}; |
| 116 | std::pair<std::vector<std::string>, std::vector<std::string>> ban_list; | 116 | std::pair<std::vector<std::string>, std::vector<std::string>> multiplayer_ban_list; |
| 117 | 117 | ||
| 118 | // logging | 118 | // logging |
| 119 | Settings::Setting<bool> show_console{false, "showConsole"}; | 119 | Settings::Setting<bool> show_console{false, "showConsole"}; |