yuzu: Multiple room UI improvements

This commit is contained in:
german77 2022-09-09 15:29:22 -05:00 committed by FearlessTobi
parent f5e635adda
commit 8f207bd93d
18 changed files with 176 additions and 59 deletions

View File

@ -35,7 +35,8 @@ namespace Service::HID {
// Updating period for each HID device. // Updating period for each HID device.
// Period time is obtained by measuring the number of samples in a second on HW using a homebrew // Period time is obtained by measuring the number of samples in a second on HW using a homebrew
constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) // Correct pad_update_ns is 4ms this is overclocked to lower input lag
constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)

View File

@ -206,4 +206,14 @@ std::optional<NetworkInterface> GetSelectedNetworkInterface() {
return *res; return *res;
} }
void SelectFirstNetworkInterface() {
const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
if (network_interfaces.size() == 0) {
return;
}
Settings::values.network_interface.SetValue(network_interfaces[0].name);
}
} // namespace Network } // namespace Network

View File

@ -24,5 +24,6 @@ struct NetworkInterface {
std::vector<NetworkInterface> GetAvailableNetworkInterfaces(); std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
std::optional<NetworkInterface> GetSelectedNetworkInterface(); std::optional<NetworkInterface> GetSelectedNetworkInterface();
void SelectFirstNetworkInterface();
} // namespace Network } // namespace Network

View File

@ -1296,6 +1296,7 @@ void GMainWindow::ConnectMenuEvents() {
&MultiplayerState::OnDirectConnectToRoom); &MultiplayerState::OnDirectConnectToRoom);
connect(ui->action_Show_Room, &QAction::triggered, multiplayer_state, connect(ui->action_Show_Room, &QAction::triggered, multiplayer_state,
&MultiplayerState::OnOpenNetworkRoom); &MultiplayerState::OnOpenNetworkRoom);
connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig);
// Tools // Tools
connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
@ -1336,6 +1337,8 @@ void GMainWindow::UpdateMenuState() {
} else { } else {
ui->action_Pause->setText(tr("&Pause")); ui->action_Pause->setText(tr("&Pause"));
} }
multiplayer_state->UpdateNotificationStatus();
} }
void GMainWindow::OnDisplayTitleBars(bool show) { void GMainWindow::OnDisplayTitleBars(bool show) {
@ -2766,6 +2769,11 @@ void GMainWindow::OnExit() {
OnStopGame(); OnStopGame();
} }
void GMainWindow::OnSaveConfig() {
system->ApplySettings();
config->Save();
}
void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"), OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"),
Qt::AlignLeft | Qt::AlignVCenter); Qt::AlignLeft | Qt::AlignVCenter);

View File

