summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/hid/hid.cpp3
-rw-r--r--src/core/internal_network/network_interface.cpp10
-rw-r--r--src/core/internal_network/network_interface.h1
-rw-r--r--src/yuzu/main.cpp8
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui10
-rw-r--r--src/yuzu/multiplayer/client_room.cpp3
-rw-r--r--src/yuzu/multiplayer/direct_connect.cpp2
-rw-r--r--src/yuzu/multiplayer/direct_connect.h1
-rw-r--r--src/yuzu/multiplayer/host_room.cpp1
-rw-r--r--src/yuzu/multiplayer/host_room.h3
-rw-r--r--src/yuzu/multiplayer/lobby.cpp67
-rw-r--r--src/yuzu/multiplayer/lobby.h8
-rw-r--r--src/yuzu/multiplayer/lobby_p.h16
-rw-r--r--src/yuzu/multiplayer/message.cpp6
-rw-r--r--src/yuzu/multiplayer/state.cpp79
-rw-r--r--src/yuzu/multiplayer/state.h14
-rw-r--r--src/yuzu/uisettings.h2
18 files changed, 176 insertions, 59 deletions
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 3d3457160..7e923462b 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -35,7 +35,8 @@ namespace Service::HID {
35 35
36// Updating period for each HID device. 36// Updating period for each HID device.
37// Period time is obtained by measuring the number of samples in a second on HW using a homebrew 37// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
38constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) 38// Correct pad_update_ns is 4ms this is overclocked to lower input lag
39constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
39constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) 40constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
40constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) 41constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
41 42
diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp
index 0f0a66160..858ae1cfb 100644
--- a/src/core/internal_network/network_interface.cpp
+++ b/src/core/internal_network/network_interface.cpp
@@ -206,4 +206,14 @@ std::optional<NetworkInterface> GetSelectedNetworkInterface() {
206 return *res; 206 return *res;
207} 207}
208 208
209void SelectFirstNetworkInterface() {
210 const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
211
212 if (network_interfaces.size() == 0) {
213 return;
214 }
215
216 Settings::values.network_interface.SetValue(network_interfaces[0].name);
217}
218
209} // namespace Network 219} // namespace Network
diff --git a/src/core/internal_network/network_interface.h b/src/core/internal_network/network_interface.h
index 9b98b6b42..175e61b1f 100644
--- a/src/core/internal_network/network_interface.h
+++ b/src/core/internal_network/network_interface.h
@@ -24,5 +24,6 @@ struct NetworkInterface {
24 24
25std::vector<NetworkInterface> GetAvailableNetworkInterfaces(); 25std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
26std::optional<NetworkInterface> GetSelectedNetworkInterface(); 26std::optional<NetworkInterface> GetSelectedNetworkInterface();
27void SelectFirstNetworkInterface();
27 28
28} // namespace Network 29} // namespace Network
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9dfa8d639..deee1c370 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1296,6 +1296,7 @@ void GMainWindow::ConnectMenuEvents() {
1296 &MultiplayerState::OnDirectConnectToRoom); 1296 &MultiplayerState::OnDirectConnectToRoom);
1297 connect(ui->action_Show_Room, &QAction::triggered, multiplayer_state, 1297 connect(ui->action_Show_Room, &QAction::triggered, multiplayer_state,
1298 &MultiplayerState::OnOpenNetworkRoom); 1298 &MultiplayerState::OnOpenNetworkRoom);
1299 connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig);
1299 1300
1300 // Tools 1301 // Tools
1301 connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, 1302 connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
@@ -1336,6 +1337,8 @@ void GMainWindow::UpdateMenuState() {
1336 } else { 1337 } else {
1337 ui->action_Pause->setText(tr("&Pause")); 1338 ui->action_Pause->setText(tr("&Pause"));
1338 } 1339 }
1340
1341 multiplayer_state->UpdateNotificationStatus();
1339} 1342}
1340 1343
1341void GMainWindow::OnDisplayTitleBars(bool show) { 1344void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -2766,6 +2769,11 @@ void GMainWindow::OnExit() {
2766 OnStopGame(); 2769 OnStopGame();
2767} 2770}
2768 2771
2772void GMainWindow::OnSaveConfig() {
2773 system->ApplySettings();
2774 config->Save();
2775}
2776
2769void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { 2777void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
2770 OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"), 2778 OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"),
2771 Qt::AlignLeft | Qt::AlignVCenter); 2779 Qt::AlignLeft | Qt::AlignVCenter);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 1ae2b93d9..1a756b171 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -169,6 +169,7 @@ public slots:
169 void OnLoadComplete(); 169 void OnLoadComplete();
170 void OnExecuteProgram(std::size_t program_index); 170 void OnExecuteProgram(std::size_t program_index);
171 void OnExit(); 171 void OnExit();
172 void OnSaveConfig();
172 void ControllerSelectorReconfigureControllers( 173 void ControllerSelectorReconfigureControllers(
173 const Core::Frontend::ControllerParameters& parameters); 174 const Core::Frontend::ControllerParameters& parameters);
174 void SoftwareKeyboardInitialize( 175 void SoftwareKeyboardInitialize(
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 60a8deab1..de1545216 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -265,7 +265,7 @@
265 <bool>true</bool> 265 <bool>true</bool>
266 </property> 266 </property>
267 <property name="text"> 267 <property name="text">
268 <string>Browse Public Game Lobby</string> 268 <string>&amp;Browse Public Game Lobby</string>
269 </property> 269 </property>
270 </action> 270 </action>
271 <action name="action_Start_Room"> 271 <action name="action_Start_Room">
@@ -273,7 +273,7 @@
273 <bool>true</bool> 273 <bool>true</bool>
274 </property> 274 </property>
275 <property name="text"> 275 <property name="text">
276 <string>Create Room</string> 276 <string>&amp;Create Room</string>
277 </property> 277 </property>
278 </action> 278 </action>
279 <action name="action_Leave_Room"> 279 <action name="action_Leave_Room">
@@ -281,12 +281,12 @@
281 <bool>false</bool> 281 <bool>false</bool>
282 </property> 282 </property>
283 <property name="text"> 283 <property name="text">
284 <string>Leave Room</string> 284 <string>&amp;Leave Room</string>
285 </property> 285 </property>
286 </action> 286 </action>
287 <action name="action_Connect_To_Room"> 287 <action name="action_Connect_To_Room">
288 <property name="text"> 288 <property name="text">
289 <string>Direct Connect to Room</string> 289 <string>&amp;Direct Connect to Room</string>
290 </property> 290 </property>
291 </action> 291 </action>
292 <action name="action_Show_Room"> 292 <action name="action_Show_Room">
@@ -294,7 +294,7 @@
294 <bool>false</bool> 294 <bool>false</bool>
295 </property> 295 </property>
296 <property name="text"> 296 <property name="text">
297 <string>Show Current Room</string> 297 <string>&amp;Show Current Room</string>
298 </property> 298 </property>
299 </action> 299 </action>
300 <action name="action_Fullscreen"> 300 <action name="action_Fullscreen">
diff --git a/src/yuzu/multiplayer/client_room.cpp b/src/yuzu/multiplayer/client_room.cpp
index b34a8d004..caf34a414 100644
--- a/src/yuzu/multiplayer/client_room.cpp
+++ b/src/yuzu/multiplayer/client_room.cpp
@@ -97,8 +97,9 @@ void ClientRoomWindow::UpdateView() {
97 auto memberlist = member->GetMemberInformation(); 97 auto memberlist = member->GetMemberInformation();
98 ui->chat->SetPlayerList(memberlist); 98 ui->chat->SetPlayerList(memberlist);
99 const auto information = member->GetRoomInformation(); 99 const auto information = member->GetRoomInformation();
100 setWindowTitle(QString(tr("%1 (%2/%3 members) - connected")) 100 setWindowTitle(QString(tr("%1 - %2 (%3/%4 members) - connected"))
101 .arg(QString::fromStdString(information.name)) 101 .arg(QString::fromStdString(information.name))
102 .arg(QString::fromStdString(information.preferred_game.name))
102 .arg(memberlist.size()) 103 .arg(memberlist.size())
103 .arg(information.member_slots)); 104 .arg(information.member_slots));
104 ui->description->setText(QString::fromStdString(information.description)); 105 ui->description->setText(QString::fromStdString(information.description));
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp
index 017063074..10bf0a4fb 100644
--- a/src/yuzu/multiplayer/direct_connect.cpp
+++ b/src/yuzu/multiplayer/direct_connect.cpp
@@ -106,6 +106,8 @@ void DirectConnectWindow::Connect() {
106 UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault(); 106 UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault();
107 } 107 }
108 108
109 emit SaveConfig();
110
109 // attempt to connect in a different thread 111 // attempt to connect in a different thread
110 QFuture<void> f = QtConcurrent::run([&] { 112 QFuture<void> f = QtConcurrent::run([&] {
111 if (auto room_member = room_network.GetRoomMember().lock()) { 113 if (auto room_member = room_network.GetRoomMember().lock()) {
diff --git a/src/yuzu/multiplayer/direct_connect.h b/src/yuzu/multiplayer/direct_connect.h
index e39dd1e0d..b8f66cfb2 100644
--- a/src/yuzu/multiplayer/direct_connect.h
+++ b/src/yuzu/multiplayer/direct_connect.h
@@ -31,6 +31,7 @@ signals:
31 * connections that it might have. 31 * connections that it might have.
32 */ 32 */
33 void Closed(); 33 void Closed();
34 void SaveConfig();
34 35
35private slots: 36private slots:
36 void OnConnection(); 37 void OnConnection();
diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp
index 0c6adfd04..a8faa5b24 100644
--- a/src/yuzu/multiplayer/host_room.cpp
+++ b/src/yuzu/multiplayer/host_room.cpp
@@ -232,6 +232,7 @@ void HostRoomWindow::Host() {
232 } 232 }
233 UISettings::values.multiplayer_room_description = ui->room_description->toPlainText(); 233 UISettings::values.multiplayer_room_description = ui->room_description->toPlainText();
234 ui->host->setEnabled(true); 234 ui->host->setEnabled(true);
235 emit SaveConfig();
235 close(); 236 close();
236 } 237 }
237} 238}
diff --git a/src/yuzu/multiplayer/host_room.h b/src/yuzu/multiplayer/host_room.h
index 034cb2eef..ae816e2e0 100644
--- a/src/yuzu/multiplayer/host_room.h
+++ b/src/yuzu/multiplayer/host_room.h
@@ -46,6 +46,9 @@ public:
46 void UpdateGameList(QStandardItemModel* list); 46 void UpdateGameList(QStandardItemModel* list);
47 void RetranslateUi(); 47 void RetranslateUi();
48 48
49signals:
50 void SaveConfig();
51
49private: 52private:
50 void Host(); 53 void Host();
51 std::unique_ptr<Network::VerifyUser::Backend> CreateVerifyBackend(bool use_validation) const; 54 std::unique_ptr<Network::VerifyUser::Backend> CreateVerifyBackend(bool use_validation) const;
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index 107d40547..08c275696 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -7,6 +7,7 @@
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" 9#include "core/core.h"
10#include "core/hle/service/acc/profile_manager.h"
10#include "core/internal_network/network_interface.h" 11#include "core/internal_network/network_interface.h"
11#include "network/network.h" 12#include "network/network.h"
12#include "ui_lobby.h" 13#include "ui_lobby.h"
@@ -26,9 +27,9 @@
26Lobby::Lobby(QWidget* parent, QStandardItemModel* list, 27Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
27 std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_) 28 std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_)
28 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), 29 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
29 ui(std::make_unique<Ui::Lobby>()), 30 ui(std::make_unique<Ui::Lobby>()), announce_multiplayer_session(session),
30 announce_multiplayer_session(session), system{system_}, room_network{ 31 profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_},
31 system.GetRoomNetwork()} { 32 room_network{system.GetRoomNetwork()} {
32 ui->setupUi(this); 33 ui->setupUi(this);
33 34
34 // setup the watcher for background connections 35 // setup the watcher for background connections
@@ -60,9 +61,17 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
60 61
61 ui->nickname->setValidator(validation.GetNickname()); 62 ui->nickname->setValidator(validation.GetNickname());
62 ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue()); 63 ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
63 if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { 64
64 // Use yuzu Web Service user name as nickname by default 65 // Try find the best nickname by default
65 ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); 66 if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("yuzu")) {
67 if (!Settings::values.yuzu_username.GetValue().empty()) {
68 ui->nickname->setText(
69 QString::fromStdString(Settings::values.yuzu_username.GetValue()));
70 } else if (!GetProfileUsername().empty()) {
71 ui->nickname->setText(QString::fromStdString(GetProfileUsername()));
72 } else {
73 ui->nickname->setText(QStringLiteral("yuzu"));
74 }
66 } 75 }
67 76
68 // UI Buttons 77 // UI Buttons
@@ -76,12 +85,6 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
76 // Actions 85 // Actions
77 connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this, 86 connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this,
78 &Lobby::OnRefreshLobby); 87 &Lobby::OnRefreshLobby);
79
80 // manually start a refresh when the window is opening
81 // TODO(jroweboy): if this refresh is slow for people with bad internet, then don't do it as
82 // part of the constructor, but offload the refresh until after the window shown. perhaps emit a
83 // refreshroomlist signal from places that open the lobby
84 RefreshLobby();
85} 88}
86 89
87Lobby::~Lobby() = default; 90Lobby::~Lobby() = default;
@@ -96,6 +99,7 @@ void Lobby::UpdateGameList(QStandardItemModel* list) {
96 } 99 }
97 if (proxy) 100 if (proxy)
98 proxy->UpdateGameList(game_list); 101 proxy->UpdateGameList(game_list);
102 ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder);
99} 103}
100 104
101void Lobby::RetranslateUi() { 105void Lobby::RetranslateUi() {
@@ -117,6 +121,11 @@ void Lobby::OnExpandRoom(const QModelIndex& index) {
117 121
118void Lobby::OnJoinRoom(const QModelIndex& source) { 122void Lobby::OnJoinRoom(const QModelIndex& source) {
119 if (!Network::GetSelectedNetworkInterface()) { 123 if (!Network::GetSelectedNetworkInterface()) {
124 LOG_INFO(WebService, "Automatically selected network interface for room network.");
125 Network::SelectFirstNetworkInterface();
126 }
127
128 if (!Network::GetSelectedNetworkInterface()) {
120 NetworkMessage::ErrorManager::ShowError( 129 NetworkMessage::ErrorManager::ShowError(
121 NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED); 130 NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED);
122 return; 131 return;
@@ -197,16 +206,16 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
197 proxy->data(connection_index, LobbyItemHost::HostIPRole).toString(); 206 proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();
198 UISettings::values.multiplayer_port = 207 UISettings::values.multiplayer_port =
199 proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt(); 208 proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
209 emit SaveConfig();
200} 210}
201 211
202void Lobby::ResetModel() { 212void Lobby::ResetModel() {
203 model->clear(); 213 model->clear();
204 model->insertColumns(0, Column::TOTAL); 214 model->insertColumns(0, Column::TOTAL);
205 model->setHeaderData(Column::EXPAND, Qt::Horizontal, QString(), Qt::DisplayRole); 215 model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole);
206 model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Room Name"), Qt::DisplayRole); 216 model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Room Name"), Qt::DisplayRole);
207 model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Preferred Game"), Qt::DisplayRole); 217 model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Preferred Game"), Qt::DisplayRole);
208 model->setHeaderData(Column::HOST, Qt::Horizontal, tr("Host"), Qt::DisplayRole); 218 model->setHeaderData(Column::HOST, Qt::Horizontal, tr("Host"), Qt::DisplayRole);
209 model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole);
210} 219}
211 220
212void Lobby::RefreshLobby() { 221void Lobby::RefreshLobby() {
@@ -229,6 +238,7 @@ void Lobby::OnRefreshLobby() {
229 for (int r = 0; r < game_list->rowCount(); ++r) { 238 for (int r = 0; r < game_list->rowCount(); ++r) {
230 auto index = game_list->index(r, 0); 239 auto index = game_list->index(r, 0);
231 auto game_id = game_list->data(index, GameListItemPath::ProgramIdRole).toULongLong(); 240 auto game_id = game_list->data(index, GameListItemPath::ProgramIdRole).toULongLong();
241
232 if (game_id != 0 && room.information.preferred_game.id == game_id) { 242 if (game_id != 0 && room.information.preferred_game.id == game_id) {
233 smdh_icon = game_list->data(index, Qt::DecorationRole).value<QPixmap>(); 243 smdh_icon = game_list->data(index, Qt::DecorationRole).value<QPixmap>();
234 } 244 }
@@ -243,17 +253,16 @@ void Lobby::OnRefreshLobby() {
243 members.append(var); 253 members.append(var);
244 } 254 }
245 255
246 auto first_item = new LobbyItem(); 256 auto first_item = new LobbyItemGame(
257 room.information.preferred_game.id,
258 QString::fromStdString(room.information.preferred_game.name), smdh_icon);
247 auto row = QList<QStandardItem*>({ 259 auto row = QList<QStandardItem*>({
248 first_item, 260 first_item,
249 new LobbyItemName(room.has_password, QString::fromStdString(room.information.name)), 261 new LobbyItemName(room.has_password, QString::fromStdString(room.information.name)),
250 new LobbyItemGame(room.information.preferred_game.id, 262 new LobbyItemMemberList(members, room.information.member_slots),
251 QString::fromStdString(room.information.preferred_game.name),
252 smdh_icon),
253 new LobbyItemHost(QString::fromStdString(room.information.host_username), 263 new LobbyItemHost(QString::fromStdString(room.information.host_username),
254 QString::fromStdString(room.ip), room.information.port, 264 QString::fromStdString(room.ip), room.information.port,
255 QString::fromStdString(room.verify_uid)), 265 QString::fromStdString(room.verify_uid)),
256 new LobbyItemMemberList(members, room.information.member_slots),
257 }); 266 });
258 model->appendRow(row); 267 model->appendRow(row);
259 // To make the rows expandable, add the member data as a child of the first column of the 268 // To make the rows expandable, add the member data as a child of the first column of the
@@ -283,6 +292,26 @@ void Lobby::OnRefreshLobby() {
283 ui->room_list->setFirstColumnSpanned(j, proxy->index(i, 0), true); 292 ui->room_list->setFirstColumnSpanned(j, proxy->index(i, 0), true);
284 } 293 }
285 } 294 }
295
296 ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder);
297}
298
299std::string Lobby::GetProfileUsername() {
300 const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
301 Service::Account::ProfileBase profile{};
302
303 if (!current_user.has_value()) {
304 return "";
305 }
306
307 if (!profile_manager->GetProfileBase(*current_user, profile)) {
308 return "";
309 }
310
311 const auto text = Common::StringFromFixedZeroTerminatedBuffer(
312 reinterpret_cast<const char*>(profile.username.data()), profile.username.size());
313
314 return text;
286} 315}
287 316
288LobbyFilterProxyModel::LobbyFilterProxyModel(QWidget* parent, QStandardItemModel* list) 317LobbyFilterProxyModel::LobbyFilterProxyModel(QWidget* parent, QStandardItemModel* list)
diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h
index 2696aec21..300dad13e 100644
--- a/src/yuzu/multiplayer/lobby.h
+++ b/src/yuzu/multiplayer/lobby.h
@@ -24,6 +24,10 @@ namespace Core {
24class System; 24class System;
25} 25}
26 26
27namespace Service::Account {
28class ProfileManager;
29}
30
27/** 31/**
28 * Listing of all public games pulled from services. The lobby should be simple enough for users to 32 * Listing of all public games pulled from services. The lobby should be simple enough for users to
29 * find the game they want to play, and join it. 33 * find the game they want to play, and join it.
@@ -75,8 +79,11 @@ private slots:
75 79
76signals: 80signals:
77 void StateChanged(const Network::RoomMember::State&); 81 void StateChanged(const Network::RoomMember::State&);
82 void SaveConfig();
78 83
79private: 84private:
85 std::string GetProfileUsername();
86
80 /** 87 /**
81 * Removes all entries in the Lobby before refreshing. 88 * Removes all entries in the Lobby before refreshing.
82 */ 89 */
@@ -96,6 +103,7 @@ private:
96 103
97 QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher; 104 QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher;
98 std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; 105 std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
106 std::unique_ptr<Service::Account::ProfileManager> profile_manager;
99 QFutureWatcher<void>* watcher; 107 QFutureWatcher<void>* watcher;
100 Validation validation; 108 Validation validation;
101 Core::System& system; 109 Core::System& system;
diff --git a/src/yuzu/multiplayer/lobby_p.h b/src/yuzu/multiplayer/lobby_p.h
index 8071cede4..8b1707506 100644
--- a/src/yuzu/multiplayer/lobby_p.h
+++ b/src/yuzu/multiplayer/lobby_p.h
@@ -11,11 +11,10 @@
11 11
12namespace Column { 12namespace Column {
13enum List { 13enum List {
14 EXPAND,
15 ROOM_NAME,
16 GAME_NAME, 14 GAME_NAME,
17 HOST, 15 ROOM_NAME,
18 MEMBER, 16 MEMBER,
17 HOST,
19 TOTAL, 18 TOTAL,
20}; 19};
21} 20}
@@ -98,7 +97,12 @@ public:
98 if (role == Qt::DecorationRole) { 97 if (role == Qt::DecorationRole) {
99 auto val = data(GameIconRole); 98 auto val = data(GameIconRole);
100 if (val.isValid()) { 99 if (val.isValid()) {
101 val = val.value<QPixmap>().scaled(16, 16, Qt::KeepAspectRatio); 100 val = val.value<QPixmap>().scaled(32, 32, Qt::KeepAspectRatio,
101 Qt::TransformationMode::SmoothTransformation);
102 } else {
103 auto blank_image = QPixmap(32, 32);
104 blank_image.fill(Qt::black);
105 val = blank_image;
102 } 106 }
103 return val; 107 return val;
104 } else if (role != Qt::DisplayRole) { 108 } else if (role != Qt::DisplayRole) {
@@ -191,8 +195,8 @@ public:
191 return LobbyItem::data(role); 195 return LobbyItem::data(role);
192 } 196 }
193 auto members = data(MemberListRole).toList(); 197 auto members = data(MemberListRole).toList();
194 return QStringLiteral("%1 / %2").arg(QString::number(members.size()), 198 return QStringLiteral("%1 / %2 ")
195 data(MaxPlayerRole).toString()); 199 .arg(QString::number(members.size()), data(MaxPlayerRole).toString());
196 } 200 }
197 201
198 bool operator<(const QStandardItem& other) const override { 202 bool operator<(const QStandardItem& other) const override {
diff --git a/src/yuzu/multiplayer/message.cpp b/src/yuzu/multiplayer/message.cpp
index 758b5b731..6d8f18274 100644
--- a/src/yuzu/multiplayer/message.cpp
+++ b/src/yuzu/multiplayer/message.cpp
@@ -49,9 +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( 52const ConnectionError ErrorManager::NO_INTERFACE_SELECTED(QT_TR_NOOP(
53 QT_TR_NOOP("No network interface is selected.\nPlease go to Configure -> System -> Network and " 53 "No valid network interface is selected.\nPlease go to Configure -> System -> Network and "
54 "make a selection.")); 54 "make a selection."));
55 55
56static bool WarnMessage(const std::string& title, const std::string& text) { 56static bool WarnMessage(const std::string& title, const std::string& text) {
57 return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()), 57 return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()),
diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp
index 3ad846028..ae2738ad4 100644
--- a/src/yuzu/multiplayer/state.cpp
+++ b/src/yuzu/multiplayer/state.cpp
@@ -44,9 +44,6 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis
44 44
45 status_text = new ClickableLabel(this); 45 status_text = new ClickableLabel(this);
46 status_icon = new ClickableLabel(this); 46 status_icon = new ClickableLabel(this);
47 status_text->setToolTip(tr("Current connection status"));
48 status_text->setText(tr("Not Connected. Click here to find a room!"));
49 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16));
50 47
51 connect(status_text, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom); 48 connect(status_text, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom);
52 connect(status_icon, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom); 49 connect(status_icon, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom);
@@ -57,6 +54,8 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis
57 HideNotification(); 54 HideNotification();
58 } 55 }
59 }); 56 });
57
58 retranslateUi();
60} 59}
61 60
62MultiplayerState::~MultiplayerState() = default; 61MultiplayerState::~MultiplayerState() = default;
@@ -90,14 +89,7 @@ void MultiplayerState::Close() {
90void MultiplayerState::retranslateUi() { 89void MultiplayerState::retranslateUi() {
91 status_text->setToolTip(tr("Current connection status")); 90 status_text->setToolTip(tr("Current connection status"));
92 91
93 if (current_state == Network::RoomMember::State::Uninitialized) { 92 UpdateNotificationStatus();
94 status_text->setText(tr("Not Connected. Click here to find a room!"));
95 } else if (current_state == Network::RoomMember::State::Joined ||
96 current_state == Network::RoomMember::State::Moderator) {
97 status_text->setText(tr("Connected"));
98 } else {
99 status_text->setText(tr("Not Connected"));
100 }
101 93
102 if (lobby) { 94 if (lobby) {
103 lobby->RetranslateUi(); 95 lobby->RetranslateUi();
@@ -113,21 +105,55 @@ void MultiplayerState::retranslateUi() {
113 } 105 }
114} 106}
115 107
108void MultiplayerState::SetNotificationStatus(NotificationStatus status) {
109 notification_status = status;
110 UpdateNotificationStatus();
111}
112
113void MultiplayerState::UpdateNotificationStatus() {
114 switch (notification_status) {
115 case NotificationStatus::Unitialized:
116 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16));
117 status_text->setText(tr("Not Connected. Click here to find a room!"));
118 leave_room->setEnabled(false);
119 show_room->setEnabled(false);
120 break;
121 case NotificationStatus::Disconnected:
122 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16));
123 status_text->setText(tr("Not Connected"));
124 leave_room->setEnabled(false);
125 show_room->setEnabled(false);
126 break;
127 case NotificationStatus::Connected:
128 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16));
129 status_text->setText(tr("Connected"));
130 leave_room->setEnabled(true);
131 show_room->setEnabled(true);
132 break;
133 case NotificationStatus::Notification:
134 status_icon->setPixmap(
135 QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16));
136 status_text->setText(tr("New Messages Received"));
137 leave_room->setEnabled(true);
138 show_room->setEnabled(true);
139 break;
140 }
141
142 // Clean up status bar if game is running
143 if (system.IsPoweredOn()) {
144 status_text->clear();
145 }
146}
147
116void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& state) { 148void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& state) {
117 LOG_DEBUG(Frontend, "Network State: {}", Network::GetStateStr(state)); 149 LOG_DEBUG(Frontend, "Network State: {}", Network::GetStateStr(state));
118 if (state == Network::RoomMember::State::Joined || 150 if (state == Network::RoomMember::State::Joined ||
119 state == Network::RoomMember::State::Moderator) { 151 state == Network::RoomMember::State::Moderator) {
120 152
121 OnOpenNetworkRoom(); 153 OnOpenNetworkRoom();
122 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); 154 SetNotificationStatus(NotificationStatus::Connected);
123 status_text->setText(tr("Connected"));
124 leave_room->setEnabled(true);
125 show_room->setEnabled(true);
126 } else { 155 } else {
127 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); 156 SetNotificationStatus(NotificationStatus::Disconnected);
128 status_text->setText(tr("Not Connected"));
129 leave_room->setEnabled(false);
130 show_room->setEnabled(false);
131 } 157 }
132 158
133 current_state = state; 159 current_state = state;
@@ -185,6 +211,10 @@ void MultiplayerState::OnAnnounceFailed(const WebService::WebResult& result) {
185 QMessageBox::Ok); 211 QMessageBox::Ok);
186} 212}
187 213
214void MultiplayerState::OnSaveConfig() {
215 emit SaveConfig();
216}
217
188void MultiplayerState::UpdateThemedIcons() { 218void MultiplayerState::UpdateThemedIcons() {
189 if (show_notification) { 219 if (show_notification) {
190 status_icon->setPixmap( 220 status_icon->setPixmap(
@@ -209,13 +239,16 @@ static void BringWidgetToFront(QWidget* widget) {
209void MultiplayerState::OnViewLobby() { 239void MultiplayerState::OnViewLobby() {
210 if (lobby == nullptr) { 240 if (lobby == nullptr) {
211 lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system); 241 lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system);
242 connect(lobby, &Lobby::SaveConfig, this, &MultiplayerState::OnSaveConfig);
212 } 243 }
244 lobby->RefreshLobby();
213 BringWidgetToFront(lobby); 245 BringWidgetToFront(lobby);
214} 246}
215 247
216void MultiplayerState::OnCreateRoom() { 248void MultiplayerState::OnCreateRoom() {
217 if (host_room == nullptr) { 249 if (host_room == nullptr) {
218 host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system); 250 host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system);
251 connect(host_room, &HostRoomWindow::SaveConfig, this, &MultiplayerState::OnSaveConfig);
219 } 252 }
220 BringWidgetToFront(host_room); 253 BringWidgetToFront(host_room);
221} 254}
@@ -250,14 +283,12 @@ void MultiplayerState::ShowNotification() {
250 show_notification = true; 283 show_notification = true;
251 QApplication::alert(nullptr); 284 QApplication::alert(nullptr);
252 QApplication::beep(); 285 QApplication::beep();
253 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); 286 SetNotificationStatus(NotificationStatus::Notification);
254 status_text->setText(tr("New Messages Received"));
255} 287}
256 288
257void MultiplayerState::HideNotification() { 289void MultiplayerState::HideNotification() {
258 show_notification = false; 290 show_notification = false;
259 status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); 291 SetNotificationStatus(NotificationStatus::Connected);
260 status_text->setText(tr("Connected"));
261} 292}
262 293
263void MultiplayerState::OnOpenNetworkRoom() { 294void MultiplayerState::OnOpenNetworkRoom() {
@@ -280,6 +311,8 @@ void MultiplayerState::OnOpenNetworkRoom() {
280void MultiplayerState::OnDirectConnectToRoom() { 311void MultiplayerState::OnDirectConnectToRoom() {
281 if (direct_connect == nullptr) { 312 if (direct_connect == nullptr) {
282 direct_connect = new DirectConnectWindow(system, this); 313 direct_connect = new DirectConnectWindow(system, this);
314 connect(direct_connect, &DirectConnectWindow::SaveConfig, this,
315 &MultiplayerState::OnSaveConfig);
283 } 316 }
284 BringWidgetToFront(direct_connect); 317 BringWidgetToFront(direct_connect);
285} 318}
diff --git a/src/yuzu/multiplayer/state.h b/src/yuzu/multiplayer/state.h
index c92496413..5d681c5c6 100644
--- a/src/yuzu/multiplayer/state.h
+++ b/src/yuzu/multiplayer/state.h
@@ -22,6 +22,13 @@ class MultiplayerState : public QWidget {
22 Q_OBJECT; 22 Q_OBJECT;
23 23
24public: 24public:
25 enum class NotificationStatus {
26 Unitialized,
27 Disconnected,
28 Connected,
29 Notification,
30 };
31
25 explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room, 32 explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room,
26 QAction* show_room, Core::System& system_); 33 QAction* show_room, Core::System& system_);
27 ~MultiplayerState(); 34 ~MultiplayerState();
@@ -31,6 +38,10 @@ public:
31 */ 38 */
32 void Close(); 39 void Close();
33 40
41 void SetNotificationStatus(NotificationStatus state);
42
43 void UpdateNotificationStatus();
44
34 ClickableLabel* GetStatusText() const { 45 ClickableLabel* GetStatusText() const {
35 return status_text; 46 return status_text;
36 } 47 }
@@ -64,6 +75,7 @@ public slots:
64 void OnOpenNetworkRoom(); 75 void OnOpenNetworkRoom();
65 void OnDirectConnectToRoom(); 76 void OnDirectConnectToRoom();
66 void OnAnnounceFailed(const WebService::WebResult&); 77 void OnAnnounceFailed(const WebService::WebResult&);
78 void OnSaveConfig();
67 void UpdateThemedIcons(); 79 void UpdateThemedIcons();
68 void ShowNotification(); 80 void ShowNotification();
69 void HideNotification(); 81 void HideNotification();
@@ -72,6 +84,7 @@ signals:
72 void NetworkStateChanged(const Network::RoomMember::State&); 84 void NetworkStateChanged(const Network::RoomMember::State&);
73 void NetworkError(const Network::RoomMember::Error&); 85 void NetworkError(const Network::RoomMember::Error&);
74 void AnnounceFailed(const WebService::WebResult&); 86 void AnnounceFailed(const WebService::WebResult&);
87 void SaveConfig();
75 88
76private: 89private:
77 Lobby* lobby = nullptr; 90 Lobby* lobby = nullptr;
@@ -85,6 +98,7 @@ private:
85 QAction* show_room; 98 QAction* show_room;
86 std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; 99 std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
87 Network::RoomMember::State current_state = Network::RoomMember::State::Uninitialized; 100 Network::RoomMember::State current_state = Network::RoomMember::State::Uninitialized;
101 NotificationStatus notification_status = NotificationStatus::Unitialized;
88 bool has_mod_perms = false; 102 bool has_mod_perms = false;
89 Network::RoomMember::CallbackHandle<Network::RoomMember::State> state_callback_handle; 103 Network::RoomMember::CallbackHandle<Network::RoomMember::State> state_callback_handle;
90 Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle; 104 Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle;
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index e12d414d9..753797efc 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -102,7 +102,7 @@ struct Values {
102 Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"}; 102 Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};
103 103
104 // multiplayer settings 104 // multiplayer settings
105 Settings::Setting<QString> multiplayer_nickname{QStringLiteral("yuzu"), "nickname"}; 105 Settings::Setting<QString> multiplayer_nickname{{}, "nickname"};
106 Settings::Setting<QString> multiplayer_ip{{}, "ip"}; 106 Settings::Setting<QString> multiplayer_ip{{}, "ip"};
107 Settings::SwitchableSetting<uint, true> multiplayer_port{24872, 0, UINT16_MAX, "port"}; 107 Settings::SwitchableSetting<uint, true> multiplayer_port{24872, 0, UINT16_MAX, "port"};
108 Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"}; 108 Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"};