summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/templates/build-msvc.yml2
-rw-r--r--.ci/yuzu-mainline-step2.yml2
-rw-r--r--.ci/yuzu-patreon-step2.yml2
-rw-r--r--.github/workflows/verify.yml2
-rw-r--r--externals/CMakeLists.txt1
-rw-r--r--src/common/announce_multiplayer_room.h1
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/common/settings.h1
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/core.cpp9
-rw-r--r--src/core/file_sys/system_archive/shared_font.cpp2
-rw-r--r--src/core/hle/service/acc/acc.cpp2
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.cpp2
-rw-r--r--src/core/hle/service/ldn/ldn_types.h16
-rw-r--r--src/core/hle/service/ns/iplatform_service_manager.cpp (renamed from src/core/hle/service/ns/pl_u.cpp)34
-rw-r--r--src/core/hle/service/ns/iplatform_service_manager.h (renamed from src/core/hle/service/ns/pl_u.h)6
-rw-r--r--src/core/hle/service/ns/ns.cpp5
-rw-r--r--src/core/hle/service/sockets/bsd.cpp6
-rw-r--r--src/core/internal_network/socket_proxy.cpp8
-rw-r--r--src/dedicated_room/CMakeLists.txt4
-rw-r--r--src/dedicated_room/yuzu_room.cpp9
-rw-r--r--src/input_common/drivers/sdl_driver.cpp11
-rw-r--r--src/network/CMakeLists.txt6
-rw-r--r--src/network/announce_multiplayer_session.cpp (renamed from src/core/announce_multiplayer_session.cpp)0
-rw-r--r--src/network/announce_multiplayer_session.h (renamed from src/core/announce_multiplayer_session.h)0
-rw-r--r--src/network/room.cpp14
-rw-r--r--src/network/room_member.cpp6
-rw-r--r--src/network/room_member.h2
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp10
-rw-r--r--src/video_core/buffer_cache/buffer_base.h5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp2
-rw-r--r--src/video_core/shader_environment.cpp7
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.h4
-rw-r--r--src/yuzu/configuration/configure_debug.ui7
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp8
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h1
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui10
-rw-r--r--src/yuzu/main.cpp2
-rw-r--r--src/yuzu/multiplayer/chat_room.cpp25
-rw-r--r--src/yuzu/multiplayer/client_room.cpp2
-rw-r--r--src/yuzu/multiplayer/direct_connect.cpp17
-rw-r--r--src/yuzu/multiplayer/direct_connect.h7
-rw-r--r--src/yuzu/multiplayer/host_room.cpp19
-rw-r--r--src/yuzu/multiplayer/host_room.h6
-rw-r--r--src/yuzu/multiplayer/lobby.cpp20
-rw-r--r--src/yuzu/multiplayer/lobby.h9
-rw-r--r--src/yuzu/multiplayer/message.cpp10
-rw-r--r--src/yuzu/multiplayer/message.h9
-rw-r--r--src/yuzu/multiplayer/state.cpp13
-rw-r--r--src/yuzu/multiplayer/state.h9
-rw-r--r--src/yuzu_cmd/config.cpp1
-rw-r--r--src/yuzu_cmd/default_ini.h4
55 files changed, 271 insertions, 102 deletions
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml
index 2a1bf93bc..a2ee71bd8 100644
--- a/.ci/templates/build-msvc.yml
+++ b/.ci/templates/build-msvc.yml
@@ -9,7 +9,7 @@ parameters:
9steps: 9steps:
10- script: choco install vulkan-sdk 10- script: choco install vulkan-sdk
11 displayName: 'Install vulkan-sdk' 11 displayName: 'Install vulkan-sdk'
12- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd .. 12- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd ..
13 displayName: 'Configure CMake' 13 displayName: 'Configure CMake'
14- task: MSBuild@1 14- task: MSBuild@1
15 displayName: 'Build' 15 displayName: 'Build'
diff --git a/.ci/yuzu-mainline-step2.yml b/.ci/yuzu-mainline-step2.yml
index 0e99f43fa..b294827f4 100644
--- a/.ci/yuzu-mainline-step2.yml
+++ b/.ci/yuzu-mainline-step2.yml
@@ -50,7 +50,7 @@ stages:
50 timeoutInMinutes: 120 50 timeoutInMinutes: 120
51 displayName: 'msvc' 51 displayName: 'msvc'
52 pool: 52 pool:
53 vmImage: windows-2019 53 vmImage: windows-2022
54 steps: 54 steps:
55 - template: ./templates/sync-source.yml 55 - template: ./templates/sync-source.yml
56 parameters: 56 parameters:
diff --git a/.ci/yuzu-patreon-step2.yml b/.ci/yuzu-patreon-step2.yml
index 33c081c53..5d5b140fd 100644
--- a/.ci/yuzu-patreon-step2.yml
+++ b/.ci/yuzu-patreon-step2.yml
@@ -15,7 +15,7 @@ stages:
15 timeoutInMinutes: 120 15 timeoutInMinutes: 120
16 displayName: 'windows-msvc' 16 displayName: 'windows-msvc'
17 pool: 17 pool:
18 vmImage: windows-2019 18 vmImage: windows-2022
19 steps: 19 steps:
20 - template: ./templates/sync-source.yml 20 - template: ./templates/sync-source.yml
21 parameters: 21 parameters:
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 9a973ee0c..733a52764 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -71,7 +71,7 @@ jobs:
71 build-msvc: 71 build-msvc:
72 name: 'test build (windows, msvc)' 72 name: 'test build (windows, msvc)'
73 needs: format 73 needs: format
74 runs-on: windows-2019 74 runs-on: windows-2022
75 steps: 75 steps:
76 - name: Set up cache 76 - name: Set up cache
77 uses: actions/cache@v3 77 uses: actions/cache@v3
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index eea70fc27..e80fd124e 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -16,7 +16,6 @@ endif()
16 16
17# Dynarmic 17# Dynarmic
18if (ARCHITECTURE_x86_64) 18if (ARCHITECTURE_x86_64)
19 set(DYNARMIC_TESTS OFF)
20 set(DYNARMIC_NO_BUNDLED_FMT ON) 19 set(DYNARMIC_NO_BUNDLED_FMT ON)
21 set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE) 20 set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE)
22 add_subdirectory(dynarmic) 21 add_subdirectory(dynarmic)
diff --git a/src/common/announce_multiplayer_room.h b/src/common/announce_multiplayer_room.h
index cb004e0eb..4a3100fa4 100644
--- a/src/common/announce_multiplayer_room.h
+++ b/src/common/announce_multiplayer_room.h
@@ -16,6 +16,7 @@ namespace AnnounceMultiplayerRoom {
16struct GameInfo { 16struct GameInfo {
17 std::string name{""}; 17 std::string name{""};
18 u64 id{0}; 18 u64 id{0};
19 std::string version{""};
19}; 20};
20 21
21struct Member { 22struct Member {
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 7282a45d3..0a560ebb7 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -195,6 +195,7 @@ void RestoreGlobalState(bool is_powered_on) {
195 values.shader_backend.SetGlobal(true); 195 values.shader_backend.SetGlobal(true);
196 values.use_asynchronous_shaders.SetGlobal(true); 196 values.use_asynchronous_shaders.SetGlobal(true);
197 values.use_fast_gpu_time.SetGlobal(true); 197 values.use_fast_gpu_time.SetGlobal(true);
198 values.use_pessimistic_flushes.SetGlobal(true);
198 values.bg_red.SetGlobal(true); 199 values.bg_red.SetGlobal(true);
199 values.bg_green.SetGlobal(true); 200 values.bg_green.SetGlobal(true);
200 values.bg_blue.SetGlobal(true); 201 values.bg_blue.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 14ed9b237..13651de57 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -446,6 +446,7 @@ struct Values {
446 ShaderBackend::SPIRV, "shader_backend"}; 446 ShaderBackend::SPIRV, "shader_backend"};
447 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 447 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
448 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 448 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
449 SwitchableSetting<bool> use_pessimistic_flushes{false, "use_pessimistic_flushes"};
449 450
450 SwitchableSetting<u8> bg_red{0, "bg_red"}; 451 SwitchableSetting<u8> bg_red{0, "bg_red"};
451 SwitchableSetting<u8> bg_green{0, "bg_green"}; 452 SwitchableSetting<u8> bg_green{0, "bg_green"};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8db9a3c65..806e7ff6c 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -2,8 +2,6 @@
2# SPDX-License-Identifier: GPL-2.0-or-later 2# SPDX-License-Identifier: GPL-2.0-or-later
3 3
4add_library(core STATIC 4add_library(core STATIC
5 announce_multiplayer_session.cpp
6 announce_multiplayer_session.h
7 arm/arm_interface.h 5 arm/arm_interface.h
8 arm/arm_interface.cpp 6 arm/arm_interface.cpp
9 arm/dynarmic/arm_dynarmic_32.cpp 7 arm/dynarmic/arm_dynarmic_32.cpp
@@ -540,14 +538,14 @@ add_library(core STATIC
540 hle/service/npns/npns.cpp 538 hle/service/npns/npns.cpp
541 hle/service/npns/npns.h 539 hle/service/npns/npns.h
542 hle/service/ns/errors.h 540 hle/service/ns/errors.h
541 hle/service/ns/iplatform_service_manager.cpp
542 hle/service/ns/iplatform_service_manager.h
543 hle/service/ns/language.cpp 543 hle/service/ns/language.cpp
544 hle/service/ns/language.h 544 hle/service/ns/language.h
545 hle/service/ns/ns.cpp 545 hle/service/ns/ns.cpp
546 hle/service/ns/ns.h 546 hle/service/ns/ns.h
547 hle/service/ns/pdm_qry.cpp 547 hle/service/ns/pdm_qry.cpp
548 hle/service/ns/pdm_qry.h 548 hle/service/ns/pdm_qry.h
549 hle/service/ns/pl_u.cpp
550 hle/service/ns/pl_u.h
551 hle/service/nvdrv/devices/nvdevice.h 549 hle/service/nvdrv/devices/nvdevice.h
552 hle/service/nvdrv/devices/nvdisp_disp0.cpp 550 hle/service/nvdrv/devices/nvdisp_disp0.cpp
553 hle/service/nvdrv/devices/nvdisp_disp0.h 551 hle/service/nvdrv/devices/nvdisp_disp0.h
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ea32a4a8d..e651ce100 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -319,10 +319,19 @@ struct System::Impl {
319 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) { 319 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
320 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result); 320 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
321 } 321 }
322
323 std::string title_version;
324 const FileSys::PatchManager pm(program_id, system.GetFileSystemController(),
325 system.GetContentProvider());
326 const auto metadata = pm.GetControlMetadata();
327 if (metadata.first != nullptr) {
328 title_version = metadata.first->GetVersionString();
329 }
322 if (auto room_member = room_network.GetRoomMember().lock()) { 330 if (auto room_member = room_network.GetRoomMember().lock()) {
323 Network::GameInfo game_info; 331 Network::GameInfo game_info;
324 game_info.name = name; 332 game_info.name = name;
325 game_info.id = program_id; 333 game_info.id = program_id;
334 game_info.version = title_version;
326 room_member->SendGameInfo(game_info); 335 room_member->SendGameInfo(game_info);
327 } 336 }
328 337
diff --git a/src/core/file_sys/system_archive/shared_font.cpp b/src/core/file_sys/system_archive/shared_font.cpp
index f841988ff..3210583f0 100644
--- a/src/core/file_sys/system_archive/shared_font.cpp
+++ b/src/core/file_sys/system_archive/shared_font.cpp
@@ -9,7 +9,7 @@
9#include "core/file_sys/system_archive/data/font_standard.h" 9#include "core/file_sys/system_archive/data/font_standard.h"
10#include "core/file_sys/system_archive/shared_font.h" 10#include "core/file_sys/system_archive/shared_font.h"
11#include "core/file_sys/vfs_vector.h" 11#include "core/file_sys/vfs_vector.h"
12#include "core/hle/service/ns/pl_u.h" 12#include "core/hle/service/ns/iplatform_service_manager.h"
13 13
14namespace FileSys::SystemArchive { 14namespace FileSys::SystemArchive {
15 15
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index def105832..bb838e285 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -534,7 +534,7 @@ public:
534 534
535private: 535private:
536 void CheckAvailability(Kernel::HLERequestContext& ctx) { 536 void CheckAvailability(Kernel::HLERequestContext& ctx) {
537 LOG_WARNING(Service_ACC, "(STUBBED) called"); 537 LOG_DEBUG(Service_ACC, "(STUBBED) called");
538 IPC::ResponseBuilder rb{ctx, 3}; 538 IPC::ResponseBuilder rb{ctx, 3};
539 rb.Push(ResultSuccess); 539 rb.Push(ResultSuccess);
540 rb.Push(false); // TODO: Check when this is supposed to return true and when not 540 rb.Push(false); // TODO: Check when this is supposed to return true and when not
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp
index 4b804b78c..14aa6f69e 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.cpp
+++ b/src/core/hle/service/am/applets/applet_web_browser.cpp
@@ -21,7 +21,7 @@
21#include "core/hle/service/am/am.h" 21#include "core/hle/service/am/am.h"
22#include "core/hle/service/am/applets/applet_web_browser.h" 22#include "core/hle/service/am/applets/applet_web_browser.h"
23#include "core/hle/service/filesystem/filesystem.h" 23#include "core/hle/service/filesystem/filesystem.h"
24#include "core/hle/service/ns/pl_u.h" 24#include "core/hle/service/ns/iplatform_service_manager.h"
25#include "core/loader/loader.h" 25#include "core/loader/loader.h"
26 26
27namespace Service::AM::Applets { 27namespace Service::AM::Applets {
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h
index 0c07a7397..6231e936d 100644
--- a/src/core/hle/service/ldn/ldn_types.h
+++ b/src/core/hle/service/ldn/ldn_types.h
@@ -113,7 +113,7 @@ enum class LinkLevel : s8 {
113 Bad, 113 Bad,
114 Low, 114 Low,
115 Good, 115 Good,
116 Excelent, 116 Excellent,
117}; 117};
118 118
119struct NodeLatestUpdate { 119struct NodeLatestUpdate {
@@ -145,11 +145,19 @@ struct NetworkId {
145static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size"); 145static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
146 146
147struct Ssid { 147struct Ssid {
148 u8 length; 148 u8 length{};
149 std::array<char, SsidLengthMax + 1> raw; 149 std::array<char, SsidLengthMax + 1> raw{};
150
151 Ssid() = default;
152
153 explicit Ssid(std::string_view data) {
154 length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
155 data.copy(raw.data(), length);
156 raw[length] = 0;
157 }
150 158
151 std::string GetStringValue() const { 159 std::string GetStringValue() const {
152 return std::string(raw.data(), length); 160 return std::string(raw.data());
153 } 161 }
154}; 162};
155static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); 163static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size");
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/iplatform_service_manager.cpp
index cc11f3e08..fd047ff26 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/iplatform_service_manager.cpp
@@ -20,7 +20,7 @@
20#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/kernel.h"
21#include "core/hle/kernel/physical_memory.h" 21#include "core/hle/kernel/physical_memory.h"
22#include "core/hle/service/filesystem/filesystem.h" 22#include "core/hle/service/filesystem/filesystem.h"
23#include "core/hle/service/ns/pl_u.h" 23#include "core/hle/service/ns/iplatform_service_manager.h"
24 24
25namespace Service::NS { 25namespace Service::NS {
26 26
@@ -99,7 +99,7 @@ static u32 GetU32Swapped(const u8* data) {
99 return Common::swap32(value); 99 return Common::swap32(value);
100} 100}
101 101
102struct PL_U::Impl { 102struct IPlatformServiceManager::Impl {
103 const FontRegion& GetSharedFontRegion(std::size_t index) const { 103 const FontRegion& GetSharedFontRegion(std::size_t index) const {
104 if (index >= shared_font_regions.size() || shared_font_regions.empty()) { 104 if (index >= shared_font_regions.size() || shared_font_regions.empty()) {
105 // No font fallback 105 // No font fallback
@@ -134,16 +134,16 @@ struct PL_U::Impl {
134 std::vector<FontRegion> shared_font_regions; 134 std::vector<FontRegion> shared_font_regions;
135}; 135};
136 136
137PL_U::PL_U(Core::System& system_) 137IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_)
138 : ServiceFramework{system_, "pl:u"}, impl{std::make_unique<Impl>()} { 138 : ServiceFramework{system_, service_name_}, impl{std::make_unique<Impl>()} {
139 // clang-format off 139 // clang-format off
140 static const FunctionInfo functions[] = { 140 static const FunctionInfo functions[] = {
141 {0, &PL_U::RequestLoad, "RequestLoad"}, 141 {0, &IPlatformServiceManager::RequestLoad, "RequestLoad"},
142 {1, &PL_U::GetLoadState, "GetLoadState"}, 142 {1, &IPlatformServiceManager::GetLoadState, "GetLoadState"},
143 {2, &PL_U::GetSize, "GetSize"}, 143 {2, &IPlatformServiceManager::GetSize, "GetSize"},
144 {3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, 144 {3, &IPlatformServiceManager::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"},
145 {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, 145 {4, &IPlatformServiceManager::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
146 {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, 146 {5, &IPlatformServiceManager::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
147 {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"}, 147 {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"},
148 {100, nullptr, "RequestApplicationFunctionAuthorization"}, 148 {100, nullptr, "RequestApplicationFunctionAuthorization"},
149 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, 149 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
@@ -206,9 +206,9 @@ PL_U::PL_U(Core::System& system_)
206 } 206 }
207} 207}
208 208
209PL_U::~PL_U() = default; 209IPlatformServiceManager::~IPlatformServiceManager() = default;
210 210
211void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { 211void IPlatformServiceManager::RequestLoad(Kernel::HLERequestContext& ctx) {
212 IPC::RequestParser rp{ctx}; 212 IPC::RequestParser rp{ctx};
213 const u32 shared_font_type{rp.Pop<u32>()}; 213 const u32 shared_font_type{rp.Pop<u32>()};
214 // Games don't call this so all fonts should be loaded 214 // Games don't call this so all fonts should be loaded
@@ -218,7 +218,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
218 rb.Push(ResultSuccess); 218 rb.Push(ResultSuccess);
219} 219}
220 220
221void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { 221void IPlatformServiceManager::GetLoadState(Kernel::HLERequestContext& ctx) {
222 IPC::RequestParser rp{ctx}; 222 IPC::RequestParser rp{ctx};
223 const u32 font_id{rp.Pop<u32>()}; 223 const u32 font_id{rp.Pop<u32>()};
224 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 224 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -228,7 +228,7 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
228 rb.Push<u32>(static_cast<u32>(LoadState::Done)); 228 rb.Push<u32>(static_cast<u32>(LoadState::Done));
229} 229}
230 230
231void PL_U::GetSize(Kernel::HLERequestContext& ctx) { 231void IPlatformServiceManager::GetSize(Kernel::HLERequestContext& ctx) {
232 IPC::RequestParser rp{ctx}; 232 IPC::RequestParser rp{ctx};
233 const u32 font_id{rp.Pop<u32>()}; 233 const u32 font_id{rp.Pop<u32>()};
234 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 234 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -238,7 +238,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
238 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); 238 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
239} 239}
240 240
241void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { 241void IPlatformServiceManager::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
242 IPC::RequestParser rp{ctx}; 242 IPC::RequestParser rp{ctx};
243 const u32 font_id{rp.Pop<u32>()}; 243 const u32 font_id{rp.Pop<u32>()};
244 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 244 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -248,7 +248,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
248 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); 248 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
249} 249}
250 250
251void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 251void IPlatformServiceManager::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
252 // Map backing memory for the font data 252 // Map backing memory for the font data
253 LOG_DEBUG(Service_NS, "called"); 253 LOG_DEBUG(Service_NS, "called");
254 254
@@ -261,7 +261,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
261 rb.PushCopyObjects(&kernel.GetFontSharedMem()); 261 rb.PushCopyObjects(&kernel.GetFontSharedMem());
262} 262}
263 263
264void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { 264void IPlatformServiceManager::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
265 IPC::RequestParser rp{ctx}; 265 IPC::RequestParser rp{ctx};
266 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for 266 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
267 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); 267 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/iplatform_service_manager.h
index 07d0ac934..ed6eda89f 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/iplatform_service_manager.h
@@ -36,10 +36,10 @@ constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
36void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output); 36void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output);
37void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset); 37void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset);
38 38
39class PL_U final : public ServiceFramework<PL_U> { 39class IPlatformServiceManager final : public ServiceFramework<IPlatformServiceManager> {
40public: 40public:
41 explicit PL_U(Core::System& system_); 41 explicit IPlatformServiceManager(Core::System& system_, const char* service_name_);
42 ~PL_U() override; 42 ~IPlatformServiceManager() override;
43 43
44private: 44private:
45 void RequestLoad(Kernel::HLERequestContext& ctx); 45 void RequestLoad(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index aafc8fe03..f7318c3cb 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -9,10 +9,10 @@
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/service/ns/errors.h" 11#include "core/hle/service/ns/errors.h"
12#include "core/hle/service/ns/iplatform_service_manager.h"
12#include "core/hle/service/ns/language.h" 13#include "core/hle/service/ns/language.h"
13#include "core/hle/service/ns/ns.h" 14#include "core/hle/service/ns/ns.h"
14#include "core/hle/service/ns/pdm_qry.h" 15#include "core/hle/service/ns/pdm_qry.h"
15#include "core/hle/service/ns/pl_u.h"
16#include "core/hle/service/set/set.h" 16#include "core/hle/service/set/set.h"
17 17
18namespace Service::NS { 18namespace Service::NS {
@@ -764,7 +764,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
764 764
765 std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager); 765 std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager);
766 766
767 std::make_shared<PL_U>(system)->InstallAsService(service_manager); 767 std::make_shared<IPlatformServiceManager>(system, "pl:s")->InstallAsService(service_manager);
768 std::make_shared<IPlatformServiceManager>(system, "pl:u")->InstallAsService(service_manager);
768} 769}
769 770
770} // namespace Service::NS 771} // namespace Service::NS
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index e08c3cb67..cc679cc81 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -933,7 +933,11 @@ BSD::BSD(Core::System& system_, const char* name)
933 } 933 }
934} 934}
935 935
936BSD::~BSD() = default; 936BSD::~BSD() {
937 if (auto room_member = room_network.GetRoomMember().lock()) {
938 room_member->Unbind(proxy_packet_received);
939 }
940}
937 941
938BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { 942BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {
939 // clang-format off 943 // clang-format off
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
index 49d067f4c..0c746bd82 100644
--- a/src/core/internal_network/socket_proxy.cpp
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -26,6 +26,12 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
26 closed) { 26 closed) {
27 return; 27 return;
28 } 28 }
29
30 if (!broadcast && packet.broadcast) {
31 LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode");
32 return;
33 }
34
29 std::lock_guard guard(packets_mutex); 35 std::lock_guard guard(packets_mutex);
30 received_packets.push(packet); 36 received_packets.push(packet);
31} 37}
@@ -203,7 +209,7 @@ std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& mess
203 packet.local_endpoint = local_endpoint; 209 packet.local_endpoint = local_endpoint;
204 packet.remote_endpoint = *addr; 210 packet.remote_endpoint = *addr;
205 packet.protocol = protocol; 211 packet.protocol = protocol;
206 packet.broadcast = broadcast; 212 packet.broadcast = broadcast && packet.remote_endpoint.ip[3] == 255;
207 213
208 auto& ip = local_endpoint.ip; 214 auto& ip = local_endpoint.ip;
209 auto ipv4 = Network::GetHostIPv4Address(); 215 auto ipv4 = Network::GetHostIPv4Address();
diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt
index b674b915b..1efdbc1f7 100644
--- a/src/dedicated_room/CMakeLists.txt
+++ b/src/dedicated_room/CMakeLists.txt
@@ -10,13 +10,13 @@ add_executable(yuzu-room
10 10
11create_target_directory_groups(yuzu-room) 11create_target_directory_groups(yuzu-room)
12 12
13target_link_libraries(yuzu-room PRIVATE common core network) 13target_link_libraries(yuzu-room PRIVATE common network)
14if (ENABLE_WEB_SERVICE) 14if (ENABLE_WEB_SERVICE)
15 target_compile_definitions(yuzu-room PRIVATE -DENABLE_WEB_SERVICE) 15 target_compile_definitions(yuzu-room PRIVATE -DENABLE_WEB_SERVICE)
16 target_link_libraries(yuzu-room PRIVATE web_service) 16 target_link_libraries(yuzu-room PRIVATE web_service)
17endif() 17endif()
18 18
19target_link_libraries(yuzu-room PRIVATE mbedtls) 19target_link_libraries(yuzu-room PRIVATE mbedtls mbedcrypto)
20if (MSVC) 20if (MSVC)
21 target_link_libraries(yuzu-room PRIVATE getopt) 21 target_link_libraries(yuzu-room PRIVATE getopt)
22endif() 22endif()
diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp
index 482e772fb..7b6deba41 100644
--- a/src/dedicated_room/yuzu_room.cpp
+++ b/src/dedicated_room/yuzu_room.cpp
@@ -27,8 +27,8 @@
27#include "common/scm_rev.h" 27#include "common/scm_rev.h"
28#include "common/settings.h" 28#include "common/settings.h"
29#include "common/string_util.h" 29#include "common/string_util.h"
30#include "core/announce_multiplayer_session.h"
31#include "core/core.h" 30#include "core/core.h"
31#include "network/announce_multiplayer_session.h"
32#include "network/network.h" 32#include "network/network.h"
33#include "network/room.h" 33#include "network/room.h"
34#include "network/verify_user.h" 34#include "network/verify_user.h"
@@ -75,6 +75,12 @@ static constexpr char BanListMagic[] = "YuzuRoom-BanList-1";
75 75
76static constexpr char token_delimiter{':'}; 76static constexpr char token_delimiter{':'};
77 77
78static void PadToken(std::string& token) {
79 while (token.size() % 4 != 0) {
80 token.push_back('=');
81 }
82}
83
78static std::string UsernameFromDisplayToken(const std::string& display_token) { 84static std::string UsernameFromDisplayToken(const std::string& display_token) {
79 std::size_t outlen; 85 std::size_t outlen;
80 86
@@ -300,6 +306,7 @@ int main(int argc, char** argv) {
300 if (username.empty()) { 306 if (username.empty()) {
301 LOG_INFO(Network, "Hosting a public room"); 307 LOG_INFO(Network, "Hosting a public room");
302 Settings::values.web_api_url = web_api_url; 308 Settings::values.web_api_url = web_api_url;
309 PadToken(token);
303 Settings::values.yuzu_username = UsernameFromDisplayToken(token); 310 Settings::values.yuzu_username = UsernameFromDisplayToken(token);
304 username = Settings::values.yuzu_username.GetValue(); 311 username = Settings::values.yuzu_username.GetValue();
305 Settings::values.yuzu_token = TokenFromDisplayToken(token); 312 Settings::values.yuzu_token = TokenFromDisplayToken(token);
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index de388ec4c..5cc1ccbd9 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -40,13 +40,13 @@ public:
40 void EnableMotion() { 40 void EnableMotion() {
41 if (sdl_controller) { 41 if (sdl_controller) {
42 SDL_GameController* controller = sdl_controller.get(); 42 SDL_GameController* controller = sdl_controller.get();
43 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { 43 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL);
44 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO);
45 if (has_accel) {
44 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); 46 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
45 has_accel = true;
46 } 47 }
47 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { 48 if (has_gyro) {
48 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); 49 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
49 has_gyro = true;
50 } 50 }
51 } 51 }
52 } 52 }
@@ -305,6 +305,7 @@ void SDLDriver::InitJoystick(int joystick_index) {
305 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); 305 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
306 PreSetController(joystick->GetPadIdentifier()); 306 PreSetController(joystick->GetPadIdentifier());
307 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); 307 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
308 joystick->EnableMotion();
308 joystick_map[guid].emplace_back(std::move(joystick)); 309 joystick_map[guid].emplace_back(std::move(joystick));
309 return; 310 return;
310 } 311 }
@@ -316,6 +317,7 @@ void SDLDriver::InitJoystick(int joystick_index) {
316 317
317 if (joystick_it != joystick_guid_list.end()) { 318 if (joystick_it != joystick_guid_list.end()) {
318 (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); 319 (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
320 (*joystick_it)->EnableMotion();
319 return; 321 return;
320 } 322 }
321 323
@@ -323,6 +325,7 @@ void SDLDriver::InitJoystick(int joystick_index) {
323 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); 325 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
324 PreSetController(joystick->GetPadIdentifier()); 326 PreSetController(joystick->GetPadIdentifier());
325 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); 327 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
328 joystick->EnableMotion();
326 joystick_guid_list.emplace_back(std::move(joystick)); 329 joystick_guid_list.emplace_back(std::move(joystick));
327} 330}
328 331
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index 312f79b68..6f8ca4b90 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -2,6 +2,8 @@
2# SPDX-License-Identifier: GPL-3.0-or-later 2# SPDX-License-Identifier: GPL-3.0-or-later
3 3
4add_library(network STATIC 4add_library(network STATIC
5 announce_multiplayer_session.cpp
6 announce_multiplayer_session.h
5 network.cpp 7 network.cpp
6 network.h 8 network.h
7 packet.cpp 9 packet.cpp
@@ -17,3 +19,7 @@ add_library(network STATIC
17create_target_directory_groups(network) 19create_target_directory_groups(network)
18 20
19target_link_libraries(network PRIVATE common enet Boost::boost) 21target_link_libraries(network PRIVATE common enet Boost::boost)
22if (ENABLE_WEB_SERVICE)
23 target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE)
24 target_link_libraries(network PRIVATE web_service)
25endif()
diff --git a/src/core/announce_multiplayer_session.cpp b/src/network/announce_multiplayer_session.cpp
index 6737ce85a..6737ce85a 100644
--- a/src/core/announce_multiplayer_session.cpp
+++ b/src/network/announce_multiplayer_session.cpp
diff --git a/src/core/announce_multiplayer_session.h b/src/network/announce_multiplayer_session.h
index db790f7d2..db790f7d2 100644
--- a/src/core/announce_multiplayer_session.h
+++ b/src/network/announce_multiplayer_session.h
diff --git a/src/network/room.cpp b/src/network/room.cpp
index b06797bf1..8c63b255b 100644
--- a/src/network/room.cpp
+++ b/src/network/room.cpp
@@ -221,7 +221,7 @@ public:
221 * Extracts the game name from a received ENet packet and broadcasts it. 221 * Extracts the game name from a received ENet packet and broadcasts it.
222 * @param event The ENet event that was received. 222 * @param event The ENet event that was received.
223 */ 223 */
224 void HandleGameNamePacket(const ENetEvent* event); 224 void HandleGameInfoPacket(const ENetEvent* event);
225 225
226 /** 226 /**
227 * Removes the client from the members list if it was in it and announces the change 227 * Removes the client from the members list if it was in it and announces the change
@@ -234,7 +234,7 @@ public:
234void Room::RoomImpl::ServerLoop() { 234void Room::RoomImpl::ServerLoop() {
235 while (state != State::Closed) { 235 while (state != State::Closed) {
236 ENetEvent event; 236 ENetEvent event;
237 if (enet_host_service(server, &event, 50) > 0) { 237 if (enet_host_service(server, &event, 5) > 0) {
238 switch (event.type) { 238 switch (event.type) {
239 case ENET_EVENT_TYPE_RECEIVE: 239 case ENET_EVENT_TYPE_RECEIVE:
240 switch (event.packet->data[0]) { 240 switch (event.packet->data[0]) {
@@ -242,7 +242,7 @@ void Room::RoomImpl::ServerLoop() {
242 HandleJoinRequest(&event); 242 HandleJoinRequest(&event);
243 break; 243 break;
244 case IdSetGameInfo: 244 case IdSetGameInfo:
245 HandleGameNamePacket(&event); 245 HandleGameInfoPacket(&event);
246 break; 246 break;
247 case IdProxyPacket: 247 case IdProxyPacket:
248 HandleProxyPacket(&event); 248 HandleProxyPacket(&event);
@@ -778,6 +778,7 @@ void Room::RoomImpl::BroadcastRoomInformation() {
778 packet.Write(member.fake_ip); 778 packet.Write(member.fake_ip);
779 packet.Write(member.game_info.name); 779 packet.Write(member.game_info.name);
780 packet.Write(member.game_info.id); 780 packet.Write(member.game_info.id);
781 packet.Write(member.game_info.version);
781 packet.Write(member.user_data.username); 782 packet.Write(member.user_data.username);
782 packet.Write(member.user_data.display_name); 783 packet.Write(member.user_data.display_name);
783 packet.Write(member.user_data.avatar_url); 784 packet.Write(member.user_data.avatar_url);
@@ -817,6 +818,7 @@ void Room::RoomImpl::HandleProxyPacket(const ENetEvent* event) {
817 in_packet.IgnoreBytes(sizeof(u16)); // Port 818 in_packet.IgnoreBytes(sizeof(u16)); // Port
818 819
819 in_packet.IgnoreBytes(sizeof(u8)); // Protocol 820 in_packet.IgnoreBytes(sizeof(u8)); // Protocol
821
820 bool broadcast; 822 bool broadcast;
821 in_packet.Read(broadcast); // Broadcast 823 in_packet.Read(broadcast); // Broadcast
822 824
@@ -909,7 +911,7 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) {
909 } 911 }
910} 912}
911 913
912void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) { 914void Room::RoomImpl::HandleGameInfoPacket(const ENetEvent* event) {
913 Packet in_packet; 915 Packet in_packet;
914 in_packet.Append(event->packet->data, event->packet->dataLength); 916 in_packet.Append(event->packet->data, event->packet->dataLength);
915 917
@@ -917,6 +919,7 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {
917 GameInfo game_info; 919 GameInfo game_info;
918 in_packet.Read(game_info.name); 920 in_packet.Read(game_info.name);
919 in_packet.Read(game_info.id); 921 in_packet.Read(game_info.id);
922 in_packet.Read(game_info.version);
920 923
921 { 924 {
922 std::lock_guard lock(member_mutex); 925 std::lock_guard lock(member_mutex);
@@ -935,7 +938,8 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {
935 if (game_info.name.empty()) { 938 if (game_info.name.empty()) {
936 LOG_INFO(Network, "{} is not playing", display_name); 939 LOG_INFO(Network, "{} is not playing", display_name);
937 } else { 940 } else {
938 LOG_INFO(Network, "{} is playing {}", display_name, game_info.name); 941 LOG_INFO(Network, "{} is playing {} ({})", display_name, game_info.name,
942 game_info.version);
939 } 943 }
940 } 944 }
941 } 945 }
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp
index 9f08bf611..06818af78 100644
--- a/src/network/room_member.cpp
+++ b/src/network/room_member.cpp
@@ -103,7 +103,7 @@ public:
103 103
104 /** 104 /**
105 * Extracts a ProxyPacket from a received ENet packet. 105 * Extracts a ProxyPacket from a received ENet packet.
106 * @param event The ENet event that was received. 106 * @param event The ENet event that was received.
107 */ 107 */
108 void HandleProxyPackets(const ENetEvent* event); 108 void HandleProxyPackets(const ENetEvent* event);
109 109
@@ -159,7 +159,7 @@ void RoomMember::RoomMemberImpl::MemberLoop() {
159 while (IsConnected()) { 159 while (IsConnected()) {
160 std::lock_guard lock(network_mutex); 160 std::lock_guard lock(network_mutex);
161 ENetEvent event; 161 ENetEvent event;
162 if (enet_host_service(client, &event, 100) > 0) { 162 if (enet_host_service(client, &event, 5) > 0) {
163 switch (event.type) { 163 switch (event.type) {
164 case ENET_EVENT_TYPE_RECEIVE: 164 case ENET_EVENT_TYPE_RECEIVE:
165 switch (event.packet->data[0]) { 165 switch (event.packet->data[0]) {
@@ -315,6 +315,7 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev
315 packet.Read(member.fake_ip); 315 packet.Read(member.fake_ip);
316 packet.Read(member.game_info.name); 316 packet.Read(member.game_info.name);
317 packet.Read(member.game_info.id); 317 packet.Read(member.game_info.id);
318 packet.Read(member.game_info.version);
318 packet.Read(member.username); 319 packet.Read(member.username);
319 packet.Read(member.display_name); 320 packet.Read(member.display_name);
320 packet.Read(member.avatar_url); 321 packet.Read(member.avatar_url);
@@ -622,6 +623,7 @@ void RoomMember::SendGameInfo(const GameInfo& game_info) {
622 packet.Write(static_cast<u8>(IdSetGameInfo)); 623 packet.Write(static_cast<u8>(IdSetGameInfo));
623 packet.Write(game_info.name); 624 packet.Write(game_info.name);
624 packet.Write(game_info.id); 625 packet.Write(game_info.id);
626 packet.Write(game_info.version);
625 room_member_impl->Send(std::move(packet)); 627 room_member_impl->Send(std::move(packet));
626} 628}
627 629
diff --git a/src/network/room_member.h b/src/network/room_member.h
index 4252b7146..f578f7f6a 100644
--- a/src/network/room_member.h
+++ b/src/network/room_member.h
@@ -146,7 +146,7 @@ public:
146 const std::string& password = "", const std::string& token = ""); 146 const std::string& password = "", const std::string& token = "");
147 147
148 /** 148 /**
149 * Sends a WiFi packet to the room. 149 * Sends a Proxy packet to the room.
150 * @param packet The WiFi packet to send. 150 * @param packet The WiFi packet to send.
151 */ 151 */
152 void SendProxyPacket(const ProxyPacket& packet); 152 void SendProxyPacket(const ProxyPacket& packet);
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index 5cead5135..597112ba4 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -415,11 +415,11 @@ void TexturePass(Environment& env, IR::Program& program) {
415 inst->SetFlags(flags); 415 inst->SetFlags(flags);
416 break; 416 break;
417 case IR::Opcode::ImageSampleImplicitLod: 417 case IR::Opcode::ImageSampleImplicitLod:
418 if (flags.type == TextureType::Color2D) { 418 if (flags.type != TextureType::Color2D) {
419 auto texture_type = ReadTextureType(env, cbuf); 419 break;
420 if (texture_type == TextureType::Color2DRect) { 420 }
421 PatchImageSampleImplicitLod(*texture_inst.block, *texture_inst.inst); 421 if (ReadTextureType(env, cbuf) == TextureType::Color2DRect) {
422 } 422 PatchImageSampleImplicitLod(*texture_inst.block, *texture_inst.inst);
423 } 423 }
424 break; 424 break;
425 case IR::Opcode::ImageFetch: 425 case IR::Opcode::ImageFetch:
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h
index 0b2bc67b1..f9a6472cf 100644
--- a/src/video_core/buffer_cache/buffer_base.h
+++ b/src/video_core/buffer_cache/buffer_base.h
@@ -12,6 +12,7 @@
12#include "common/common_funcs.h" 12#include "common/common_funcs.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/div_ceil.h" 14#include "common/div_ceil.h"
15#include "common/settings.h"
15#include "core/memory.h" 16#include "core/memory.h"
16 17
17namespace VideoCommon { 18namespace VideoCommon {
@@ -219,7 +220,9 @@ public:
219 NotifyRasterizer<false>(word_index, untracked_words[word_index], cached_bits); 220 NotifyRasterizer<false>(word_index, untracked_words[word_index], cached_bits);
220 untracked_words[word_index] |= cached_bits; 221 untracked_words[word_index] |= cached_bits;
221 cpu_words[word_index] |= cached_bits; 222 cpu_words[word_index] |= cached_bits;
222 cached_words[word_index] = 0; 223 if (!Settings::values.use_pessimistic_flushes) {
224 cached_words[word_index] = 0;
225 }
223 } 226 }
224 } 227 }
225 228
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 1ad56d9e7..ddb70934c 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -49,7 +49,7 @@ using VideoCommon::LoadPipelines;
49using VideoCommon::SerializePipeline; 49using VideoCommon::SerializePipeline;
50using Context = ShaderContext::Context; 50using Context = ShaderContext::Context;
51 51
52constexpr u32 CACHE_VERSION = 5; 52constexpr u32 CACHE_VERSION = 6;
53 53
54template <typename Container> 54template <typename Container>
55auto MakeSpan(Container& container) { 55auto MakeSpan(Container& container) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 3adad5af4..9708dc45e 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -53,7 +53,7 @@ using VideoCommon::FileEnvironment;
53using VideoCommon::GenericEnvironment; 53using VideoCommon::GenericEnvironment;
54using VideoCommon::GraphicsEnvironment; 54using VideoCommon::GraphicsEnvironment;
55 55
56constexpr u32 CACHE_VERSION = 5; 56constexpr u32 CACHE_VERSION = 6;
57 57
58template <typename Container> 58template <typename Container>
59auto MakeSpan(Container& container) { 59auto MakeSpan(Container& container) {
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 808d88eec..5f7625947 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -39,11 +39,8 @@ static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) {
39 return Shader::TextureType::Color1D; 39 return Shader::TextureType::Color1D;
40 case Tegra::Texture::TextureType::Texture2D: 40 case Tegra::Texture::TextureType::Texture2D:
41 case Tegra::Texture::TextureType::Texture2DNoMipmap: 41 case Tegra::Texture::TextureType::Texture2DNoMipmap:
42 if (entry.normalized_coords) { 42 return entry.normalized_coords ? Shader::TextureType::Color2D
43 return Shader::TextureType::Color2D; 43 : Shader::TextureType::Color2DRect;
44 } else {
45 return Shader::TextureType::Color2DRect;
46 }
47 case Tegra::Texture::TextureType::Texture3D: 44 case Tegra::Texture::TextureType::Texture3D:
48 return Shader::TextureType::Color3D; 45 return Shader::TextureType::Color3D;
49 case Tegra::Texture::TextureType::TextureCubemap: 46 case Tegra::Texture::TextureType::TextureCubemap:
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index da6e5aa88..8ecd87150 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -684,6 +684,7 @@ void Config::ReadRendererValues() {
684 ReadGlobalSetting(Settings::values.shader_backend); 684 ReadGlobalSetting(Settings::values.shader_backend);
685 ReadGlobalSetting(Settings::values.use_asynchronous_shaders); 685 ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
686 ReadGlobalSetting(Settings::values.use_fast_gpu_time); 686 ReadGlobalSetting(Settings::values.use_fast_gpu_time);
687 ReadGlobalSetting(Settings::values.use_pessimistic_flushes);
687 ReadGlobalSetting(Settings::values.bg_red); 688 ReadGlobalSetting(Settings::values.bg_red);
688 ReadGlobalSetting(Settings::values.bg_green); 689 ReadGlobalSetting(Settings::values.bg_green);
689 ReadGlobalSetting(Settings::values.bg_blue); 690 ReadGlobalSetting(Settings::values.bg_blue);
@@ -1300,6 +1301,7 @@ void Config::SaveRendererValues() {
1300 Settings::values.shader_backend.UsingGlobal()); 1301 Settings::values.shader_backend.UsingGlobal());
1301 WriteGlobalSetting(Settings::values.use_asynchronous_shaders); 1302 WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
1302 WriteGlobalSetting(Settings::values.use_fast_gpu_time); 1303 WriteGlobalSetting(Settings::values.use_fast_gpu_time);
1304 WriteGlobalSetting(Settings::values.use_pessimistic_flushes);
1303 WriteGlobalSetting(Settings::values.bg_red); 1305 WriteGlobalSetting(Settings::values.bg_red);
1304 WriteGlobalSetting(Settings::values.bg_green); 1306 WriteGlobalSetting(Settings::values.bg_green);
1305 WriteGlobalSetting(Settings::values.bg_blue); 1307 WriteGlobalSetting(Settings::values.bg_blue);
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index e16d127a8..04d397750 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -14,7 +14,7 @@
14#include "yuzu/uisettings.h" 14#include "yuzu/uisettings.h"
15 15
16ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent) 16ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent)
17 : QWidget(parent), ui{std::make_unique<Ui::ConfigureDebug>()}, system{system_} { 17 : QScrollArea(parent), ui{std::make_unique<Ui::ConfigureDebug>()}, system{system_} {
18 ui->setupUi(this); 18 ui->setupUi(this);
19 SetConfiguration(); 19 SetConfiguration();
20 20
diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index 64d68ab8f..42d30f170 100644
--- a/src/yuzu/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
@@ -4,7 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include <QWidget> 7#include <QScrollArea>
8 8
9namespace Core { 9namespace Core {
10class System; 10class System;
@@ -14,7 +14,7 @@ namespace Ui {
14class ConfigureDebug; 14class ConfigureDebug;
15} 15}
16 16
17class ConfigureDebug : public QWidget { 17class ConfigureDebug : public QScrollArea {
18 Q_OBJECT 18 Q_OBJECT
19 19
20public: 20public:
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 4c16274fc..47b8b80f1 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -1,7 +1,11 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureDebug</class> 3 <class>ConfigureDebug</class>
4 <widget class="QWidget" name="ConfigureDebug"> 4 <widget class="QScrollArea" name="ConfigureDebug">
5 <property name="widgetResizable">
6 <bool>true</bool>
7 </property>
8 <widget class="QWidget">
5 <layout class="QVBoxLayout" name="verticalLayout_1"> 9 <layout class="QVBoxLayout" name="verticalLayout_1">
6 <item> 10 <item>
7 <layout class="QVBoxLayout" name="verticalLayout_2"> 11 <layout class="QVBoxLayout" name="verticalLayout_2">
@@ -322,6 +326,7 @@
322 </item> 326 </item>
323 </layout> 327 </layout>
324 </widget> 328 </widget>
329 </widget>
325 <tabstops> 330 <tabstops>
326 <tabstop>log_filter_edit</tabstop> 331 <tabstop>log_filter_edit</tabstop>
327 <tabstop>toggle_console</tabstop> 332 <tabstop>toggle_console</tabstop>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 7c3196c83..01f074699 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -28,6 +28,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
28 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); 28 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
29 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); 29 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
30 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); 30 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
31 ui->use_pessimistic_flushes->setChecked(Settings::values.use_pessimistic_flushes.GetValue());
31 32
32 if (Settings::IsConfiguringGlobal()) { 33 if (Settings::IsConfiguringGlobal()) {
33 ui->gpu_accuracy->setCurrentIndex( 34 ui->gpu_accuracy->setCurrentIndex(
@@ -55,6 +56,8 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
55 use_asynchronous_shaders); 56 use_asynchronous_shaders);
56 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, 57 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
57 ui->use_fast_gpu_time, use_fast_gpu_time); 58 ui->use_fast_gpu_time, use_fast_gpu_time);
59 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_pessimistic_flushes,
60 ui->use_pessimistic_flushes, use_pessimistic_flushes);
58} 61}
59 62
60void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { 63void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
@@ -77,6 +80,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
77 ui->use_asynchronous_shaders->setEnabled( 80 ui->use_asynchronous_shaders->setEnabled(
78 Settings::values.use_asynchronous_shaders.UsingGlobal()); 81 Settings::values.use_asynchronous_shaders.UsingGlobal());
79 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); 82 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
83 ui->use_pessimistic_flushes->setEnabled(
84 Settings::values.use_pessimistic_flushes.UsingGlobal());
80 ui->anisotropic_filtering_combobox->setEnabled( 85 ui->anisotropic_filtering_combobox->setEnabled(
81 Settings::values.max_anisotropy.UsingGlobal()); 86 Settings::values.max_anisotropy.UsingGlobal());
82 87
@@ -89,6 +94,9 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
89 use_asynchronous_shaders); 94 use_asynchronous_shaders);
90 ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time, 95 ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time,
91 Settings::values.use_fast_gpu_time, use_fast_gpu_time); 96 Settings::values.use_fast_gpu_time, use_fast_gpu_time);
97 ConfigurationShared::SetColoredTristate(ui->use_pessimistic_flushes,
98 Settings::values.use_pessimistic_flushes,
99 use_pessimistic_flushes);
92 ConfigurationShared::SetColoredComboBox( 100 ConfigurationShared::SetColoredComboBox(
93 ui->gpu_accuracy, ui->label_gpu_accuracy, 101 ui->gpu_accuracy, ui->label_gpu_accuracy,
94 static_cast<int>(Settings::values.gpu_accuracy.GetValue(true))); 102 static_cast<int>(Settings::values.gpu_accuracy.GetValue(true)));
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 1ef7bd916..12e816905 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -39,6 +39,7 @@ private:
39 ConfigurationShared::CheckState use_vsync; 39 ConfigurationShared::CheckState use_vsync;
40 ConfigurationShared::CheckState use_asynchronous_shaders; 40 ConfigurationShared::CheckState use_asynchronous_shaders;
41 ConfigurationShared::CheckState use_fast_gpu_time; 41 ConfigurationShared::CheckState use_fast_gpu_time;
42 ConfigurationShared::CheckState use_pessimistic_flushes;
42 43
43 const Core::System& system; 44 const Core::System& system;
44}; 45};
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index d6d819364..87a121471 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -100,6 +100,16 @@
100 </widget> 100 </widget>
101 </item> 101 </item>
102 <item> 102 <item>
103 <widget class="QCheckBox" name="use_pessimistic_flushes">
104 <property name="toolTip">
105 <string>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</string>
106 </property>
107 <property name="text">
108 <string>Use pessimistic buffer flushes (Hack)</string>
109 </property>
110 </widget>
111 </item>
112 <item>
103 <widget class="QWidget" name="af_layout" native="true"> 113 <widget class="QWidget" name="af_layout" native="true">
104 <layout class="QHBoxLayout" name="horizontalLayout_1"> 114 <layout class="QHBoxLayout" name="horizontalLayout_1">
105 <property name="leftMargin"> 115 <property name="leftMargin">
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index e103df977..a85adc072 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -860,7 +860,7 @@ void GMainWindow::InitializeWidgets() {
860 }); 860 });
861 861
862 multiplayer_state = new MultiplayerState(this, game_list->GetModel(), ui->action_Leave_Room, 862 multiplayer_state = new MultiplayerState(this, game_list->GetModel(), ui->action_Leave_Room,
863 ui->action_Show_Room, system->GetRoomNetwork()); 863 ui->action_Show_Room, *system);
864 multiplayer_state->setVisible(false); 864 multiplayer_state->setVisible(false);
865 865
866 // Create status bar 866 // Create status bar
diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp
index 1968a3c75..9e672f82e 100644
--- a/src/yuzu/multiplayer/chat_room.cpp
+++ b/src/yuzu/multiplayer/chat_room.cpp
@@ -16,7 +16,7 @@
16#include <QUrl> 16#include <QUrl>
17#include <QtConcurrent/QtConcurrentRun> 17#include <QtConcurrent/QtConcurrentRun>
18#include "common/logging/log.h" 18#include "common/logging/log.h"
19#include "core/announce_multiplayer_session.h" 19#include "network/announce_multiplayer_session.h"
20#include "ui_chat_room.h" 20#include "ui_chat_room.h"
21#include "yuzu/game_list_p.h" 21#include "yuzu/game_list_p.h"
22#include "yuzu/multiplayer/chat_room.h" 22#include "yuzu/multiplayer/chat_room.h"
@@ -122,19 +122,22 @@ public:
122 static const int UsernameRole = Qt::UserRole + 2; 122 static const int UsernameRole = Qt::UserRole + 2;
123 static const int AvatarUrlRole = Qt::UserRole + 3; 123 static const int AvatarUrlRole = Qt::UserRole + 3;
124 static const int GameNameRole = Qt::UserRole + 4; 124 static const int GameNameRole = Qt::UserRole + 4;
125 static const int GameVersionRole = Qt::UserRole + 5;
125 126
126 PlayerListItem() = default; 127 PlayerListItem() = default;
127 explicit PlayerListItem(const std::string& nickname, const std::string& username, 128 explicit PlayerListItem(const std::string& nickname, const std::string& username,
128 const std::string& avatar_url, const std::string& game_name) { 129 const std::string& avatar_url,
130 const AnnounceMultiplayerRoom::GameInfo& game_info) {
129 setEditable(false); 131 setEditable(false);
130 setData(QString::fromStdString(nickname), NicknameRole); 132 setData(QString::fromStdString(nickname), NicknameRole);
131 setData(QString::fromStdString(username), UsernameRole); 133 setData(QString::fromStdString(username), UsernameRole);
132 setData(QString::fromStdString(avatar_url), AvatarUrlRole); 134 setData(QString::fromStdString(avatar_url), AvatarUrlRole);
133 if (game_name.empty()) { 135 if (game_info.name.empty()) {
134 setData(QObject::tr("Not playing a game"), GameNameRole); 136 setData(QObject::tr("Not playing a game"), GameNameRole);
135 } else { 137 } else {
136 setData(QString::fromStdString(game_name), GameNameRole); 138 setData(QString::fromStdString(game_info.name), GameNameRole);
137 } 139 }
140 setData(QString::fromStdString(game_info.version), GameVersionRole);
138 } 141 }
139 142
140 QVariant data(int role) const override { 143 QVariant data(int role) const override {
@@ -149,7 +152,13 @@ public:
149 } else { 152 } else {
150 name = QStringLiteral("%1 (%2)").arg(nickname, username); 153 name = QStringLiteral("%1 (%2)").arg(nickname, username);
151 } 154 }
152 return QStringLiteral("%1\n %2").arg(name, data(GameNameRole).toString()); 155 const QString version = data(GameVersionRole).toString();
156 QString version_string;
157 if (!version.isEmpty()) {
158 version_string = QStringLiteral("(%1)").arg(version);
159 }
160 return QStringLiteral("%1\n %2 %3")
161 .arg(name, data(GameNameRole).toString(), version_string);
153 } 162 }
154}; 163};
155 164
@@ -167,6 +176,10 @@ ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::C
167 176
168 ui->chat_history->document()->setMaximumBlockCount(max_chat_lines); 177 ui->chat_history->document()->setMaximumBlockCount(max_chat_lines);
169 178
179 auto font = ui->chat_history->font();
180 font.setPointSizeF(10);
181 ui->chat_history->setFont(font);
182
170 // register the network structs to use in slots and signals 183 // register the network structs to use in slots and signals
171 qRegisterMetaType<Network::ChatEntry>(); 184 qRegisterMetaType<Network::ChatEntry>();
172 qRegisterMetaType<Network::StatusMessageEntry>(); 185 qRegisterMetaType<Network::StatusMessageEntry>();
@@ -366,7 +379,7 @@ void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list)
366 if (member.nickname.empty()) 379 if (member.nickname.empty())
367 continue; 380 continue;
368 QStandardItem* name_item = new PlayerListItem(member.nickname, member.username, 381 QStandardItem* name_item = new PlayerListItem(member.nickname, member.username,
369 member.avatar_url, member.game_info.name); 382 member.avatar_url, member.game_info);
370 383
371#ifdef ENABLE_WEB_SERVICE 384#ifdef ENABLE_WEB_SERVICE
372 if (!icon_cache.count(member.avatar_url) && !member.avatar_url.empty()) { 385 if (!icon_cache.count(member.avatar_url) && !member.avatar_url.empty()) {
diff --git a/src/yuzu/multiplayer/client_room.cpp b/src/yuzu/multiplayer/client_room.cpp
index 86baafbf0..b34a8d004 100644
--- a/src/yuzu/multiplayer/client_room.cpp
+++ b/src/yuzu/multiplayer/client_room.cpp
@@ -10,7 +10,7 @@
10#include <QTime> 10#include <QTime>
11#include <QtConcurrent/QtConcurrentRun> 11#include <QtConcurrent/QtConcurrentRun>
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/announce_multiplayer_session.h" 13#include "network/announce_multiplayer_session.h"
14#include "ui_client_room.h" 14#include "ui_client_room.h"
15#include "yuzu/game_list_p.h" 15#include "yuzu/game_list_p.h"
16#include "yuzu/multiplayer/client_room.h" 16#include "yuzu/multiplayer/client_room.h"
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp
index 4c0ea0a6b..017063074 100644
--- a/src/yuzu/multiplayer/direct_connect.cpp
+++ b/src/yuzu/multiplayer/direct_connect.cpp
@@ -8,6 +8,8 @@
8#include <QString> 8#include <QString>
9#include <QtConcurrent/QtConcurrentRun> 9#include <QtConcurrent/QtConcurrentRun>
10#include "common/settings.h" 10#include "common/settings.h"
11#include "core/core.h"
12#include "core/internal_network/network_interface.h"
11#include "network/network.h" 13#include "network/network.h"
12#include "ui_direct_connect.h" 14#include "ui_direct_connect.h"
13#include "yuzu/main.h" 15#include "yuzu/main.h"
@@ -20,9 +22,10 @@
20 22
21enum class ConnectionType : u8 { TraversalServer, IP }; 23enum class ConnectionType : u8 { TraversalServer, IP };
22 24
23DirectConnectWindow::DirectConnectWindow(Network::RoomNetwork& room_network_, QWidget* parent) 25DirectConnectWindow::DirectConnectWindow(Core::System& system_, QWidget* parent)
24 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), 26 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
25 ui(std::make_unique<Ui::DirectConnect>()), room_network{room_network_} { 27 ui(std::make_unique<Ui::DirectConnect>()), system{system_}, room_network{
28 system.GetRoomNetwork()} {
26 29
27 ui->setupUi(this); 30 ui->setupUi(this);
28 31
@@ -53,10 +56,20 @@ void DirectConnectWindow::RetranslateUi() {
53} 56}
54 57
55void DirectConnectWindow::Connect() { 58void DirectConnectWindow::Connect() {
59 if (!Network::GetSelectedNetworkInterface()) {
60 NetworkMessage::ErrorManager::ShowError(
61 NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED);
62 return;
63 }
56 if (!ui->nickname->hasAcceptableInput()) { 64 if (!ui->nickname->hasAcceptableInput()) {
57 NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::USERNAME_NOT_VALID); 65 NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::USERNAME_NOT_VALID);
58 return; 66 return;
59 } 67 }
68 if (system.IsPoweredOn()) {
69 if (!NetworkMessage::WarnGameRunning()) {
70 return;
71 }
72 }
60 if (const auto member = room_network.GetRoomMember().lock()) { 73 if (const auto member = room_network.GetRoomMember().lock()) {
61 // Prevent the user from trying to join a room while they are already joining. 74 // Prevent the user from trying to join a room while they are already joining.
62 if (member->GetState() == Network::RoomMember::State::Joining) { 75 if (member->GetState() == Network::RoomMember::State::Joining) {
diff --git a/src/yuzu/multiplayer/direct_connect.h b/src/yuzu/multiplayer/direct_connect.h
index 4e1043053..e39dd1e0d 100644
--- a/src/yuzu/multiplayer/direct_connect.h
+++ b/src/yuzu/multiplayer/direct_connect.h
@@ -12,11 +12,15 @@ namespace Ui {
12class DirectConnect; 12class DirectConnect;
13} 13}
14 14
15namespace Core {
16class System;
17}
18
15class DirectConnectWindow : public QDialog { 19class DirectConnectWindow : public QDialog {
16 Q_OBJECT 20 Q_OBJECT
17 21
18public: 22public:
19 explicit DirectConnectWindow(Network::RoomNetwork& room_network_, QWidget* parent = nullptr); 23 explicit DirectConnectWindow(Core::System& system_, QWidget* parent = nullptr);
20 ~DirectConnectWindow(); 24 ~DirectConnectWindow();
21 25
22 void RetranslateUi(); 26 void RetranslateUi();
@@ -39,5 +43,6 @@ private:
39 QFutureWatcher<void>* watcher; 43 QFutureWatcher<void>* watcher;
40 std::unique_ptr<Ui::DirectConnect> ui; 44 std::unique_ptr<Ui::DirectConnect> ui;
41 Validation validation; 45 Validation validation;
46 Core::System& system;
42 Network::RoomNetwork& room_network; 47 Network::RoomNetwork& room_network;
43}; 48};
diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp
index d70a9a3c8..0c6adfd04 100644
--- a/src/yuzu/multiplayer/host_room.cpp
+++ b/src/yuzu/multiplayer/host_room.cpp
@@ -12,7 +12,9 @@
12#include <QtConcurrent/QtConcurrentRun> 12#include <QtConcurrent/QtConcurrentRun>
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/settings.h" 14#include "common/settings.h"
15#include "core/announce_multiplayer_session.h" 15#include "core/core.h"
16#include "core/internal_network/network_interface.h"
17#include "network/announce_multiplayer_session.h"
16#include "ui_host_room.h" 18#include "ui_host_room.h"
17#include "yuzu/game_list_p.h" 19#include "yuzu/game_list_p.h"
18#include "yuzu/main.h" 20#include "yuzu/main.h"
@@ -27,10 +29,11 @@
27 29
28HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list, 30HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
29 std::shared_ptr<Core::AnnounceMultiplayerSession> session, 31 std::shared_ptr<Core::AnnounceMultiplayerSession> session,
30 Network::RoomNetwork& room_network_) 32 Core::System& system_)
31 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), 33 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
32 ui(std::make_unique<Ui::HostRoom>()), 34 ui(std::make_unique<Ui::HostRoom>()),
33 announce_multiplayer_session(session), room_network{room_network_} { 35 announce_multiplayer_session(session), system{system_}, room_network{
36 system.GetRoomNetwork()} {
34 ui->setupUi(this); 37 ui->setupUi(this);
35 38
36 // set up validation for all of the fields 39 // set up validation for all of the fields
@@ -105,6 +108,11 @@ std::unique_ptr<Network::VerifyUser::Backend> HostRoomWindow::CreateVerifyBacken
105} 108}
106 109
107void HostRoomWindow::Host() { 110void HostRoomWindow::Host() {
111 if (!Network::GetSelectedNetworkInterface()) {
112 NetworkMessage::ErrorManager::ShowError(
113 NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED);
114 return;
115 }
108 if (!ui->username->hasAcceptableInput()) { 116 if (!ui->username->hasAcceptableInput()) {
109 NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::USERNAME_NOT_VALID); 117 NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::USERNAME_NOT_VALID);
110 return; 118 return;
@@ -121,6 +129,11 @@ void HostRoomWindow::Host() {
121 NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::GAME_NOT_SELECTED); 129 NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::GAME_NOT_SELECTED);
122 return; 130 return;
123 } 131 }
132 if (system.IsPoweredOn()) {
133 if (!NetworkMessage::WarnGameRunning()) {
134 return;
135 }
136 }
124 if (auto member = room_network.GetRoomMember().lock()) { 137 if (auto member = room_network.GetRoomMember().lock()) {
125 if (member->GetState() == Network::RoomMember::State::Joining) { 138 if (member->GetState() == Network::RoomMember::State::Joining) {
126 return; 139 return;
diff --git a/src/yuzu/multiplayer/host_room.h b/src/yuzu/multiplayer/host_room.h
index a968042d0..034cb2eef 100644
--- a/src/yuzu/multiplayer/host_room.h
+++ b/src/yuzu/multiplayer/host_room.h
@@ -17,8 +17,9 @@ class HostRoom;
17} 17}
18 18
19namespace Core { 19namespace Core {
20class System;
20class AnnounceMultiplayerSession; 21class AnnounceMultiplayerSession;
21} 22} // namespace Core
22 23
23class ConnectionError; 24class ConnectionError;
24class ComboBoxProxyModel; 25class ComboBoxProxyModel;
@@ -35,7 +36,7 @@ class HostRoomWindow : public QDialog {
35public: 36public:
36 explicit HostRoomWindow(QWidget* parent, QStandardItemModel* list, 37 explicit HostRoomWindow(QWidget* parent, QStandardItemModel* list,
37 std::shared_ptr<Core::AnnounceMultiplayerSession> session, 38 std::shared_ptr<Core::AnnounceMultiplayerSession> session,
38 Network::RoomNetwork& room_network_); 39 Core::System& system_);
39 ~HostRoomWindow(); 40 ~HostRoomWindow();
40 41
41 /** 42 /**
@@ -54,6 +55,7 @@ private:
54 QStandardItemModel* game_list; 55 QStandardItemModel* game_list;
55 ComboBoxProxyModel* proxy; 56 ComboBoxProxyModel* proxy;
56 Validation validation; 57 Validation validation;
58 Core::System& system;
57 Network::RoomNetwork& room_network; 59 Network::RoomNetwork& room_network;
58}; 60};
59 61
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index 1cc518279..107d40547 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -6,6 +6,8 @@
6#include <QtConcurrent/QtConcurrentRun> 6#include <QtConcurrent/QtConcurrentRun>
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h" 8#include "common/settings.h"
9#include "core/core.h"
10#include "core/internal_network/network_interface.h"
9#include "network/network.h" 11#include "network/network.h"
10#include "ui_lobby.h" 12#include "ui_lobby.h"
11#include "yuzu/game_list_p.h" 13#include "yuzu/game_list_p.h"
@@ -22,11 +24,11 @@
22#endif 24#endif
23 25
24Lobby::Lobby(QWidget* parent, QStandardItemModel* list, 26Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
25 std::shared_ptr<Core::AnnounceMultiplayerSession> session, 27 std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_)
26 Network::RoomNetwork& room_network_)
27 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), 28 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
28 ui(std::make_unique<Ui::Lobby>()), 29 ui(std::make_unique<Ui::Lobby>()),
29 announce_multiplayer_session(session), room_network{room_network_} { 30 announce_multiplayer_session(session), system{system_}, room_network{
31 system.GetRoomNetwork()} {
30 ui->setupUi(this); 32 ui->setupUi(this);
31 33
32 // setup the watcher for background connections 34 // setup the watcher for background connections
@@ -114,6 +116,18 @@ void Lobby::OnExpandRoom(const QModelIndex& index) {
114} 116}
115 117
116void Lobby::OnJoinRoom(const QModelIndex& source) { 118void Lobby::OnJoinRoom(const QModelIndex& source) {
119 if (!Network::GetSelectedNetworkInterface()) {
120 NetworkMessage::ErrorManager::ShowError(
121 NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED);
122 return;
123 }
124
125 if (system.IsPoweredOn()) {
126 if (!NetworkMessage::WarnGameRunning()) {
127 return;
128 }
129 }
130
117 if (const auto member = room_network.GetRoomMember().lock()) { 131 if (const auto member = room_network.GetRoomMember().lock()) {
118 // Prevent the user from trying to join a room while they are already joining. 132 // Prevent the user from trying to join a room while they are already joining.
119 if (member->GetState() == Network::RoomMember::State::Joining) { 133 if (member->GetState() == Network::RoomMember::State::Joining) {
diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h
index 82744ca94..2696aec21 100644
--- a/src/yuzu/multiplayer/lobby.h
+++ b/src/yuzu/multiplayer/lobby.h
@@ -9,7 +9,7 @@
9#include <QSortFilterProxyModel> 9#include <QSortFilterProxyModel>
10#include <QStandardItemModel> 10#include <QStandardItemModel>
11#include "common/announce_multiplayer_room.h" 11#include "common/announce_multiplayer_room.h"
12#include "core/announce_multiplayer_session.h" 12#include "network/announce_multiplayer_session.h"
13#include "network/network.h" 13#include "network/network.h"
14#include "yuzu/multiplayer/validation.h" 14#include "yuzu/multiplayer/validation.h"
15 15
@@ -20,6 +20,10 @@ class Lobby;
20class LobbyModel; 20class LobbyModel;
21class LobbyFilterProxyModel; 21class LobbyFilterProxyModel;
22 22
23namespace Core {
24class System;
25}
26
23/** 27/**
24 * Listing of all public games pulled from services. The lobby should be simple enough for users to 28 * Listing of all public games pulled from services. The lobby should be simple enough for users to
25 * find the game they want to play, and join it. 29 * find the game they want to play, and join it.
@@ -30,7 +34,7 @@ class Lobby : public QDialog {
30public: 34public:
31 explicit Lobby(QWidget* parent, QStandardItemModel* list, 35 explicit Lobby(QWidget* parent, QStandardItemModel* list,
32 std::shared_ptr<Core::AnnounceMultiplayerSession> session, 36 std::shared_ptr<Core::AnnounceMultiplayerSession> session,
33 Network::RoomNetwork& room_network_); 37 Core::System& system_);
34 ~Lobby() override; 38 ~Lobby() override;
35 39
36 /** 40 /**
@@ -94,6 +98,7 @@ private:
94 std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; 98 std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
95 QFutureWatcher<void>* watcher; 99 QFutureWatcher<void>* watcher;
96 Validation validation; 100 Validation validation;
101 Core::System& system;
97 Network::RoomNetwork& room_network; 102 Network::RoomNetwork& room_network;
98}; 103};
99 104
diff --git a/src/yuzu/multiplayer/message.cpp b/src/yuzu/multiplayer/message.cpp
index 94d7a38b8..758b5b731 100644
--- a/src/yuzu/multiplayer/message.cpp
+++ b/src/yuzu/multiplayer/message.cpp
@@ -49,6 +49,9 @@ const ConnectionError ErrorManager::PERMISSION_DENIED(
49 QT_TR_NOOP("You do not have enough permission to perform this action.")); 49 QT_TR_NOOP("You do not have enough permission to perform this action."));
50const ConnectionError ErrorManager::NO_SUCH_USER(QT_TR_NOOP( 50const ConnectionError ErrorManager::NO_SUCH_USER(QT_TR_NOOP(
51 "The user you are trying to kick/ban could not be found.\nThey may have left the room.")); 51 "The user you are trying to kick/ban could not be found.\nThey may have left the room."));
52const ConnectionError ErrorManager::NO_INTERFACE_SELECTED(
53 QT_TR_NOOP("No network interface is selected.\nPlease go to Configure -> System -> Network and "
54 "make a selection."));
52 55
53static bool WarnMessage(const std::string& title, const std::string& text) { 56static bool WarnMessage(const std::string& title, const std::string& text) {
54 return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()), 57 return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()),
@@ -60,6 +63,13 @@ void ErrorManager::ShowError(const ConnectionError& e) {
60 QMessageBox::critical(nullptr, tr("Error"), tr(e.GetString().c_str())); 63 QMessageBox::critical(nullptr, tr("Error"), tr(e.GetString().c_str()));
61} 64}
62 65
66bool WarnGameRunning() {
67 return WarnMessage(
68 QT_TR_NOOP("Game already running"),
69 QT_TR_NOOP("Joining a room when the game is already running is discouraged "
70 "and can cause the room feature not to work correctly.\nProceed anyway?"));
71}
72
63bool WarnCloseRoom() { 73bool WarnCloseRoom() {
64 return WarnMessage( 74 return WarnMessage(
65 QT_TR_NOOP("Leave Room"), 75 QT_TR_NOOP("Leave Room"),
diff --git a/src/yuzu/multiplayer/message.h b/src/yuzu/multiplayer/message.h
index 812495c72..f038b9a1f 100644
--- a/src/yuzu/multiplayer/message.h
+++ b/src/yuzu/multiplayer/message.h
@@ -43,11 +43,20 @@ public:
43 static const ConnectionError IP_COLLISION; 43 static const ConnectionError IP_COLLISION;
44 static const ConnectionError PERMISSION_DENIED; 44 static const ConnectionError PERMISSION_DENIED;
45 static const ConnectionError NO_SUCH_USER; 45 static const ConnectionError NO_SUCH_USER;
46 static const ConnectionError NO_INTERFACE_SELECTED;
46 /** 47 /**
47 * Shows a standard QMessageBox with a error message 48 * Shows a standard QMessageBox with a error message
48 */ 49 */
49 static void ShowError(const ConnectionError& e); 50 static void ShowError(const ConnectionError& e);
50}; 51};
52
53/**
54 * Show a standard QMessageBox with a warning message about joining a room when
55 * the game is already running
56 * return true if the user wants to close the network connection
57 */
58bool WarnGameRunning();
59
51/** 60/**
52 * Show a standard QMessageBox with a warning message about leaving the room 61 * Show a standard QMessageBox with a warning message about leaving the room
53 * return true if the user wants to close the network connection 62 * return true if the user wants to close the network connection
diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp
index dba76b22b..66e098296 100644
--- a/src/yuzu/multiplayer/state.cpp
+++ b/src/yuzu/multiplayer/state.cpp
@@ -8,6 +8,7 @@
8#include <QStandardItemModel> 8#include <QStandardItemModel>
9#include "common/announce_multiplayer_room.h" 9#include "common/announce_multiplayer_room.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/core.h"
11#include "yuzu/game_list.h" 12#include "yuzu/game_list.h"
12#include "yuzu/multiplayer/client_room.h" 13#include "yuzu/multiplayer/client_room.h"
13#include "yuzu/multiplayer/direct_connect.h" 14#include "yuzu/multiplayer/direct_connect.h"
@@ -19,10 +20,9 @@
19#include "yuzu/util/clickable_label.h" 20#include "yuzu/util/clickable_label.h"
20 21
21MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model_, 22MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model_,
22 QAction* leave_room_, QAction* show_room_, 23 QAction* leave_room_, QAction* show_room_, Core::System& system_)
23 Network::RoomNetwork& room_network_)
24 : QWidget(parent), game_list_model(game_list_model_), leave_room(leave_room_), 24 : QWidget(parent), game_list_model(game_list_model_), leave_room(leave_room_),
25 show_room(show_room_), room_network{room_network_} { 25 show_room(show_room_), system{system_}, room_network{system.GetRoomNetwork()} {
26 if (auto member = room_network.GetRoomMember().lock()) { 26 if (auto member = room_network.GetRoomMember().lock()) {
27 // register the network structs to use in slots and signals 27 // register the network structs to use in slots and signals
28 state_callback_handle = member->BindOnStateChanged( 28 state_callback_handle = member->BindOnStateChanged(
@@ -208,15 +208,14 @@ static void BringWidgetToFront(QWidget* widget) {
208 208
209void MultiplayerState::OnViewLobby() { 209void MultiplayerState::OnViewLobby() {
210 if (lobby == nullptr) { 210 if (lobby == nullptr) {
211 lobby = new Lobby(this, game_list_model, announce_multiplayer_session, room_network); 211 lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system);
212 } 212 }
213 BringWidgetToFront(lobby); 213 BringWidgetToFront(lobby);
214} 214}
215 215
216void MultiplayerState::OnCreateRoom() { 216void MultiplayerState::OnCreateRoom() {
217 if (host_room == nullptr) { 217 if (host_room == nullptr) {
218 host_room = 218 host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system);
219 new HostRoomWindow(this, game_list_model, announce_multiplayer_session, room_network);
220 } 219 }
221 BringWidgetToFront(host_room); 220 BringWidgetToFront(host_room);
222} 221}
@@ -279,7 +278,7 @@ void MultiplayerState::OnOpenNetworkRoom() {
279 278
280void MultiplayerState::OnDirectConnectToRoom() { 279void MultiplayerState::OnDirectConnectToRoom() {
281 if (direct_connect == nullptr) { 280 if (direct_connect == nullptr) {
282 direct_connect = new DirectConnectWindow(room_network, this); 281 direct_connect = new DirectConnectWindow(system, this);
283 } 282 }
284 BringWidgetToFront(direct_connect); 283 BringWidgetToFront(direct_connect);
285} 284}
diff --git a/src/yuzu/multiplayer/state.h b/src/yuzu/multiplayer/state.h
index 9c60712d5..c92496413 100644
--- a/src/yuzu/multiplayer/state.h
+++ b/src/yuzu/multiplayer/state.h
@@ -4,7 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <QWidget> 6#include <QWidget>
7#include "core/announce_multiplayer_session.h" 7#include "network/announce_multiplayer_session.h"
8#include "network/network.h" 8#include "network/network.h"
9 9
10class QStandardItemModel; 10class QStandardItemModel;
@@ -14,12 +14,16 @@ class ClientRoomWindow;
14class DirectConnectWindow; 14class DirectConnectWindow;
15class ClickableLabel; 15class ClickableLabel;
16 16
17namespace Core {
18class System;
19}
20
17class MultiplayerState : public QWidget { 21class MultiplayerState : public QWidget {
18 Q_OBJECT; 22 Q_OBJECT;
19 23
20public: 24public:
21 explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room, 25 explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room,
22 QAction* show_room, Network::RoomNetwork& room_network_); 26 QAction* show_room, Core::System& system_);
23 ~MultiplayerState(); 27 ~MultiplayerState();
24 28
25 /** 29 /**
@@ -86,6 +90,7 @@ private:
86 Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle; 90 Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle;
87 91
88 bool show_notification = false; 92 bool show_notification = false;
93 Core::System& system;
89 Network::RoomNetwork& room_network; 94 Network::RoomNetwork& room_network;
90}; 95};
91 96
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index bd0fb75f8..66dd0dc15 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -314,6 +314,7 @@ void Config::ReadValues() {
314 ReadSetting("Renderer", Settings::values.nvdec_emulation); 314 ReadSetting("Renderer", Settings::values.nvdec_emulation);
315 ReadSetting("Renderer", Settings::values.accelerate_astc); 315 ReadSetting("Renderer", Settings::values.accelerate_astc);
316 ReadSetting("Renderer", Settings::values.use_fast_gpu_time); 316 ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
317 ReadSetting("Renderer", Settings::values.use_pessimistic_flushes);
317 318
318 ReadSetting("Renderer", Settings::values.bg_red); 319 ReadSetting("Renderer", Settings::values.bg_red);
319 ReadSetting("Renderer", Settings::values.bg_green); 320 ReadSetting("Renderer", Settings::values.bg_green);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 1168cf136..d214771b0 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -319,6 +319,10 @@ use_asynchronous_gpu_emulation =
319# 0: Off, 1 (default): On 319# 0: Off, 1 (default): On
320use_fast_gpu_time = 320use_fast_gpu_time =
321 321
322# Force unmodified buffers to be flushed, which can cost performance.
323# 0: Off (default), 1: On
324use_pessimistic_flushes =
325
322# Whether to use garbage collection or not for GPU caches. 326# Whether to use garbage collection or not for GPU caches.
323# 0 (default): Off, 1: On 327# 0 (default): Off, 1: On
324use_caches_gc = 328use_caches_gc =