@ -169,6 +169,7 @@ public slots:
void OnLoadComplete(); void OnLoadComplete();
void OnExecuteProgram(std::size_t program_index); void OnExecuteProgram(std::size_t program_index);
void OnExit(); void OnExit();
void OnSaveConfig();
void ControllerSelectorReconfigureControllers( void ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters); const Core::Frontend::ControllerParameters& parameters);
void SoftwareKeyboardInitialize( void SoftwareKeyboardInitialize(

View File

@ -265,7 +265,7 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Browse Public Game Lobby</string> <string>&amp;Browse Public Game Lobby</string>
</property> </property>
</action> </action>
<action name="action_Start_Room"> <action name="action_Start_Room">
@ -273,7 +273,7 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Create Room</string> <string>&amp;Create Room</string>
</property> </property>
</action> </action>
<action name="action_Leave_Room"> <action name="action_Leave_Room">
@ -281,12 +281,12 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Leave Room</string> <string>&amp;Leave Room</string>
</property> </property>
</action> </action>
<action name="action_Connect_To_Room"> <action name="action_Connect_To_Room">
<property name="text"> <property name="text">
<string>Direct Connect to Room</string> <string>&amp;Direct Connect to Room</string>
</property> </property>
</action> </action>
<action name="action_Show_Room"> <action name="action_Show_Room">
@ -294,7 +294,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Show Current Room</string> <string>&amp;Show Current Room</string>
</property> </property>
</action> </action>
<action name="action_Fullscreen"> <action name="action_Fullscreen">

View File

@ -97,8 +97,9 @@ void ClientRoomWindow::UpdateView() {
auto memberlist = member->GetMemberInformation(); auto memberlist = member->GetMemberInformation();
ui->chat->SetPlayerList(memberlist); ui->chat->SetPlayerList(memberlist);
const auto information = member->GetRoomInformation(); const auto information = member->GetRoomInformation();
setWindowTitle(QString(tr("%1 (%2/%3 members) - connected")) setWindowTitle(QString(tr("%1 - %2 (%3/%4 members) - connected"))
.arg(QString::fromStdString(information.name)) .arg(QString::fromStdString(information.name))
.arg(QString::fromStdString(information.preferred_game.name))
.arg(memberlist.size()) .arg(memberlist.size())
.arg(information.member_slots)); .arg(information.member_slots));
ui->description->setText(QString::fromStdString(information.description)); ui->description->setText(QString::fromStdString(information.description));

View File

@ -106,6 +106,8 @@ void DirectConnectWindow::Connect() {
UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault(); UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault();
} }
emit SaveConfig();
// attempt to connect in a different thread // attempt to connect in a different thread
QFuture<void> f = QtConcurrent::run([&] { QFuture<void> f = QtConcurrent::run([&] {
if (auto room_member = room_network.GetRoomMember().lock()) { if (auto room_member = room_network.GetRoomMember().lock()) {

View File

@ -31,6 +31,7 @@ signals:
* connections that it might have. * connections that it might have.
*/ */
void Closed(); void Closed();
void SaveConfig();
private slots: private slots:
void OnConnection(); void OnConnection();

View File

@ -232,6 +232,7 @@ void HostRoomWindow::Host() {
} }
UISettings::values.multiplayer_room_description = ui->room_description->toPlainText(); UISettings::values.multiplayer_room_description = ui->room_description->toPlainText();
ui->host->setEnabled(true); ui->host->setEnabled(true);
emit SaveConfig();
close(); close();
} }
} }

View File

@ -46,6 +46,9 @@ public:
void UpdateGameList(QStandardItemModel* list); void UpdateGameList(QStandardItemModel* list);
void RetranslateUi(); void RetranslateUi();
signals:
void SaveConfig();
private: private:
void Host(); void Host();
std::unique_ptr<Network::VerifyUser::Backend> CreateVerifyBackend(bool use_validation) const; std::unique_ptr<Network::VerifyUser::Backend> CreateVerifyBackend(bool use_validation) const;

View File

@ -7,6 +7,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/internal_network/network_interface.h" #include "core/internal_network/network_interface.h"
#include "network/network.h" #include "network/network.h"
#include "ui_lobby.h" #include "ui_lobby.h"
@ -26,9 +27,9 @@
Lobby::Lobby(QWidget* parent, QStandardItemModel* list, Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_) std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
ui(std::make_unique<Ui::Lobby>()), ui(std::make_unique<Ui::Lobby>()), announce_multiplayer_session(session),
announce_multiplayer_session(session), system{system_}, room_network{ profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_},
system.GetRoomNetwork()} { room_network{system.GetRoomNetwork()} {
ui->setupUi(this); ui->setupUi(this);
// setup the watcher for background connections // setup the watcher for background connections
@ -60,9 +61,17 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
ui->nickname->setValidator(validation.GetNickname()); ui->nickname->setValidator(validation.GetNickname());
ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue()); ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
// Use yuzu Web Service user name as nickname by default // Try find the best nickname by default
ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("yuzu")) {
if (!Settings::values.yuzu_username.GetValue().empty()) {
ui->nickname->setText(
QString::fromStdString(Settings::values.yuzu_username.GetValue()));
} else if (!GetProfileUsername().empty()) {
ui->nickname->setText(QString::fromStdString(GetProfileUsername()));
} else {
ui->nickname->setText(QStringLiteral("yuzu"));
}
} }
// UI Buttons // UI Buttons
@ -76,12 +85,6 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
// Actions // Actions
connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this, connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this,
&Lobby::OnRefreshLobby); &Lobby::OnRefreshLobby);
// manually start a refresh when the window is opening
// TODO(jroweboy): if this refresh is slow for people with bad internet, then don't do it as
// part of the constructor, but offload the refresh until after the window shown. perhaps emit a
// refreshroomlist signal from places that open the lobby
RefreshLobby();
} }
Lobby::~Lobby() = default; Lobby::~Lobby() = default;
@ -96,6 +99,7 @@ void Lobby::UpdateGameList(QStandardItemModel* list) {
} }
if (proxy) if (proxy)
proxy->UpdateGameList(game_list); proxy->UpdateGameList(game_list);
ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder);
} }
void Lobby::RetranslateUi() { void Lobby::RetranslateUi() {
@ -116,6 +120,11 @@ void Lobby::OnExpandRoom(const QModelIndex& index) {
} }
void Lobby::OnJoinRoom(const QModelIndex& source) { void Lobby::OnJoinRoom(const QModelIndex& source) {
if (!Network::GetSelectedNetworkInterface()) {
LOG_INFO(WebService, "Automatically selected network interface for room network.");
Network::SelectFirstNetworkInterface();
}
if (!Network::GetSelectedNetworkInterface()) { if (!Network::GetSelectedNetworkInterface()) {
NetworkMessage::ErrorManager::ShowError( NetworkMessage::ErrorManager::ShowError(
NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED); NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED);
@ -197,16 +206,16 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
proxy->data(connection_index, LobbyItemHost::HostIPRole).toString(); proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();
UISettings::values.multiplayer_port = UISettings::values.multiplayer_port =
proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt(); proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
emit SaveConfig();
} }
void Lobby::ResetModel() { void Lobby::ResetModel() {
model->clear(); model->clear();
model->insertColumns(0, Column::TOTAL); model->insertColumns(0, Column::TOTAL);
model->setHeaderData(Column::EXPAND, Qt::Horizontal, QString(), Qt::DisplayRole); model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole);
model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Room Name"), Qt::DisplayRole); model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Room Name"), Qt::DisplayRole);
model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Preferred Game"), Qt::DisplayRole); model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Preferred Game"), Qt::DisplayRole);
model->setHeaderData(Column::HOST, Qt::Horizontal, tr("Host"), Qt::DisplayRole); model->setHeaderData(Column::HOST, Qt::Horizontal, tr("Host"), Qt::DisplayRole);
model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole);
} }
void Lobby::RefreshLobby() { void Lobby::RefreshLobby() {
@ -229,6 +238,7 @@ void Lobby::OnRefreshLobby() {
for (int r = 0; r < game_list->rowCount(); ++r) { for (int r = 0; r < game_list->rowCount(); ++r) {
auto index = game_list->index(r, 0); auto index = game_list->index(r, 0);
auto game_id = game_list->data(index, GameListItemPath::ProgramIdRole).toULongLong(); auto game_id = game_list->data(index, GameListItemPath::ProgramIdRole).toULongLong();
if (game_id != 0 && room.information.preferred_game.id == game_id) { if (game_id != 0 && room.information.preferred_game.id == game_id) {
smdh_icon = game_list->data(index, Qt::DecorationRole).value<QPixmap>(); smdh_icon = game_list->data(index, Qt::DecorationRole).value<QPixmap>();
} }
@ -243,17 +253,16 @@ void Lobby::OnRefreshLobby() {
members.append(var); members.append(var);
} }
auto first_item = new LobbyItem(); auto first_item = new LobbyItemGame(
room.information.preferred_game.id,
QString::fromStdString(room.information.preferred_game.name), smdh_icon);
auto row = QList<QStandardItem*>({ auto row = QList<QStandardItem*>({
first_item, first_item,
new LobbyItemName(room.has_password, QString::fromStdString(room.information.name)), new LobbyItemName(room.has_password, QString::fromStdString(room.information.name)),
new LobbyItemGame(room.information.preferred_game.id, new LobbyItemMemberList(members, room.information.member_slots),
QString::fromStdString(room.information.preferred_game.name),
smdh_icon),
new LobbyItemHost(QString::fromStdString(room.information.host_username), new LobbyItemHost(QString::fromStdString(room.information.host_username),
QString::fromStdString(room.ip), room.information.port, QString::fromStdString(room.ip), room.information.port,
QString::fromStdString(room.verify_uid)), QString::fromStdString(room.verify_uid)),
new LobbyItemMemberList(members, room.information.member_slots),
}); });
model->appendRow(row); model->appendRow(row);
// To make the rows expandable, add the member data as a child of the first column of the // 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() {
ui->room_list->setFirstColumnSpanned(j, proxy->index(i, 0), true); ui->room_list->setFirstColumnSpanned(j, proxy->index(i, 0), true);
} }
} }
ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder);
}
std::string Lobby::GetProfileUsername() {
const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
Service::Account::ProfileBase profile{};
if (!current_user.has_value()) {
return "";
}
if (!profile_manager->GetProfileBase(*current_user, profile)) {
return "";
}
const auto text = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(profile.username.data()), profile.username.size());
return text;
} }
LobbyFilterProxyModel::LobbyFilterProxyModel(QWidget* parent, QStandardItemModel* list) LobbyFilterProxyModel::LobbyFilterProxyModel(QWidget* parent, QStandardItemModel* list)

