summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/announce_multiplayer_room.h1
-rw-r--r--src/common/parent_of_member.h2
-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/hid/emulated_controller.cpp35
-rw-r--r--src/core/hid/emulated_controller.h1
-rw-r--r--src/core/hle/service/acc/acc.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.cpp2
-rw-r--r--src/core/hle/service/apm/apm_controller.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp14
-rw-r--r--src/core/hle/service/ldn/ldn_types.h16
-rw-r--r--src/core/hle/service/mm/mm_u.cpp10
-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/nvdrv/devices/nvmap.cpp4
-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/backend/glasm/emit_glasm_image.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp1
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp1
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp5
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h2
-rw-r--r--src/shader_recompiler/ir_opt/rescaling_pass.cpp7
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp23
-rw-r--r--src/shader_recompiler/shader_info.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp9
-rw-r--r--src/video_core/shader_environment.cpp6
-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/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
61 files changed, 347 insertions, 120 deletions
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/parent_of_member.h b/src/common/parent_of_member.h
index 70b1c5624..8e03f17d8 100644
--- a/src/common/parent_of_member.h
+++ b/src/common/parent_of_member.h
@@ -11,7 +11,7 @@ namespace Common {
11namespace detail { 11namespace detail {
12template <typename T, size_t Size, size_t Align> 12template <typename T, size_t Size, size_t Align>
13struct TypedStorageImpl { 13struct TypedStorageImpl {
14 std::aligned_storage_t<Size, Align> storage_; 14 alignas(Align) u8 storage_[Size];
15}; 15};
16} // namespace detail 16} // namespace detail
17 17
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/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 049602e7d..f9f902c2d 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -101,8 +101,10 @@ void EmulatedController::ReloadFromSettings() {
101 // Other or debug controller should always be a pro controller 101 // Other or debug controller should always be a pro controller
102 if (npad_id_type != NpadIdType::Other) { 102 if (npad_id_type != NpadIdType::Other) {
103 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); 103 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
104 original_npad_type = npad_type;
104 } else { 105 } else {
105 SetNpadStyleIndex(NpadStyleIndex::ProController); 106 SetNpadStyleIndex(NpadStyleIndex::ProController);
107 original_npad_type = npad_type;
106 } 108 }
107 109
108 if (player.connected) { 110 if (player.connected) {
@@ -354,6 +356,7 @@ void EmulatedController::DisableConfiguration() {
354 Disconnect(); 356 Disconnect();
355 } 357 }
356 SetNpadStyleIndex(tmp_npad_type); 358 SetNpadStyleIndex(tmp_npad_type);
359 original_npad_type = tmp_npad_type;
357 } 360 }
358 361
359 // Apply temporary connected status to the real controller 362 // Apply temporary connected status to the real controller
@@ -1004,13 +1007,27 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
1004 if (!is_connected) { 1007 if (!is_connected) {
1005 return; 1008 return;
1006 } 1009 }
1010
1011 // Attempt to reconnect with the original type
1012 if (npad_type != original_npad_type) {
1013 Disconnect();
1014 const auto current_npad_type = npad_type;
1015 SetNpadStyleIndex(original_npad_type);
1016 if (IsControllerSupported()) {
1017 Connect();
1018 return;
1019 }
1020 SetNpadStyleIndex(current_npad_type);
1021 Connect();
1022 }
1023
1007 if (IsControllerSupported()) { 1024 if (IsControllerSupported()) {
1008 return; 1025 return;
1009 } 1026 }
1010 1027
1011 Disconnect(); 1028 Disconnect();
1012 1029
1013 // Fallback fullkey controllers to Pro controllers 1030 // Fallback Fullkey controllers to Pro controllers
1014 if (IsControllerFullkey() && supported_style_tag.fullkey) { 1031 if (IsControllerFullkey() && supported_style_tag.fullkey) {
1015 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); 1032 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1016 SetNpadStyleIndex(NpadStyleIndex::ProController); 1033 SetNpadStyleIndex(NpadStyleIndex::ProController);
@@ -1018,6 +1035,22 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
1018 return; 1035 return;
1019 } 1036 }
1020 1037
1038 // Fallback Dual joycon controllers to Pro controllers
1039 if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
1040 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1041 SetNpadStyleIndex(NpadStyleIndex::ProController);
1042 Connect();
1043 return;
1044 }
1045
1046 // Fallback Pro controllers to Dual joycon
1047 if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) {
1048 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type);
1049 SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
1050 Connect();
1051 return;
1052 }
1053
1021 LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller", 1054 LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller",
1022 npad_type); 1055 npad_type);
1023} 1056}
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index cbd7c26d3..c3aa8f9d3 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -440,6 +440,7 @@ private:
440 440
441 const NpadIdType npad_id_type; 441 const NpadIdType npad_id_type;
442 NpadStyleIndex npad_type{NpadStyleIndex::None}; 442 NpadStyleIndex npad_type{NpadStyleIndex::None};
443 NpadStyleIndex original_npad_type{NpadStyleIndex::None};
443 NpadStyleTag supported_style_tag{NpadStyleSet::All}; 444 NpadStyleTag supported_style_tag{NpadStyleSet::All};
444 bool is_connected{false}; 445 bool is_connected{false};
445 bool is_configuring{false}; 446 bool is_configuring{false};
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/am.cpp b/src/core/hle/service/am/am.cpp
index 118f226e4..6fb7e198e 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -754,7 +754,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
754} 754}
755 755
756void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { 756void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
757 LOG_WARNING(Service_AM, "(STUBBED) called"); 757 LOG_DEBUG(Service_AM, "(STUBBED) called");
758 758
759 IPC::ResponseBuilder rb{ctx, 3}; 759 IPC::ResponseBuilder rb{ctx, 3};
760 rb.Push(ResultSuccess); 760 rb.Push(ResultSuccess);
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/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp
index 4e710491b..d6de84066 100644
--- a/src/core/hle/service/apm/apm_controller.cpp
+++ b/src/core/hle/service/apm/apm_controller.cpp
@@ -80,7 +80,7 @@ PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(Performa
80} 80}
81 81
82void Controller::SetClockSpeed(u32 mhz) { 82void Controller::SetClockSpeed(u32 mhz) {
83 LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); 83 LOG_DEBUG(Service_APM, "called, mhz={:08X}", mhz);
84 // TODO(DarkLordZach): Actually signal core_timing to change clock speed. 84 // TODO(DarkLordZach): Actually signal core_timing to change clock speed.
85 // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used. 85 // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used.
86} 86}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 7909141c0..3d3457160 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -819,12 +819,12 @@ void Hid::EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx
819 const auto result = controller.EnableSixAxisSensorUnalteredPassthrough( 819 const auto result = controller.EnableSixAxisSensorUnalteredPassthrough(
820 parameters.sixaxis_handle, parameters.enabled); 820 parameters.sixaxis_handle, parameters.enabled);
821 821
822 LOG_WARNING(Service_HID, 822 LOG_DEBUG(Service_HID,
823 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, " 823 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
824 "applet_resource_user_id={}", 824 "applet_resource_user_id={}",
825 parameters.enabled, parameters.sixaxis_handle.npad_type, 825 parameters.enabled, parameters.sixaxis_handle.npad_type,
826 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, 826 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
827 parameters.applet_resource_user_id); 827 parameters.applet_resource_user_id);
828 828
829 IPC::ResponseBuilder rb{ctx, 2}; 829 IPC::ResponseBuilder rb{ctx, 2};
830 rb.Push(result); 830 rb.Push(result);
@@ -846,7 +846,7 @@ void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext&
846 const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled( 846 const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled(
847 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled); 847 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
848 848
849 LOG_WARNING( 849 LOG_DEBUG(
850 Service_HID, 850 Service_HID,
851 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 851 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
852 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, 852 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
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/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index 5ebb124a7..ba8c0e230 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -46,7 +46,7 @@ private:
46 IPC::RequestParser rp{ctx}; 46 IPC::RequestParser rp{ctx};
47 min = rp.Pop<u32>(); 47 min = rp.Pop<u32>();
48 max = rp.Pop<u32>(); 48 max = rp.Pop<u32>();
49 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); 49 LOG_DEBUG(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
50 50
51 current = min; 51 current = min;
52 IPC::ResponseBuilder rb{ctx, 2}; 52 IPC::ResponseBuilder rb{ctx, 2};
@@ -54,7 +54,7 @@ private:
54 } 54 }
55 55
56 void GetOld(Kernel::HLERequestContext& ctx) { 56 void GetOld(Kernel::HLERequestContext& ctx) {
57 LOG_WARNING(Service_MM, "(STUBBED) called"); 57 LOG_DEBUG(Service_MM, "(STUBBED) called");
58 58
59 IPC::ResponseBuilder rb{ctx, 3}; 59 IPC::ResponseBuilder rb{ctx, 3};
60 rb.Push(ResultSuccess); 60 rb.Push(ResultSuccess);
@@ -81,8 +81,8 @@ private:
81 u32 input_id = rp.Pop<u32>(); 81 u32 input_id = rp.Pop<u32>();
82 min = rp.Pop<u32>(); 82 min = rp.Pop<u32>();
83 max = rp.Pop<u32>(); 83 max = rp.Pop<u32>();
84 LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", 84 LOG_DEBUG(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", input_id,
85 input_id, min, max); 85 min, max);
86 86
87 current = min; 87 current = min;
88 IPC::ResponseBuilder rb{ctx, 2}; 88 IPC::ResponseBuilder rb{ctx, 2};
@@ -90,7 +90,7 @@ private:
90 } 90 }
91 91
92 void Get(Kernel::HLERequestContext& ctx) { 92 void Get(Kernel::HLERequestContext& ctx) {
93 LOG_WARNING(Service_MM, "(STUBBED) called"); 93 LOG_DEBUG(Service_MM, "(STUBBED) called");
94 94
95 IPC::ResponseBuilder rb{ctx, 3}; 95 IPC::ResponseBuilder rb{ctx, 3};
96 rb.Push(ResultSuccess); 96 rb.Push(ResultSuccess);
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/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 728bfa00b..d8518149d 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -198,7 +198,7 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output)
198 IocParamParams params; 198 IocParamParams params;
199 std::memcpy(&params, input.data(), sizeof(params)); 199 std::memcpy(&params, input.data(), sizeof(params));
200 200
201 LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); 201 LOG_DEBUG(Service_NVDRV, "(STUBBED) called type={}", params.param);
202 202
203 auto object = GetObject(params.handle); 203 auto object = GetObject(params.handle);
204 if (!object) { 204 if (!object) {
@@ -243,7 +243,7 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
243 IocFreeParams params; 243 IocFreeParams params;
244 std::memcpy(&params, input.data(), sizeof(params)); 244 std::memcpy(&params, input.data(), sizeof(params));
245 245
246 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 246 LOG_DEBUG(Service_NVDRV, "(STUBBED) called");
247 247
248 auto itr = handles.find(params.handle); 248 auto itr = handles.find(params.handle);
249 if (itr == handles.end()) { 249 if (itr == handles.end()) {
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/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index a97b143e4..e67e80fac 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -67,6 +67,7 @@ std::string_view TextureType(IR::TextureInstInfo info) {
67 case TextureType::ColorArray1D: 67 case TextureType::ColorArray1D:
68 return "SHADOWARRAY1D"; 68 return "SHADOWARRAY1D";
69 case TextureType::Color2D: 69 case TextureType::Color2D:
70 case TextureType::Color2DRect:
70 return "SHADOW2D"; 71 return "SHADOW2D";
71 case TextureType::ColorArray2D: 72 case TextureType::ColorArray2D:
72 return "SHADOWARRAY2D"; 73 return "SHADOWARRAY2D";
@@ -86,6 +87,7 @@ std::string_view TextureType(IR::TextureInstInfo info) {
86 case TextureType::ColorArray1D: 87 case TextureType::ColorArray1D:
87 return "ARRAY1D"; 88 return "ARRAY1D";
88 case TextureType::Color2D: 89 case TextureType::Color2D:
90 case TextureType::Color2DRect:
89 return "2D"; 91 return "2D";
90 case TextureType::ColorArray2D: 92 case TextureType::ColorArray2D:
91 return "ARRAY2D"; 93 return "ARRAY2D";
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index 6af7e3fe6..cecdbb9d6 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -466,6 +466,7 @@ void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value&
466 case TextureType::ColorArray1D: 466 case TextureType::ColorArray1D:
467 case TextureType::Color2D: 467 case TextureType::Color2D:
468 case TextureType::ColorCube: 468 case TextureType::ColorCube:
469 case TextureType::Color2DRect:
469 return ctx.AddU32x4( 470 return ctx.AddU32x4(
470 "{}=uvec4(uvec2(textureSize({},int({}))),0u,uint(textureQueryLevels({})));", inst, 471 "{}=uvec4(uvec2(textureSize({},int({}))),0u,uint(textureQueryLevels({})));", inst,
471 texture, lod, texture); 472 texture, lod, texture);
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index 221b06328..c767a9dc3 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -86,6 +86,7 @@ std::string_view SamplerType(TextureType type, bool is_depth) {
86 case TextureType::ColorArray1D: 86 case TextureType::ColorArray1D:
87 return "sampler1DArray"; 87 return "sampler1DArray";
88 case TextureType::Color2D: 88 case TextureType::Color2D:
89 case TextureType::Color2DRect:
89 return "sampler2D"; 90 return "sampler2D";
90 case TextureType::ColorArray2D: 91 case TextureType::ColorArray2D:
91 return "sampler2DArray"; 92 return "sampler2DArray";
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index d8d86c91a..fb5799c42 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -453,6 +453,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
453 case TextureType::ColorArray1D: 453 case TextureType::ColorArray1D:
454 case TextureType::Color2D: 454 case TextureType::Color2D:
455 case TextureType::ColorCube: 455 case TextureType::ColorCube:
456 case TextureType::Color2DRect:
456 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod), 457 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod),
457 zero, mips()); 458 zero, mips());
458 case TextureType::ColorArray2D: 459 case TextureType::ColorArray2D:
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 98dd9035a..aecc4c612 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -41,6 +41,7 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
41 case TextureType::ColorArray1D: 41 case TextureType::ColorArray1D:
42 return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format); 42 return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format);
43 case TextureType::Color2D: 43 case TextureType::Color2D:
44 case TextureType::Color2DRect:
44 return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format); 45 return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format);
45 case TextureType::ColorArray2D: 46 case TextureType::ColorArray2D:
46 return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format); 47 return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format);
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index d2b658bca..11086ed8c 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -1832,6 +1832,11 @@ Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod) {
1832 return Inst(op, handle, lod); 1832 return Inst(op, handle, lod);
1833} 1833}
1834 1834
1835Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
1836 TextureInstInfo info) {
1837 return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod);
1838}
1839
1835Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, TextureInstInfo info) { 1840Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, TextureInstInfo info) {
1836 const Opcode op{handle.IsImmediate() ? Opcode::BoundImageQueryLod 1841 const Opcode op{handle.IsImmediate() ? Opcode::BoundImageQueryLod
1837 : Opcode::BindlessImageQueryLod}; 1842 : Opcode::BindlessImageQueryLod};
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index c29bda558..25839a371 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -315,6 +315,8 @@ public:
315 const F32& dref, const F32& lod, 315 const F32& dref, const F32& lod,
316 const Value& offset, TextureInstInfo info); 316 const Value& offset, TextureInstInfo info);
317 [[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod); 317 [[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod);
318 [[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
319 TextureInstInfo info);
318 320
319 [[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords, 321 [[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords,
320 TextureInstInfo info); 322 TextureInstInfo info);
diff --git a/src/shader_recompiler/ir_opt/rescaling_pass.cpp b/src/shader_recompiler/ir_opt/rescaling_pass.cpp
index 0d5f2e4d8..9198fa5f2 100644
--- a/src/shader_recompiler/ir_opt/rescaling_pass.cpp
+++ b/src/shader_recompiler/ir_opt/rescaling_pass.cpp
@@ -16,6 +16,7 @@ namespace {
16 switch (type) { 16 switch (type) {
17 case TextureType::Color2D: 17 case TextureType::Color2D:
18 case TextureType::ColorArray2D: 18 case TextureType::ColorArray2D:
19 case TextureType::Color2DRect:
19 return true; 20 return true;
20 case TextureType::Color1D: 21 case TextureType::Color1D:
21 case TextureType::ColorArray1D: 22 case TextureType::ColorArray1D:
@@ -132,7 +133,8 @@ void PatchImageQueryDimensions(IR::Block& block, IR::Inst& inst) {
132 const IR::U1 is_scaled{ir.IsTextureScaled(ir.Imm32(info.descriptor_index))}; 133 const IR::U1 is_scaled{ir.IsTextureScaled(ir.Imm32(info.descriptor_index))};
133 switch (info.type) { 134 switch (info.type) {
134 case TextureType::Color2D: 135 case TextureType::Color2D:
135 case TextureType::ColorArray2D: { 136 case TextureType::ColorArray2D:
137 case TextureType::Color2DRect: {
136 const IR::Value new_inst{&*block.PrependNewInst(it, inst)}; 138 const IR::Value new_inst{&*block.PrependNewInst(it, inst)};
137 const IR::U32 width{DownScale(ir, is_scaled, IR::U32{ir.CompositeExtract(new_inst, 0)})}; 139 const IR::U32 width{DownScale(ir, is_scaled, IR::U32{ir.CompositeExtract(new_inst, 0)})};
138 const IR::U32 height{DownScale(ir, is_scaled, IR::U32{ir.CompositeExtract(new_inst, 1)})}; 140 const IR::U32 height{DownScale(ir, is_scaled, IR::U32{ir.CompositeExtract(new_inst, 1)})};
@@ -163,6 +165,7 @@ void ScaleIntegerComposite(IR::IREmitter& ir, IR::Inst& inst, const IR::U1& is_s
163 const IR::U32 y{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(composite, 1)})}; 165 const IR::U32 y{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(composite, 1)})};
164 switch (info.type) { 166 switch (info.type) {
165 case TextureType::Color2D: 167 case TextureType::Color2D:
168 case TextureType::Color2DRect:
166 inst.SetArg(index, ir.CompositeConstruct(x, y)); 169 inst.SetArg(index, ir.CompositeConstruct(x, y));
167 break; 170 break;
168 case TextureType::ColorArray2D: { 171 case TextureType::ColorArray2D: {
@@ -193,6 +196,7 @@ void ScaleIntegerOffsetComposite(IR::IREmitter& ir, IR::Inst& inst, const IR::U1
193 switch (info.type) { 196 switch (info.type) {
194 case TextureType::ColorArray2D: 197 case TextureType::ColorArray2D:
195 case TextureType::Color2D: 198 case TextureType::Color2D:
199 case TextureType::Color2DRect:
196 inst.SetArg(index, ir.CompositeConstruct(x, y)); 200 inst.SetArg(index, ir.CompositeConstruct(x, y));
197 break; 201 break;
198 case TextureType::Color1D: 202 case TextureType::Color1D:
@@ -216,6 +220,7 @@ void SubScaleCoord(IR::IREmitter& ir, IR::Inst& inst, const IR::U1& is_scaled) {
216 const IR::U32 scaled_y{SubScale(ir, is_scaled, coord_y, IR::Attribute::PositionY)}; 220 const IR::U32 scaled_y{SubScale(ir, is_scaled, coord_y, IR::Attribute::PositionY)};
217 switch (info.type) { 221 switch (info.type) {
218 case TextureType::Color2D: 222 case TextureType::Color2D:
223 case TextureType::Color2DRect:
219 inst.SetArg(1, ir.CompositeConstruct(scaled_x, scaled_y)); 224 inst.SetArg(1, ir.CompositeConstruct(scaled_x, scaled_y));
220 break; 225 break;
221 case TextureType::ColorArray2D: { 226 case TextureType::ColorArray2D: {
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index ca3e306e8..597112ba4 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -362,6 +362,21 @@ private:
362 TextureDescriptors& texture_descriptors; 362 TextureDescriptors& texture_descriptors;
363 ImageDescriptors& image_descriptors; 363 ImageDescriptors& image_descriptors;
364}; 364};
365
366void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
367 IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
368 const auto info{inst.Flags<IR::TextureInstInfo>()};
369 const IR::Value coord(inst.Arg(1));
370 const IR::Value handle(ir.Imm32(0));
371 const IR::U32 lod{ir.Imm32(0)};
372 const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, info);
373 inst.SetArg(
374 1, ir.CompositeConstruct(
375 ir.FPMul(IR::F32(ir.CompositeExtract(coord, 0)),
376 ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 0)))),
377 ir.FPMul(IR::F32(ir.CompositeExtract(coord, 1)),
378 ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1))))));
379}
365} // Anonymous namespace 380} // Anonymous namespace
366 381
367void TexturePass(Environment& env, IR::Program& program) { 382void TexturePass(Environment& env, IR::Program& program) {
@@ -399,6 +414,14 @@ void TexturePass(Environment& env, IR::Program& program) {
399 flags.type.Assign(ReadTextureType(env, cbuf)); 414 flags.type.Assign(ReadTextureType(env, cbuf));
400 inst->SetFlags(flags); 415 inst->SetFlags(flags);
401 break; 416 break;
417 case IR::Opcode::ImageSampleImplicitLod:
418 if (flags.type != TextureType::Color2D) {
419 break;
420 }
421 if (ReadTextureType(env, cbuf) == TextureType::Color2DRect) {
422 PatchImageSampleImplicitLod(*texture_inst.block, *texture_inst.inst);
423 }
424 break;
402 case IR::Opcode::ImageFetch: 425 case IR::Opcode::ImageFetch:
403 if (flags.type != TextureType::Color1D) { 426 if (flags.type != TextureType::Color1D) {
404 break; 427 break;
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h
index fd2ef5336..f5690805c 100644
--- a/src/shader_recompiler/shader_info.h
+++ b/src/shader_recompiler/shader_info.h
@@ -24,8 +24,9 @@ enum class TextureType : u32 {
24 ColorCube, 24 ColorCube,
25 ColorArrayCube, 25 ColorArrayCube,
26 Buffer, 26 Buffer,
27 Color2DRect,
27}; 28};
28constexpr u32 NUM_TEXTURE_TYPES = 8; 29constexpr u32 NUM_TEXTURE_TYPES = 9;
29 30
30enum class ImageFormat : u32 { 31enum class ImageFormat : u32 {
31 Typeless, 32 Typeless,
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_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 8c0fffc67..99cd11d1e 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -93,6 +93,7 @@ GLenum ImageTarget(Shader::TextureType type, int num_samples = 1) {
93 case Shader::TextureType::Color1D: 93 case Shader::TextureType::Color1D:
94 return GL_TEXTURE_1D; 94 return GL_TEXTURE_1D;
95 case Shader::TextureType::Color2D: 95 case Shader::TextureType::Color2D:
96 case Shader::TextureType::Color2DRect:
96 return is_multisampled ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; 97 return is_multisampled ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
97 case Shader::TextureType::ColorCube: 98 case Shader::TextureType::ColorCube:
98 return GL_TEXTURE_CUBE_MAP; 99 return GL_TEXTURE_CUBE_MAP;
@@ -502,6 +503,7 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager&
502 set_view(Shader::TextureType::ColorArray1D, null_image_1d_array.handle); 503 set_view(Shader::TextureType::ColorArray1D, null_image_1d_array.handle);
503 set_view(Shader::TextureType::ColorArray2D, null_image_view_2d_array.handle); 504 set_view(Shader::TextureType::ColorArray2D, null_image_view_2d_array.handle);
504 set_view(Shader::TextureType::ColorArrayCube, null_image_cube_array.handle); 505 set_view(Shader::TextureType::ColorArrayCube, null_image_cube_array.handle);
506 set_view(Shader::TextureType::Color2DRect, null_image_view_2d.handle);
505 507
506 if (resolution.active) { 508 if (resolution.active) {
507 for (size_t i = 0; i < rescale_draw_fbos.size(); ++i) { 509 for (size_t i = 0; i < rescale_draw_fbos.size(); ++i) {
@@ -1110,6 +1112,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1110 flat_range.extent.layers = 1; 1112 flat_range.extent.layers = 1;
1111 [[fallthrough]]; 1113 [[fallthrough]];
1112 case ImageViewType::e2D: 1114 case ImageViewType::e2D:
1115 case ImageViewType::Rect:
1113 if (True(flags & VideoCommon::ImageViewFlagBits::Slice)) { 1116 if (True(flags & VideoCommon::ImageViewFlagBits::Slice)) {
1114 // 2D and 2D array views on a 3D textures are used exclusively for render targets 1117 // 2D and 2D array views on a 3D textures are used exclusively for render targets
1115 ASSERT(info.range.extent.levels == 1); 1118 ASSERT(info.range.extent.levels == 1);
@@ -1135,9 +1138,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1135 SetupView(Shader::TextureType::ColorCube); 1138 SetupView(Shader::TextureType::ColorCube);
1136 SetupView(Shader::TextureType::ColorArrayCube); 1139 SetupView(Shader::TextureType::ColorArrayCube);
1137 break; 1140 break;
1138 case ImageViewType::Rect:
1139 UNIMPLEMENTED();
1140 break;
1141 case ImageViewType::Buffer: 1141 case ImageViewType::Buffer:
1142 ASSERT(false); 1142 ASSERT(false);
1143 break; 1143 break;
@@ -1150,6 +1150,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1150 default_handle = Handle(Shader::TextureType::ColorArray1D); 1150 default_handle = Handle(Shader::TextureType::ColorArray1D);
1151 break; 1151 break;
1152 case ImageViewType::e2D: 1152 case ImageViewType::e2D:
1153 case ImageViewType::Rect:
1153 default_handle = Handle(Shader::TextureType::Color2D); 1154 default_handle = Handle(Shader::TextureType::Color2D);
1154 break; 1155 break;
1155 case ImageViewType::e2DArray: 1156 case ImageViewType::e2DArray:
@@ -1210,6 +1211,7 @@ GLuint ImageView::MakeView(Shader::TextureType view_type, GLenum view_format) {
1210 case Shader::TextureType::Color1D: 1211 case Shader::TextureType::Color1D:
1211 case Shader::TextureType::Color2D: 1212 case Shader::TextureType::Color2D:
1212 case Shader::TextureType::ColorCube: 1213 case Shader::TextureType::ColorCube:
1214 case Shader::TextureType::Color2DRect:
1213 view_range = flat_range; 1215 view_range = flat_range;
1214 break; 1216 break;
1215 case Shader::TextureType::ColorArray1D: 1217 case Shader::TextureType::ColorArray1D:
@@ -1250,7 +1252,6 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const TSCEntry& config) {
1250 const GLint seamless = config.cubemap_interface_filtering ? GL_TRUE : GL_FALSE; 1252 const GLint seamless = config.cubemap_interface_filtering ? GL_TRUE : GL_FALSE;
1251 1253
1252 UNIMPLEMENTED_IF(config.cubemap_anisotropy != 1); 1254 UNIMPLEMENTED_IF(config.cubemap_anisotropy != 1);
1253 UNIMPLEMENTED_IF(config.float_coord_normalization != 0);
1254 1255
1255 sampler.Create(); 1256 sampler.Create();
1256 const GLuint handle = sampler.handle; 1257 const GLuint handle = sampler.handle;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 43cc94fab..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) {
@@ -434,7 +434,9 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
434 state.statistics.get(), false)}; 434 state.statistics.get(), false)};
435 435
436 std::scoped_lock lock{state.mutex}; 436 std::scoped_lock lock{state.mutex};
437 graphics_cache.emplace(key, std::move(pipeline)); 437 if (pipeline) {
438 graphics_cache.emplace(key, std::move(pipeline));
439 }
438 ++state.built; 440 ++state.built;
439 if (state.has_loaded) { 441 if (state.has_loaded) {
440 callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); 442 callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 16e46d3e5..7e40c2df1 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -69,10 +69,17 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in
69 const float width = conv(src.scale_x * 2.0f); 69 const float width = conv(src.scale_x * 2.0f);
70 float y = conv(src.translate_y - src.scale_y); 70 float y = conv(src.translate_y - src.scale_y);
71 float height = conv(src.scale_y * 2.0f); 71 float height = conv(src.scale_y * 2.0f);
72 if (regs.screen_y_control.y_negate) { 72 bool y_negate = regs.screen_y_control.y_negate;
73
74 if (!device.IsNvViewportSwizzleSupported()) {
75 y_negate = y_negate != (src.swizzle.y == Maxwell::ViewportSwizzle::NegativeY);
76 }
77
78 if (y_negate) {
73 y += height; 79 y += height;
74 height = -height; 80 height = -height;
75 } 81 }
82
76 const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f; 83 const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f;
77 VkViewport viewport{ 84 VkViewport viewport{
78 .x = x, 85 .x = x,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 16463a892..caca79d79 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -230,6 +230,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
230 case Shader::TextureType::Color1D: 230 case Shader::TextureType::Color1D:
231 return VK_IMAGE_VIEW_TYPE_1D; 231 return VK_IMAGE_VIEW_TYPE_1D;
232 case Shader::TextureType::Color2D: 232 case Shader::TextureType::Color2D:
233 case Shader::TextureType::Color2DRect:
233 return VK_IMAGE_VIEW_TYPE_2D; 234 return VK_IMAGE_VIEW_TYPE_2D;
234 case Shader::TextureType::ColorCube: 235 case Shader::TextureType::ColorCube:
235 return VK_IMAGE_VIEW_TYPE_CUBE; 236 return VK_IMAGE_VIEW_TYPE_CUBE;
@@ -254,6 +255,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
254 case VideoCommon::ImageViewType::e1D: 255 case VideoCommon::ImageViewType::e1D:
255 return VK_IMAGE_VIEW_TYPE_1D; 256 return VK_IMAGE_VIEW_TYPE_1D;
256 case VideoCommon::ImageViewType::e2D: 257 case VideoCommon::ImageViewType::e2D:
258 case VideoCommon::ImageViewType::Rect:
257 return VK_IMAGE_VIEW_TYPE_2D; 259 return VK_IMAGE_VIEW_TYPE_2D;
258 case VideoCommon::ImageViewType::Cube: 260 case VideoCommon::ImageViewType::Cube:
259 return VK_IMAGE_VIEW_TYPE_CUBE; 261 return VK_IMAGE_VIEW_TYPE_CUBE;
@@ -265,9 +267,6 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
265 return VK_IMAGE_VIEW_TYPE_2D_ARRAY; 267 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
266 case VideoCommon::ImageViewType::CubeArray: 268 case VideoCommon::ImageViewType::CubeArray:
267 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; 269 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
268 case VideoCommon::ImageViewType::Rect:
269 UNIMPLEMENTED_MSG("Rect image view");
270 return VK_IMAGE_VIEW_TYPE_2D;
271 case VideoCommon::ImageViewType::Buffer: 270 case VideoCommon::ImageViewType::Buffer:
272 ASSERT_MSG(false, "Texture buffers can't be image views"); 271 ASSERT_MSG(false, "Texture buffers can't be image views");
273 return VK_IMAGE_VIEW_TYPE_1D; 272 return VK_IMAGE_VIEW_TYPE_1D;
@@ -1579,6 +1578,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1579 break; 1578 break;
1580 case VideoCommon::ImageViewType::e2D: 1579 case VideoCommon::ImageViewType::e2D:
1581 case VideoCommon::ImageViewType::e2DArray: 1580 case VideoCommon::ImageViewType::e2DArray:
1581 case VideoCommon::ImageViewType::Rect:
1582 create(TextureType::Color2D, 1); 1582 create(TextureType::Color2D, 1);
1583 create(TextureType::ColorArray2D, std::nullopt); 1583 create(TextureType::ColorArray2D, std::nullopt);
1584 render_target = Handle(Shader::TextureType::ColorArray2D); 1584 render_target = Handle(Shader::TextureType::ColorArray2D);
@@ -1592,9 +1592,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1592 create(TextureType::ColorCube, 6); 1592 create(TextureType::ColorCube, 6);
1593 create(TextureType::ColorArrayCube, std::nullopt); 1593 create(TextureType::ColorArrayCube, std::nullopt);
1594 break; 1594 break;
1595 case VideoCommon::ImageViewType::Rect:
1596 UNIMPLEMENTED();
1597 break;
1598 case VideoCommon::ImageViewType::Buffer: 1595 case VideoCommon::ImageViewType::Buffer:
1599 ASSERT(false); 1596 ASSERT(false);
1600 break; 1597 break;
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index c4e923bbf..5f7625947 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -39,7 +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 return Shader::TextureType::Color2D; 42 return entry.normalized_coords ? Shader::TextureType::Color2D
43 : Shader::TextureType::Color2DRect;
43 case Tegra::Texture::TextureType::Texture3D: 44 case Tegra::Texture::TextureType::Texture3D:
44 return Shader::TextureType::Color3D; 45 return Shader::TextureType::Color3D;
45 case Tegra::Texture::TextureType::TextureCubemap: 46 case Tegra::Texture::TextureType::TextureCubemap:
@@ -53,7 +54,8 @@ static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) {
53 case Tegra::Texture::TextureType::TextureCubeArray: 54 case Tegra::Texture::TextureType::TextureCubeArray:
54 return Shader::TextureType::ColorArrayCube; 55 return Shader::TextureType::ColorArrayCube;
55 default: 56 default:
56 throw Shader::NotImplementedException("Unknown texture type"); 57 UNIMPLEMENTED();
58 return Shader::TextureType::Color2D;
57 } 59 }
58} 60}
59 61
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/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