From 705f7db84dd85555a6aef1e136cf251725cef293 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sat, 25 Dec 2021 20:27:52 +0100 Subject: yuzu: Add ui files for multiplayer rooms --- src/yuzu/multiplayer/host_room.cpp | 237 +++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 src/yuzu/multiplayer/host_room.cpp (limited to 'src/yuzu/multiplayer/host_room.cpp') diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp new file mode 100644 index 000000000..1b73e2bec --- /dev/null +++ b/src/yuzu/multiplayer/host_room.cpp @@ -0,0 +1,237 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common/logging/log.h" +#include "common/settings.h" +#include "core/announce_multiplayer_session.h" +#include "ui_host_room.h" +#include "yuzu/game_list_p.h" +#include "yuzu/main.h" +#include "yuzu/multiplayer/host_room.h" +#include "yuzu/multiplayer/message.h" +#include "yuzu/multiplayer/state.h" +#include "yuzu/multiplayer/validation.h" +#include "yuzu/uisettings.h" +#ifdef ENABLE_WEB_SERVICE +#include "web_service/verify_user_jwt.h" +#endif + +HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list, + std::shared_ptr session) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), + ui(std::make_unique()), announce_multiplayer_session(session) { + ui->setupUi(this); + + // set up validation for all of the fields + ui->room_name->setValidator(validation.GetRoomName()); + ui->username->setValidator(validation.GetNickname()); + ui->port->setValidator(validation.GetPort()); + ui->port->setPlaceholderText(QString::number(Network::DefaultRoomPort)); + + // Create a proxy to the game list to display the list of preferred games + game_list = new QStandardItemModel; + UpdateGameList(list); + + proxy = new ComboBoxProxyModel; + proxy->setSourceModel(game_list); + proxy->sort(0, Qt::AscendingOrder); + ui->game_list->setModel(proxy); + + // Connect all the widgets to the appropriate events + connect(ui->host, &QPushButton::clicked, this, &HostRoomWindow::Host); + + // Restore the settings: + ui->username->setText(UISettings::values.room_nickname); + if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { + // Use yuzu Web Service user name as nickname by default + ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); + } + ui->room_name->setText(UISettings::values.room_name); + ui->port->setText(UISettings::values.room_port); + ui->max_player->setValue(UISettings::values.max_player); + int index = UISettings::values.host_type; + if (index < ui->host_type->count()) { + ui->host_type->setCurrentIndex(index); + } + index = ui->game_list->findData(UISettings::values.game_id, GameListItemPath::ProgramIdRole); + if (index != -1) { + ui->game_list->setCurrentIndex(index); + } + ui->room_description->setText(UISettings::values.room_description); +} + +HostRoomWindow::~HostRoomWindow() = default; + +void HostRoomWindow::UpdateGameList(QStandardItemModel* list) { + game_list->clear(); + for (int i = 0; i < list->rowCount(); i++) { + auto parent = list->item(i, 0); + for (int j = 0; j < parent->rowCount(); j++) { + game_list->appendRow(parent->child(j)->clone()); + } + } +} + +void HostRoomWindow::RetranslateUi() { + ui->retranslateUi(this); +} + +std::unique_ptr HostRoomWindow::CreateVerifyBackend( + bool use_validation) const { + std::unique_ptr verify_backend; + if (use_validation) { +#ifdef ENABLE_WEB_SERVICE + verify_backend = std::make_unique(Settings::values.web_api_url); +#else + verify_backend = std::make_unique(); +#endif + } else { + verify_backend = std::make_unique(); + } + return verify_backend; +} + +void HostRoomWindow::Host() { + if (!ui->username->hasAcceptableInput()) { + NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::USERNAME_NOT_VALID); + return; + } + if (!ui->room_name->hasAcceptableInput()) { + NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::ROOMNAME_NOT_VALID); + return; + } + if (!ui->port->hasAcceptableInput()) { + NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::PORT_NOT_VALID); + return; + } + if (ui->game_list->currentIndex() == -1) { + NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::GAME_NOT_SELECTED); + return; + } + if (auto member = Network::GetRoomMember().lock()) { + if (member->GetState() == Network::RoomMember::State::Joining) { + return; + } else if (member->IsConnected()) { + auto parent = static_cast(parentWidget()); + if (!parent->OnCloseRoom()) { + close(); + return; + } + } + ui->host->setDisabled(true); + + auto game_name = ui->game_list->currentData(Qt::DisplayRole).toString(); + auto game_id = ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong(); + auto port = ui->port->isModified() ? ui->port->text().toInt() : Network::DefaultRoomPort; + auto password = ui->password->text().toStdString(); + const bool is_public = ui->host_type->currentIndex() == 0; + Network::Room::BanList ban_list{}; + if (ui->load_ban_list->isChecked()) { + ban_list = UISettings::values.ban_list; + } + if (auto room = Network::GetRoom().lock()) { + bool created = room->Create( + ui->room_name->text().toStdString(), + ui->room_description->toPlainText().toStdString(), "", port, password, + ui->max_player->value(), Settings::values.yuzu_username.GetValue(), + game_name.toStdString(), game_id, CreateVerifyBackend(is_public), ban_list); + if (!created) { + NetworkMessage::ErrorManager::ShowError( + NetworkMessage::ErrorManager::COULD_NOT_CREATE_ROOM); + LOG_ERROR(Network, "Could not create room!"); + ui->host->setEnabled(true); + return; + } + } + // Start the announce session if they chose Public + if (is_public) { + if (auto session = announce_multiplayer_session.lock()) { + // Register the room first to ensure verify_UID is present when we connect + WebService::WebResult result = session->Register(); + if (result.result_code != WebService::WebResult::Code::Success) { + QMessageBox::warning( + this, tr("Error"), + tr("Failed to announce the room to the public lobby. In order to host a " + "room publicly, you must have a valid yuzu account configured in " + "Emulation -> Configure -> Web. If you do not want to publish a room in " + "the public lobby, then select Unlisted instead.\nDebug Message: ") + + QString::fromStdString(result.result_string), + QMessageBox::Ok); + ui->host->setEnabled(true); + if (auto room = Network::GetRoom().lock()) { + room->Destroy(); + } + return; + } + session->Start(); + } else { + LOG_ERROR(Network, "Starting announce session failed"); + } + } + std::string token; +#ifdef ENABLE_WEB_SERVICE + if (is_public) { + WebService::Client client(Settings::values.web_api_url, Settings::values.yuzu_username, + Settings::values.yuzu_token); + if (auto room = Network::GetRoom().lock()) { + token = client.GetExternalJWT(room->GetVerifyUID()).returned_data; + } + if (token.empty()) { + LOG_ERROR(WebService, "Could not get external JWT, verification may fail"); + } else { + LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size()); + } + } +#endif + // TODO: Check what to do with this + member->Join(ui->username->text().toStdString(), "", "127.0.0.1", port, 0, + Network::NoPreferredMac, password, token); + + // Store settings + UISettings::values.room_nickname = ui->username->text(); + UISettings::values.room_name = ui->room_name->text(); + UISettings::values.game_id = + ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong(); + UISettings::values.max_player = ui->max_player->value(); + + UISettings::values.host_type = ui->host_type->currentIndex(); + UISettings::values.room_port = (ui->port->isModified() && !ui->port->text().isEmpty()) + ? ui->port->text() + : QString::number(Network::DefaultRoomPort); + UISettings::values.room_description = ui->room_description->toPlainText(); + ui->host->setEnabled(true); + close(); + } +} + +QVariant ComboBoxProxyModel::data(const QModelIndex& idx, int role) const { + if (role != Qt::DisplayRole) { + auto val = QSortFilterProxyModel::data(idx, role); + // If its the icon, shrink it to 16x16 + if (role == Qt::DecorationRole) + val = val.value().scaled(16, 16, Qt::KeepAspectRatio); + return val; + } + std::string filename; + Common::SplitPath( + QSortFilterProxyModel::data(idx, GameListItemPath::FullPathRole).toString().toStdString(), + nullptr, &filename, nullptr); + QString title = QSortFilterProxyModel::data(idx, GameListItemPath::TitleRole).toString(); + return title.isEmpty() ? QString::fromStdString(filename) : title; +} + +bool ComboBoxProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { + auto leftData = left.data(GameListItemPath::TitleRole).toString(); + auto rightData = right.data(GameListItemPath::TitleRole).toString(); + return leftData.compare(rightData) < 0; +} -- cgit v1.2.3 From 6c8e45618578de1406c0bf4a7f976bd4903c339c Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Fri, 15 Jul 2022 19:45:35 +0200 Subject: Address first part of review comments --- src/yuzu/multiplayer/host_room.cpp | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'src/yuzu/multiplayer/host_room.cpp') diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index 1b73e2bec..5470b8b86 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -51,23 +51,24 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list, connect(ui->host, &QPushButton::clicked, this, &HostRoomWindow::Host); // Restore the settings: - ui->username->setText(UISettings::values.room_nickname); + ui->username->setText(UISettings::values.multiplayer_room_nickname.GetValue()); if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { // Use yuzu Web Service user name as nickname by default ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); } - ui->room_name->setText(UISettings::values.room_name); - ui->port->setText(UISettings::values.room_port); - ui->max_player->setValue(UISettings::values.max_player); - int index = UISettings::values.host_type; + ui->room_name->setText(UISettings::values.multiplayer_room_name.GetValue()); + ui->port->setText(QString::number(UISettings::values.multiplayer_room_port.GetValue())); + ui->max_player->setValue(UISettings::values.multiplayer_max_player.GetValue()); + int index = UISettings::values.multiplayer_host_type.GetValue(); if (index < ui->host_type->count()) { ui->host_type->setCurrentIndex(index); } - index = ui->game_list->findData(UISettings::values.game_id, GameListItemPath::ProgramIdRole); + index = ui->game_list->findData(UISettings::values.multiplayer_game_id.GetValue(), + GameListItemPath::ProgramIdRole); if (index != -1) { ui->game_list->setCurrentIndex(index); } - ui->room_description->setText(UISettings::values.room_description); + ui->room_description->setText(UISettings::values.multiplayer_room_description.GetValue()); } HostRoomWindow::~HostRoomWindow() = default; @@ -91,7 +92,8 @@ std::unique_ptr HostRoomWindow::CreateVerifyBacken std::unique_ptr verify_backend; if (use_validation) { #ifdef ENABLE_WEB_SERVICE - verify_backend = std::make_unique(Settings::values.web_api_url); + verify_backend = + std::make_unique(Settings::values.web_api_url.GetValue()); #else verify_backend = std::make_unique(); #endif @@ -137,7 +139,7 @@ void HostRoomWindow::Host() { const bool is_public = ui->host_type->currentIndex() == 0; Network::Room::BanList ban_list{}; if (ui->load_ban_list->isChecked()) { - ban_list = UISettings::values.ban_list; + ban_list = UISettings::values.multiplayer_ban_list; } if (auto room = Network::GetRoom().lock()) { bool created = room->Create( @@ -181,8 +183,9 @@ void HostRoomWindow::Host() { std::string token; #ifdef ENABLE_WEB_SERVICE if (is_public) { - WebService::Client client(Settings::values.web_api_url, Settings::values.yuzu_username, - Settings::values.yuzu_token); + WebService::Client client(Settings::values.web_api_url.GetValue(), + Settings::values.yuzu_username.GetValue(), + Settings::values.yuzu_token.GetValue()); if (auto room = Network::GetRoom().lock()) { token = client.GetExternalJWT(room->GetVerifyUID()).returned_data; } @@ -198,17 +201,19 @@ void HostRoomWindow::Host() { Network::NoPreferredMac, password, token); // Store settings - UISettings::values.room_nickname = ui->username->text(); - UISettings::values.room_name = ui->room_name->text(); - UISettings::values.game_id = + UISettings::values.multiplayer_room_nickname = ui->username->text(); + UISettings::values.multiplayer_room_name = ui->room_name->text(); + UISettings::values.multiplayer_game_id = ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong(); - UISettings::values.max_player = ui->max_player->value(); + UISettings::values.multiplayer_max_player = ui->max_player->value(); - UISettings::values.host_type = ui->host_type->currentIndex(); - UISettings::values.room_port = (ui->port->isModified() && !ui->port->text().isEmpty()) - ? ui->port->text() - : QString::number(Network::DefaultRoomPort); - UISettings::values.room_description = ui->room_description->toPlainText(); + UISettings::values.multiplayer_host_type = ui->host_type->currentIndex(); + if (ui->port->isModified() && !ui->port->text().isEmpty()) { + UISettings::values.multiplayer_room_port = ui->port->text().toInt(); + } else { + UISettings::values.multiplayer_room_port = Network::DefaultRoomPort; + } + UISettings::values.multiplayer_room_description = ui->room_description->toPlainText(); ui->host->setEnabled(true); close(); } -- cgit v1.2.3 From 899c8bb33094f43fbd8df9afb4ca84718ebac87e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 17 Jul 2022 22:53:44 -0500 Subject: common: multiplayer: Use GameInfo type --- src/yuzu/multiplayer/host_room.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/yuzu/multiplayer/host_room.cpp') diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index 5470b8b86..053e22fe4 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -132,21 +132,24 @@ void HostRoomWindow::Host() { } ui->host->setDisabled(true); - auto game_name = ui->game_list->currentData(Qt::DisplayRole).toString(); - auto game_id = ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong(); - auto port = ui->port->isModified() ? ui->port->text().toInt() : Network::DefaultRoomPort; - auto password = ui->password->text().toStdString(); + const AnnounceMultiplayerRoom::GameInfo game{ + .name = ui->game_list->currentData(Qt::DisplayRole).toString().toStdString(), + .id = ui->game_list->currentData(GameListItemPath::ProgramIdRole).toULongLong(), + }; + const auto port = + ui->port->isModified() ? ui->port->text().toInt() : Network::DefaultRoomPort; + const auto password = ui->password->text().toStdString(); const bool is_public = ui->host_type->currentIndex() == 0; Network::Room::BanList ban_list{}; if (ui->load_ban_list->isChecked()) { ban_list = UISettings::values.multiplayer_ban_list; } if (auto room = Network::GetRoom().lock()) { - bool created = room->Create( - ui->room_name->text().toStdString(), - ui->room_description->toPlainText().toStdString(), "", port, password, - ui->max_player->value(), Settings::values.yuzu_username.GetValue(), - game_name.toStdString(), game_id, CreateVerifyBackend(is_public), ban_list); + const bool created = + room->Create(ui->room_name->text().toStdString(), + ui->room_description->toPlainText().toStdString(), "", port, password, + ui->max_player->value(), Settings::values.yuzu_username.GetValue(), + game, CreateVerifyBackend(is_public), ban_list); if (!created) { NetworkMessage::ErrorManager::ShowError( NetworkMessage::ErrorManager::COULD_NOT_CREATE_ROOM); -- cgit v1.2.3 From 7d82e57b91dee30e0fe6fed36550ea7cc9eb778e Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Fri, 22 Jul 2022 16:31:13 +0200 Subject: network: Move global state into a seperate class Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com> --- src/yuzu/multiplayer/host_room.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/yuzu/multiplayer/host_room.cpp') diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index 053e22fe4..a48077544 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -27,9 +27,11 @@ #endif HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list, - std::shared_ptr session) + std::shared_ptr session, + Network::RoomNetwork& room_network_) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), - ui(std::make_unique()), announce_multiplayer_session(session) { + ui(std::make_unique()), + announce_multiplayer_session(session), room_network{room_network_} { ui->setupUi(this); // set up validation for all of the fields @@ -120,7 +122,7 @@ void HostRoomWindow::Host() { NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::GAME_NOT_SELECTED); return; } - if (auto member = Network::GetRoomMember().lock()) { + if (auto member = room_network.GetRoomMember().lock()) { if (member->GetState() == Network::RoomMember::State::Joining) { return; } else if (member->IsConnected()) { @@ -144,7 +146,7 @@ void HostRoomWindow::Host() { if (ui->load_ban_list->isChecked()) { ban_list = UISettings::values.multiplayer_ban_list; } - if (auto room = Network::GetRoom().lock()) { + if (auto room = room_network.GetRoom().lock()) { const bool created = room->Create(ui->room_name->text().toStdString(), ui->room_description->toPlainText().toStdString(), "", port, password, @@ -173,7 +175,7 @@ void HostRoomWindow::Host() { QString::fromStdString(result.result_string), QMessageBox::Ok); ui->host->setEnabled(true); - if (auto room = Network::GetRoom().lock()) { + if (auto room = room_network.GetRoom().lock()) { room->Destroy(); } return; @@ -189,7 +191,7 @@ void HostRoomWindow::Host() { WebService::Client client(Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(), Settings::values.yuzu_token.GetValue()); - if (auto room = Network::GetRoom().lock()) { + if (auto room = room_network.GetRoom().lock()) { token = client.GetExternalJWT(room->GetVerifyUID()).returned_data; } if (token.empty()) { -- cgit v1.2.3 From 6a2dcc8b3d4ed0940e33d60fee701bcdb063eb6b Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Mon, 25 Jul 2022 17:08:20 +0200 Subject: network, yuzu: Improve variable naming and style consistency --- src/yuzu/multiplayer/host_room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/yuzu/multiplayer/host_room.cpp') diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index a48077544..f59c6a28d 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -163,7 +163,7 @@ void HostRoomWindow::Host() { // Start the announce session if they chose Public if (is_public) { if (auto session = announce_multiplayer_session.lock()) { - // Register the room first to ensure verify_UID is present when we connect + // Register the room first to ensure verify_uid is present when we connect WebService::WebResult result = session->Register(); if (result.result_code != WebService::WebResult::Code::Success) { QMessageBox::warning( -- cgit v1.2.3 From 61ce57b5242984c297283de5868ea4938391a911 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Mon, 25 Jul 2022 17:18:30 +0200 Subject: network, yuzu: Make copyright headers SPDX-compliant --- src/yuzu/multiplayer/host_room.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/yuzu/multiplayer/host_room.cpp') diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index f59c6a28d..cb9464b2b 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -1,6 +1,5 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include #include -- cgit v1.2.3