View File

@ -24,6 +24,10 @@ namespace Core {
class System; class System;
} }
namespace Service::Account {
class ProfileManager;
}
/** /**
* Listing of all public games pulled from services. The lobby should be simple enough for users to * Listing of all public games pulled from services. The lobby should be simple enough for users to
* find the game they want to play, and join it. * find the game they want to play, and join it.
@ -75,8 +79,11 @@ private slots:
signals: signals:
void StateChanged(const Network::RoomMember::State&); void StateChanged(const Network::RoomMember::State&);
void SaveConfig();
private: private:
std::string GetProfileUsername();
/** /**
* Removes all entries in the Lobby before refreshing. * Removes all entries in the Lobby before refreshing.
*/ */
@ -96,6 +103,7 @@ private:
QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher; QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher;
std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
std::unique_ptr<Service::Account::ProfileManager> profile_manager;
QFutureWatcher<void>* watcher; QFutureWatcher<void>* watcher;
Validation validation; Validation validation;
Core::System& system; Core::System& system;

View File

@ -11,11 +11,10 @@
namespace Column { namespace Column {
enum List { enum List {
EXPAND,
ROOM_NAME,
GAME_NAME, GAME_NAME,
HOST, ROOM_NAME,
MEMBER, MEMBER,
HOST,
TOTAL, TOTAL,
}; };
} }
@ -98,7 +97,12 @@ public:
if (role == Qt::DecorationRole) { if (role == Qt::DecorationRole) {
auto val = data(GameIconRole); auto val = data(GameIconRole);
if (val.isValid()) { if (val.isValid()) {
val = val.value<QPixmap>().scaled(16, 16, Qt::KeepAspectRatio); val = val.value<QPixmap>().scaled(32, 32, Qt::KeepAspectRatio,
Qt::TransformationMode::SmoothTransformation);
} else {
auto blank_image = QPixmap(32, 32);
blank_image.fill(Qt::black);
val = blank_image;
} }
return val; return val;
} else if (role != Qt::DisplayRole) { } else if (role != Qt::DisplayRole) {
@ -191,8 +195,8 @@ public:
return LobbyItem::data(role); return LobbyItem::data(role);
} }
auto members = data(MemberListRole).toList(); auto members = data(MemberListRole).toList();
return QStringLiteral("%1 / %2").arg(QString::number(members.size()), return QStringLiteral("%1 / %2 ")
data(MaxPlayerRole).toString()); .arg(QString::number(members.size()), data(MaxPlayerRole).toString());
} }
bool operator<(const QStandardItem& other) const override { bool operator<(const QStandardItem& other) const override {

View File

@ -49,9 +49,9 @@ const ConnectionError ErrorManager::PERMISSION_DENIED(
QT_TR_NOOP("You do not have enough permission to perform this action.")); QT_TR_NOOP("You do not have enough permission to perform this action."));
const ConnectionError ErrorManager::NO_SUCH_USER(QT_TR_NOOP( const ConnectionError ErrorManager::NO_SUCH_USER(QT_TR_NOOP(
"The user you are trying to kick/ban could not be found.\nThey may have left the room.")); "The user you are trying to kick/ban could not be found.\nThey may have left the room."));
const ConnectionError ErrorManager::NO_INTERFACE_SELECTED( const ConnectionError ErrorManager::NO_INTERFACE_SELECTED(QT_TR_NOOP(
QT_TR_NOOP("No network interface is selected.\nPlease go to Configure -> System -> Network and " "No valid network interface is selected.\nPlease go to Configure -> System -> Network and "
"make a selection.")); "make a selection."));
static bool WarnMessage(const std::string& title, const std::string& text) { static bool WarnMessage(const std::string& title, const std::string& text) {
return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()), return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()),

View File

@ -44,9 +44,6 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis
status_text = new ClickableLabel(this); status_text = new ClickableLabel(this);
status_icon = new ClickableLabel(this); status_icon = new ClickableLabel(this);
status_text->setToolTip(tr("Current connection status"));
status_text->setText(tr("Not Connected. Click here to find a room!"));
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16));
connect(status_text, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom); connect(status_text, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom);
connect(status_icon, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom); connect(status_icon, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom);
@ -57,6 +54,8 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis
HideNotification(); HideNotification();
} }
}); });
retranslateUi();
} }
MultiplayerState::~MultiplayerState() = default; MultiplayerState::~MultiplayerState() = default;
@ -90,14 +89,7 @@ void MultiplayerState::Close() {
void MultiplayerState::retranslateUi() { void MultiplayerState::retranslateUi() {
status_text->setToolTip(tr("Current connection status")); status_text->setToolTip(tr("Current connection status"));
if (current_state == Network::RoomMember::State::Uninitialized) { UpdateNotificationStatus();
status_text->setText(tr("Not Connected. Click here to find a room!"));
} else if (current_state == Network::RoomMember::State::Joined ||
current_state == Network::RoomMember::State::Moderator) {
status_text->setText(tr("Connected"));
} else {
status_text->setText(tr("Not Connected"));
}
if (lobby) { if (lobby) {
lobby->RetranslateUi(); lobby->RetranslateUi();
@ -113,21 +105,55 @@ void MultiplayerState::retranslateUi() {
} }
} }
void MultiplayerState::SetNotificationStatus(NotificationStatus status) {
notification_status = status;
UpdateNotificationStatus();
}
void MultiplayerState::UpdateNotificationStatus() {
switch (notification_status) {
case NotificationStatus::Unitialized:
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16));
status_text->setText(tr("Not Connected. Click here to find a room!"));
leave_room->setEnabled(false);
show_room->setEnabled(false);
break;
case NotificationStatus::Disconnected:
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16));
status_text->setText(tr("Not Connected"));
leave_room->setEnabled(false);
show_room->setEnabled(false);
break;
case NotificationStatus::Connected:
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16));
status_text->setText(tr("Connected"));
leave_room->setEnabled(true);
show_room->setEnabled(true);
break;
case NotificationStatus::Notification:
status_icon->setPixmap(
QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16));
status_text->setText(tr("New Messages Received"));
leave_room->setEnabled(true);
show_room->setEnabled(true);
break;
}
// Clean up status bar if game is running
if (system.IsPoweredOn()) {
status_text->clear();
}
}
void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& state) { void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& state) {
LOG_DEBUG(Frontend, "Network State: {}", Network::GetStateStr(state)); LOG_DEBUG(Frontend, "Network State: {}", Network::GetStateStr(state));
if (state == Network::RoomMember::State::Joined || if (state == Network::RoomMember::State::Joined ||
state == Network::RoomMember::State::Moderator) { state == Network::RoomMember::State::Moderator) {
OnOpenNetworkRoom(); OnOpenNetworkRoom();
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); SetNotificationStatus(NotificationStatus::Connected);
status_text->setText(tr("Connected"));
leave_room->setEnabled(true);
show_room->setEnabled(true);
} else { } else {
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); SetNotificationStatus(NotificationStatus::Disconnected);
status_text->setText(tr("Not Connected"));
leave_room->setEnabled(false);
show_room->setEnabled(false);
} }
current_state = state; current_state = state;
@ -185,6 +211,10 @@ void MultiplayerState::OnAnnounceFailed(const WebService::WebResult& result) {
QMessageBox::Ok); QMessageBox::Ok);
} }
void MultiplayerState::OnSaveConfig() {
emit SaveConfig();
}
void MultiplayerState::UpdateThemedIcons() { void MultiplayerState::UpdateThemedIcons() {
if (show_notification) { if (show_notification) {
status_icon->setPixmap( status_icon->setPixmap(
@ -209,13 +239,16 @@ static void BringWidgetToFront(QWidget* widget) {
void MultiplayerState::OnViewLobby() { void MultiplayerState::OnViewLobby() {
if (lobby == nullptr) { if (lobby == nullptr) {
lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system); lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system);
connect(lobby, &Lobby::SaveConfig, this, &MultiplayerState::OnSaveConfig);
} }
lobby->RefreshLobby();
BringWidgetToFront(lobby); BringWidgetToFront(lobby);
} }
void MultiplayerState::OnCreateRoom() { void MultiplayerState::OnCreateRoom() {
if (host_room == nullptr) { if (host_room == nullptr) {
host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system); host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system);
connect(host_room, &HostRoomWindow::SaveConfig, this, &MultiplayerState::OnSaveConfig);
} }
BringWidgetToFront(host_room); BringWidgetToFront(host_room);
} }
@ -250,14 +283,12 @@ void MultiplayerState::ShowNotification() {
show_notification = true; show_notification = true;
QApplication::alert(nullptr); QApplication::alert(nullptr);
QApplication::beep(); QApplication::beep();
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); SetNotificationStatus(NotificationStatus::Notification);
status_text->setText(tr("New Messages Received"));
} }
void MultiplayerState::HideNotification() { void MultiplayerState::HideNotification() {
show_notification = false; show_notification = false;
status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); SetNotificationStatus(NotificationStatus::Connected);
status_text->setText(tr("Connected"));
} }
void MultiplayerState::OnOpenNetworkRoom() { void MultiplayerState::OnOpenNetworkRoom() {
@ -280,6 +311,8 @@ void MultiplayerState::OnOpenNetworkRoom() {
void MultiplayerState::OnDirectConnectToRoom() { void MultiplayerState::OnDirectConnectToRoom() {
if (direct_connect == nullptr) { if (direct_connect == nullptr) {
direct_connect = new DirectConnectWindow(system, this); direct_connect = new DirectConnectWindow(system, this);
connect(direct_connect, &DirectConnectWindow::SaveConfig, this,
&MultiplayerState::OnSaveConfig);
} }
BringWidgetToFront(direct_connect); BringWidgetToFront(direct_connect);
} }

View File

@ -22,6 +22,13 @@ class MultiplayerState : public QWidget {
Q_OBJECT; Q_OBJECT;
public: public:
enum class NotificationStatus {
Unitialized,
Disconnected,
Connected,
Notification,
};
explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room, explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room,
QAction* show_room, Core::System& system_); QAction* show_room, Core::System& system_);
~MultiplayerState(); ~MultiplayerState();
@ -31,6 +38,10 @@ public:
*/ */
void Close(); void Close();
void SetNotificationStatus(NotificationStatus state);
void UpdateNotificationStatus();
ClickableLabel* GetStatusText() const { ClickableLabel* GetStatusText() const {
return status_text; return status_text;
} }
@ -64,6 +75,7 @@ public slots:
void OnOpenNetworkRoom(); void OnOpenNetworkRoom();
void OnDirectConnectToRoom(); void OnDirectConnectToRoom();
void OnAnnounceFailed(const WebService::WebResult&); void OnAnnounceFailed(const WebService::WebResult&);
void OnSaveConfig();
void UpdateThemedIcons(); void UpdateThemedIcons();
void ShowNotification(); void ShowNotification();
void HideNotification(); void HideNotification();
@ -72,6 +84,7 @@ signals:
void NetworkStateChanged(const Network::RoomMember::State&); void NetworkStateChanged(const Network::RoomMember::State&);
void NetworkError(const Network::RoomMember::Error&); void NetworkError(const Network::RoomMember::Error&);
void AnnounceFailed(const WebService::WebResult&); void AnnounceFailed(const WebService::WebResult&);
void SaveConfig();
private: private:
Lobby* lobby = nullptr; Lobby* lobby = nullptr;
@ -85,6 +98,7 @@ private:
QAction* show_room; QAction* show_room;
std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
Network::RoomMember::State current_state = Network::RoomMember::State::Uninitialized; Network::RoomMember::State current_state = Network::RoomMember::State::Uninitialized;
NotificationStatus notification_status = NotificationStatus::Unitialized;
bool has_mod_perms = false; bool has_mod_perms = false;
Network::RoomMember::CallbackHandle<Network::RoomMember::State> state_callback_handle; Network::RoomMember::CallbackHandle<Network::RoomMember::State> state_callback_handle;
Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle; Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle;

View File

@ -102,7 +102,7 @@ struct Values {
Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"}; Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};
// multiplayer settings // multiplayer settings
Settings::Setting<QString> multiplayer_nickname{QStringLiteral("yuzu"), "nickname"}; Settings::Setting<QString> multiplayer_nickname{{}, "nickname"};
Settings::Setting<QString> multiplayer_ip{{}, "ip"}; Settings::Setting<QString> multiplayer_ip{{}, "ip"};
Settings::SwitchableSetting<uint, true> multiplayer_port{24872, 0, UINT16_MAX, "port"}; Settings::SwitchableSetting<uint, true> multiplayer_port{24872, 0, UINT16_MAX, "port"};
Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"}; Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"};