From 337d0ed51c0e72774cbdd5b5401de5abc566a256 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Sat, 3 Feb 2024 19:29:05 +0100 Subject: [PATCH] early-access version 4110 --- README.md | 2 +- src/CMakeLists.txt | 1 + src/common/hex_util.h | 3 +++ src/core/hle/service/am/self_controller.cpp | 15 ++++++++++- src/core/hle/service/am/self_controller.h | 2 ++ src/core/hle/service/cmif_serialization.h | 6 +++++ src/core/hle/service/cmif_types.h | 27 +++++++++++++++++-- .../hle/service/filesystem/fsp/fsp_srv.cpp | 9 +++++++ .../service/glue/time/time_zone_binary.cpp | 1 + .../service/nvdrv/devices/nvhost_as_gpu.cpp | 6 +++-- src/video_core/host1x/ffmpeg/ffmpeg.cpp | 11 ++++---- src/video_core/host1x/host1x.cpp | 2 +- src/video_core/memory_manager.cpp | 17 ++++++------ src/video_core/memory_manager.h | 8 +++--- src/yuzu/main.cpp | 7 +++++ src/yuzu/multiplayer/lobby.cpp | 13 ++++++++- src/yuzu/multiplayer/lobby_p.h | 25 ++++++++++++++--- src/yuzu/uisettings.h | 14 +++++++++- 18 files changed, 139 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 5a9980269..f38b09cb0 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 4109. +This is the source code for early-access 4110. ## Legal Notice diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 80aeef607..10aa8ad6e 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -164,6 +164,7 @@ else() if (MINGW) add_definitions(-DMINGW_HAS_SECURE_API) + add_compile_options("-msse4.1") if (MINGW_STATIC_BUILD) add_definitions(-DQT_STATICPLUGIN) diff --git a/src/common/hex_util.h b/src/common/hex_util.h index 966d9381c..ed9a9dad3 100755 --- a/src/common/hex_util.h +++ b/src/common/hex_util.h @@ -9,6 +9,7 @@ #include #include #include +#include "common/assert.h" #include "common/common_types.h" namespace Common { @@ -29,6 +30,8 @@ namespace Common { template [[nodiscard]] constexpr std::array HexStringToArray(std::string_view str) { + ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size"); + std::array out{}; if constexpr (le) { for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp index b92663b2b..65e249c0c 100755 --- a/src/core/hle/service/am/self_controller.cpp +++ b/src/core/hle/service/am/self_controller.cpp @@ -1,10 +1,13 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/logging/log.h" +#include "core/hle/result.h" #include "core/hle/service/am/am_results.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/self_controller.h" #include "core/hle/service/caps/caps_su.h" +#include "core/hle/service/hle_ipc.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" #include "core/hle/service/nvnflinger/nvnflinger.h" @@ -47,7 +50,7 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"}, {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, - {61, nullptr, "SetMediaPlaybackState"}, + {61, &ISelfController::SetMediaPlaybackState, "SetMediaPlaybackState"}, {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"}, {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"}, {64, nullptr, "SetInputDetectionSourceSet"}, @@ -324,6 +327,16 @@ void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void ISelfController::SetMediaPlaybackState(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u8 state = rp.Pop(); + + LOG_WARNING(Service_AM, "(STUBBED) called, state={}", state); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; diff --git a/src/core/hle/service/am/self_controller.h b/src/core/hle/service/am/self_controller.h index a63bc2e74..ab21a1881 100755 --- a/src/core/hle/service/am/self_controller.h +++ b/src/core/hle/service/am/self_controller.h @@ -3,6 +3,7 @@ #pragma once +#include "core/hle/service/hle_ipc.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/service.h" @@ -38,6 +39,7 @@ private: void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx); void SetHandlesRequestToDisplay(HLERequestContext& ctx); void ApproveToDisplay(HLERequestContext& ctx); + void SetMediaPlaybackState(HLERequestContext& ctx); void SetIdleTimeDetectionExtension(HLERequestContext& ctx); void GetIdleTimeDetectionExtension(HLERequestContext& ctx); void ReportUserIsActive(HLERequestContext& ctx); diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h index 315475e71..e985fe317 100755 --- a/src/core/hle/service/cmif_serialization.h +++ b/src/core/hle/service/cmif_serialization.h @@ -115,6 +115,11 @@ struct ArgumentTraits { static constexpr ArgumentType Type = ArgumentType::InData; }; +template +consteval bool ConstIfReference() { + return ((!std::is_reference_v || std::is_const_v>) && ... && true); +} + struct RequestLayout { u32 copy_handle_count; u32 move_handle_count; @@ -435,6 +440,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { } const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false; + static_assert(ConstIfReference(), "Arguments taken by reference must be const"); using MethodArguments = std::tuple...>; OutTemporaryBuffers buffers{}; diff --git a/src/core/hle/service/cmif_types.h b/src/core/hle/service/cmif_types.h index dc06169f4..84f4c2456 100755 --- a/src/core/hle/service/cmif_types.h +++ b/src/core/hle/service/cmif_types.h @@ -4,10 +4,9 @@ #pragma once #include +#include -#include "common/common_funcs.h" #include "common/common_types.h" -#include "core/hle/service/hle_ipc.h" namespace Service { @@ -22,8 +21,10 @@ class Out { public: using Type = T; + /* implicit */ Out(const Out& t) : raw(t.raw) {} /* implicit */ Out(AutoOut& t) : raw(&t.raw) {} /* implicit */ Out(Type* t) : raw(t) {} + Out& operator=(const Out&) = delete; Type* Get() const { return raw; @@ -37,6 +38,10 @@ public: return raw; } + operator Type*() const { + return raw; + } + private: Type* raw; }; @@ -113,8 +118,10 @@ class OutCopyHandle { public: using Type = T*; + /* implicit */ OutCopyHandle(const OutCopyHandle& t) : raw(t.raw) {} /* implicit */ OutCopyHandle(AutoOut& t) : raw(&t.raw) {} /* implicit */ OutCopyHandle(Type* t) : raw(t) {} + OutCopyHandle& operator=(const OutCopyHandle&) = delete; Type* Get() const { return raw; @@ -128,6 +135,10 @@ public: return raw; } + operator Type*() const { + return raw; + } + private: Type* raw; }; @@ -137,8 +148,10 @@ class OutMoveHandle { public: using Type = T*; + /* implicit */ OutMoveHandle(const OutMoveHandle& t) : raw(t.raw) {} /* implicit */ OutMoveHandle(AutoOut& t) : raw(&t.raw) {} /* implicit */ OutMoveHandle(Type* t) : raw(t) {} + OutMoveHandle& operator=(const OutMoveHandle&) = delete; Type* Get() const { return raw; @@ -152,6 +165,10 @@ public: return raw; } + operator Type*() const { + return raw; + } + private: Type* raw; }; @@ -248,8 +265,10 @@ public: static constexpr BufferAttr Attr = static_cast(A | BufferAttr_In | BufferAttr_FixedSize); using Type = T; + /* implicit */ OutLargeData(const OutLargeData& t) : raw(t.raw) {} /* implicit */ OutLargeData(Type* t) : raw(t) {} /* implicit */ OutLargeData(AutoOut& t) : raw(&t.raw) {} + OutLargeData& operator=(const OutLargeData&) = delete; Type* Get() const { return raw; @@ -263,6 +282,10 @@ public: return raw; } + operator Type*() const { + return raw; + } + private: Type* raw; }; diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp index 5fe534c73..63c2d3a58 100755 --- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp @@ -115,6 +115,11 @@ private: if (type->GetName() == "save") { for (const auto& save_id : type->GetSubdirectories()) { for (const auto& user_id : save_id->GetSubdirectories()) { + // Skip non user id subdirectories + if (user_id->GetName().size() != 0x20) { + continue; + } + const auto save_id_numeric = stoull_be(save_id->GetName()); auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); std::reverse(user_id_numeric.begin(), user_id_numeric.end()); @@ -160,6 +165,10 @@ private: } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { // Temporary Storage for (const auto& user_id : type->GetSubdirectories()) { + // Skip non user id subdirectories + if (user_id->GetName().size() != 0x20) { + continue; + } for (const auto& title_id : user_id->GetSubdirectories()) { if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) { diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp index d5f7ca3d2..18c6abd6b 100755 --- a/src/core/hle/service/glue/time/time_zone_binary.cpp +++ b/src/core/hle/service/glue/time/time_zone_binary.cpp @@ -65,6 +65,7 @@ Result MountTimeZoneBinary(Core::System& system) { // Validate that the romfs is readable, using invalid firmware keys can cause this to get // set but the files to be garbage. In that case, we want to hit the next path and // synthesise them instead. + g_time_zone_binary_mount_result = ResultSuccess; Service::PSC::Time::LocationName name{"Etc/GMT"}; if (!IsTimeZoneBinaryValid(name)) { ResetTimeZoneBinary(); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 7ef8e87f0..18cf0ab4b 100755 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -123,6 +123,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { vm.va_range_end = params.va_range_end; } + const u64 max_big_page_bits = Common::Log2Ceil64(vm.va_range_end); + const auto start_pages{static_cast(vm.va_range_start >> VM::PAGE_SIZE_BITS)}; const auto end_pages{static_cast(vm.va_range_split >> VM::PAGE_SIZE_BITS)}; vm.small_page_allocator = std::make_shared(start_pages, end_pages); @@ -132,8 +134,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { static_cast((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)}; vm.big_page_allocator = std::make_unique(start_big_pages, end_big_pages); - gmmu = std::make_shared(system, 40, vm.big_page_size_bits, - VM::PAGE_SIZE_BITS); + gmmu = std::make_shared(system, max_big_page_bits, vm.va_range_split, + vm.big_page_size_bits, VM::PAGE_SIZE_BITS); system.GPU().InitAddressSpace(*gmmu); vm.initialised = true; diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp index c80768ca3..d603bad8b 100755 --- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp +++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp @@ -134,7 +134,7 @@ bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context, const Decoder& decoder) { const auto supported_types = GetSupportedDeviceTypes(); for (const auto type : PreferredGpuDecoders) { - // AVPixelFormat hw_pix_fmt; + AVPixelFormat hw_pix_fmt; if (std::ranges::find(supported_types, type) == supported_types.end()) { LOG_DEBUG(HW_GPU, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); @@ -145,11 +145,10 @@ bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context, continue; } - // Disable GPU decoding as it cannot return decode frame ordering which breaks everything. - // if (decoder.SupportsDecodingOnDevice(&hw_pix_fmt, type)) { - // decoder_context.InitializeHardwareDecoder(*this, hw_pix_fmt); - // return true; - //} + if (decoder.SupportsDecodingOnDevice(&hw_pix_fmt, type)) { + decoder_context.InitializeHardwareDecoder(*this, hw_pix_fmt); + return true; + } } LOG_INFO(HW_GPU, "Hardware decoding is disabled due to implementation issues, using CPU."); diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp index 6bc85b9ed..25939b7a4 100755 --- a/src/video_core/host1x/host1x.cpp +++ b/src/video_core/host1x/host1x.cpp @@ -10,7 +10,7 @@ namespace Tegra::Host1x { Host1x::Host1x(Core::System& system_) : system{system_}, syncpoint_manager{}, - memory_manager(system.DeviceMemory()), gmmu_manager{system, memory_manager, 32, 12}, + memory_manager(system.DeviceMemory()), gmmu_manager{system, memory_manager, 32, 0, 12}, allocator{std::make_unique>(1 << 12)} {} Host1x::~Host1x() = default; diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 38bd727ec..a0e0b30d1 100755 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -22,11 +22,12 @@ using Tegra::Memory::GuestMemoryFlags; std::atomic MemoryManager::unique_identifier_generator{}; MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_, - u64 address_space_bits_, u64 big_page_bits_, u64 page_bits_) + u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_, + u64 page_bits_) : system{system_}, memory{memory_}, address_space_bits{address_space_bits_}, - page_bits{page_bits_}, big_page_bits{big_page_bits_}, entries{}, big_entries{}, - page_table{address_space_bits, address_space_bits + page_bits - 38, - page_bits != big_page_bits ? page_bits : 0}, + split_address{split_address_}, page_bits{page_bits_}, big_page_bits{big_page_bits_}, + entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38, + page_bits != big_page_bits ? page_bits : 0}, kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add( 1, std::memory_order_acq_rel)}, accumulator{std::make_unique()} { @@ -48,10 +49,10 @@ MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& entries.resize(page_table_size / 32, 0); } -MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 big_page_bits_, - u64 page_bits_) - : MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, big_page_bits_, - page_bits_) {} +MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, + GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_) + : MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, split_address_, + big_page_bits_, page_bits_) {} MemoryManager::~MemoryManager() = default; diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 9b312b112..eb3eb23eb 100755 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -36,10 +36,11 @@ namespace Tegra { class MemoryManager final { public: explicit MemoryManager(Core::System& system_, u64 address_space_bits_ = 40, - u64 big_page_bits_ = 16, u64 page_bits_ = 12); - explicit MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_, - u64 address_space_bits_ = 40, u64 big_page_bits_ = 16, + GPUVAddr split_address = 1ULL << 34, u64 big_page_bits_ = 16, u64 page_bits_ = 12); + explicit MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_, + u64 address_space_bits_ = 40, GPUVAddr split_address = 1ULL << 34, + u64 big_page_bits_ = 16, u64 page_bits_ = 12); ~MemoryManager(); static constexpr bool HAS_FLUSH_INVALIDATION = true; @@ -194,6 +195,7 @@ private: MaxwellDeviceMemoryManager& memory; const u64 address_space_bits; + GPUVAddr split_address; const u64 page_bits; u64 address_space_size; u64 page_size; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 13ae6bc6e..010dd82a8 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1353,6 +1353,13 @@ void GMainWindow::InitializeHotkeys() { LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true); LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true); LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true); + LinkActionShortcut(ui->action_View_Lobby, + QStringLiteral("Multiplayer Browse Public Game Lobby")); + LinkActionShortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room")); + LinkActionShortcut(ui->action_Connect_To_Room, + QStringLiteral("Multiplayer Direct Connect to Room")); + LinkActionShortcut(ui->action_Show_Room, QStringLiteral("Multiplayer Show Current Room")); + LinkActionShortcut(ui->action_Leave_Room, QStringLiteral("Multiplayer Leave Room")); static const QString main_window = QStringLiteral("Main Window"); const auto connect_shortcut = [&](const QString& action_name, const Fn& function) { diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index 65865ec3d..5eff13089 100755 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -77,16 +77,23 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list, // UI Buttons connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby); + connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch); connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned); connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty); connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull); - connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch); connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom); connect(ui->room_list, &QTreeView::clicked, this, &Lobby::OnExpandRoom); // Actions connect(&room_list_watcher, &QFutureWatcher::finished, this, &Lobby::OnRefreshLobby); + + // Load persistent filters after events are connected to make sure they apply + ui->search->setText( + QString::fromStdString(UISettings::values.multiplayer_filter_text.GetValue())); + ui->games_owned->setChecked(UISettings::values.multiplayer_filter_games_owned.GetValue()); + ui->hide_empty->setChecked(UISettings::values.multiplayer_filter_hide_empty.GetValue()); + ui->hide_full->setChecked(UISettings::values.multiplayer_filter_hide_full.GetValue()); } Lobby::~Lobby() = default; @@ -204,6 +211,10 @@ void Lobby::OnJoinRoom(const QModelIndex& source) { // Save settings UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString(); + UISettings::values.multiplayer_filter_text = ui->search->text().toStdString(); + UISettings::values.multiplayer_filter_games_owned = ui->games_owned->isChecked(); + UISettings::values.multiplayer_filter_hide_empty = ui->hide_empty->isChecked(); + UISettings::values.multiplayer_filter_hide_full = ui->hide_full->isChecked(); UISettings::values.multiplayer_ip = proxy->data(connection_index, LobbyItemHost::HostIPRole).value().toStdString(); UISettings::values.multiplayer_port = diff --git a/src/yuzu/multiplayer/lobby_p.h b/src/yuzu/multiplayer/lobby_p.h index 34371102c..ace6a5a9b 100755 --- a/src/yuzu/multiplayer/lobby_p.h +++ b/src/yuzu/multiplayer/lobby_p.h @@ -193,12 +193,29 @@ public: } QVariant data(int role) const override { - if (role != Qt::DisplayRole) { + switch (role) { + case Qt::DisplayRole: { + auto members = data(MemberListRole).toList(); + return QStringLiteral("%1 / %2 ") + .arg(QString::number(members.size()), data(MaxPlayerRole).toString()); + } + case Qt::ForegroundRole: { + auto members = data(MemberListRole).toList(); + auto max_players = data(MaxPlayerRole).toInt(); + if (members.size() >= max_players) { + return QBrush(QColor(255, 48, 32)); + } else if (members.size() == (max_players - 1)) { + return QBrush(QColor(255, 140, 32)); + } else if (members.size() == 0) { + return QBrush(QColor(128, 128, 128)); + } + // FIXME: How to return a value that tells Qt not to modify the + // text color from the default (as if Qt::ForegroundRole wasn't overridden)? + return QBrush(nullptr); + } + default: return LobbyItem::data(role); } - auto members = data(MemberListRole).toList(); - return QStringLiteral("%1 / %2 ") - .arg(QString::number(members.size()), data(MaxPlayerRole).toString()); } bool operator<(const QStandardItem& other) const override { diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index a4c62c5cb..6acbb5150 100755 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -169,6 +169,13 @@ struct Values { // multiplayer settings Setting multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer}; + Setting multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer}; + Setting multiplayer_filter_games_owned{linkage, false, "filter_games_owned", + Category::Multiplayer}; + Setting multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty", + Category::Multiplayer}; + Setting multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full", + Category::Multiplayer}; Setting multiplayer_ip{linkage, {}, "ip", Category::Multiplayer}; Setting multiplayer_port{linkage, 24872, 0, UINT16_MAX, "port", Category::Multiplayer}; @@ -222,7 +229,7 @@ void RestoreWindowState(std::unique_ptr& qtConfig); // This must be in alphabetical order according to action name as it must have the same order as // UISetting::values.shortcuts, which is alphabetically ordered. // clang-format off -const std::array default_hotkeys{{ +const std::array default_hotkeys{{ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, @@ -236,6 +243,11 @@ const std::array default_hotkeys{{ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},