From 25085ecb31c6110624f79a403234e68f346c8fea Mon Sep 17 00:00:00 2001 From: Jamie Meyer <45072324+HeatXD@users.noreply.github.com> Date: Sat, 29 Jul 2023 05:39:20 +0200 Subject: [PATCH] Netplay/UI update adding the traveral options to the ui. also added the roomcode to the onscreen overlay for now. --- src/core/netplay.cpp | 19 +- src/core/netplay.h | 6 +- .../createnetplaysessiondialog.ui | 25 +- .../joinnetplaysessiondialog.ui | 252 ++++++++++++------ src/duckstation-qt/netplaydialogs.cpp | 38 ++- src/duckstation-qt/netplaydialogs.h | 1 + src/duckstation-qt/qthost.cpp | 19 +- src/duckstation-qt/qthost.h | 4 +- src/frontend-common/imgui_netplay.cpp | 7 +- 9 files changed, 252 insertions(+), 119 deletions(-) diff --git a/src/core/netplay.cpp b/src/core/netplay.cpp index 0977c34b0..a9d45516f 100644 --- a/src/core/netplay.cpp +++ b/src/core/netplay.cpp @@ -129,7 +129,7 @@ static void SendTraversalPingRequest(); // GGPO session. static void CreateGGPOSession(); static void DestroyGGPOSession(); -static bool Start(bool is_hosting, std::string nickname, const std::string& remote_addr, s32 port, s32 ldelay, bool traversal = true); +static bool Start(bool is_hosting, std::string nickname, const std::string& remote_addr, s32 port, s32 ldelay, bool traversal); static void CloseSession(); // Host functions. @@ -372,8 +372,6 @@ bool Netplay::Start(bool is_hosting, std::string nickname, const std::string& re Log_ErrorPrintf("Failed to create enet host."); return false; } - // temp testing - s_traversal_host_code = nickname; s_host_player_id = 0; s_local_nickname = std::move(nickname); @@ -2359,6 +2357,11 @@ u32 Netplay::GetMaxPrediction() return MAX_ROLLBACK_FRAMES; } +std::string_view Netplay::GetHostCode() +{ + return s_traversal_host_code; +} + void Netplay::SetInputs(Netplay::Input inputs[2]) { for (u32 i = 0; i < 2; i++) @@ -2370,7 +2373,7 @@ void Netplay::SetInputs(Netplay::Input inputs[2]) } } -bool Netplay::CreateSession(std::string nickname, s32 port, s32 max_players, std::string password, int inputdelay) +bool Netplay::CreateSession(std::string nickname, s32 port, s32 max_players, std::string password, int inputdelay, bool traversal) { s_local_session_password = std::move(password); @@ -2378,7 +2381,7 @@ bool Netplay::CreateSession(std::string nickname, s32 port, s32 max_players, std // to have the same data, and we don't want to trash their local memcards. We should therefore load // the memory cards for this game (based on game/global settings), and copy that to the temp card. - if (!Netplay::Start(true, std::move(nickname), std::string(), port, inputdelay)) + if (!Netplay::Start(true, std::move(nickname), std::string(), port, inputdelay, traversal)) { CloseSession(); return false; @@ -2393,12 +2396,14 @@ bool Netplay::CreateSession(std::string nickname, s32 port, s32 max_players, std } bool Netplay::JoinSession(std::string nickname, const std::string& hostname, s32 port, std::string password, - bool spectating, int inputdelay) + bool spectating, int inputdelay, bool traversal, const std::string& hostcode) { s_local_session_password = std::move(password); s_local_spectating = spectating; - if (!Netplay::Start(false, std::move(nickname), hostname, port, inputdelay)) + s_traversal_host_code = hostcode; + + if (!Netplay::Start(false, std::move(nickname), hostname, port, inputdelay, traversal)) { CloseSession(); return false; diff --git a/src/core/netplay.h b/src/core/netplay.h index 674c6372d..af4e1cd89 100644 --- a/src/core/netplay.h +++ b/src/core/netplay.h @@ -31,8 +31,9 @@ enum : u8 NUM_ENET_CHANNELS, }; -bool CreateSession(std::string nickname, s32 port, s32 max_players, std::string password, int inputdelay); -bool JoinSession(std::string nickname, const std::string& hostname, s32 port, std::string password, bool spectating, int inputdelay); +bool CreateSession(std::string nickname, s32 port, s32 max_players, std::string password, int inputdelay, bool traversal); +bool JoinSession(std::string nickname, const std::string& hostname, s32 port, std::string password, bool spectating, + int inputdelay, bool traversal, const std::string& hostcode); bool IsActive(); @@ -49,6 +50,7 @@ void SendChatMessage(const std::string_view& msg); s32 GetPing(); u32 GetMaxPrediction(); +std::string_view GetHostCode(); /// Updates the throttle period, call when target emulation speed changes. void UpdateThrottlePeriod(); diff --git a/src/duckstation-qt/createnetplaysessiondialog.ui b/src/duckstation-qt/createnetplaysessiondialog.ui index 14a3ca781..9aa4b6d98 100644 --- a/src/duckstation-qt/createnetplaysessiondialog.ui +++ b/src/duckstation-qt/createnetplaysessiondialog.ui @@ -10,7 +10,7 @@ 0 0 496 - 267 + 302 @@ -53,7 +53,7 @@ - Select a nickname and port to open your current game session to other players via netplay. A password may optionally be supplied to restrict who can join. + <html><head/><body><p>Select a nickname and port to open your current game session to other players via netplay. A password may optionally be supplied to restrict who can join. The traversal mode option can be enabled to allow other players to join via a host code without needing to portforward.</p></body></html> true @@ -159,11 +159,22 @@ - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - + + + + + Enable Traversal Mode + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/src/duckstation-qt/joinnetplaysessiondialog.ui b/src/duckstation-qt/joinnetplaysessiondialog.ui index 8f50d0657..42a38e579 100644 --- a/src/duckstation-qt/joinnetplaysessiondialog.ui +++ b/src/duckstation-qt/joinnetplaysessiondialog.ui @@ -10,7 +10,7 @@ 0 0 480 - 254 + 308 @@ -65,95 +65,183 @@ Qt::Vertical + + QSizePolicy::Expanding + 20 - 40 + 10 - - - - - Nickname: - - - - - - - Netplay Peer - - - 128 - - - - - - - Port: - - - - - - - 1 - - - 65535 - - - 31200 - - - - - - - Hostname: - - - - - - - localhost - - - - - - - Password: - - - - - - - 128 - - - QLineEdit::Normal - - - - - - - Input Delay: - - - - - - - + + + + 0 + 190 + + + + 0 + + + + Direct Mode + + + + + + + + Nickname: + + + + + + + Netplay Peer + + + 128 + + + + + + + Input Delay: + + + + + + + + + + Hostname: + + + + + + + localhost + + + + + + + Port: + + + + + + + 1 + + + 65535 + + + 31200 + + + + + + + Password: + + + + + + + 128 + + + QLineEdit::Normal + + + + + + + + + + Traversal Mode + + + + + + + + Nickname: + + + + + + + Netplay Peer + + + 128 + + + + + + + + + + Password: + + + + + + + 128 + + + QLineEdit::Normal + + + + + + + Host Code: + + + + + + + + + + Input Delay: + + + + + + + + diff --git a/src/duckstation-qt/netplaydialogs.cpp b/src/duckstation-qt/netplaydialogs.cpp index 15942cd46..c37c6f978 100644 --- a/src/duckstation-qt/netplaydialogs.cpp +++ b/src/duckstation-qt/netplaydialogs.cpp @@ -38,9 +38,10 @@ void CreateNetplaySessionDialog::accept() const int inputdelay = m_ui.inputDelay->value(); const QString& nickname = m_ui.nickname->text(); const QString& password = m_ui.password->text(); + const bool traversal = m_ui.traversal->isChecked(); QDialog::accept(); - g_emu_thread->createNetplaySession(nickname.trimmed(), port, players, password, inputdelay); + g_emu_thread->createNetplaySession(nickname.trimmed(), port, players, password, inputdelay, traversal); } bool CreateNetplaySessionDialog::validate() @@ -64,9 +65,14 @@ JoinNetplaySessionDialog::JoinNetplaySessionDialog(QWidget* parent) connect(m_ui.port, &QSpinBox::valueChanged, this, &JoinNetplaySessionDialog::updateState); connect(m_ui.inputDelay, &QSpinBox::valueChanged, this, &JoinNetplaySessionDialog::updateState); + connect(m_ui.inputDelayTraversal, &QSpinBox::valueChanged, this, &JoinNetplaySessionDialog::updateState); connect(m_ui.nickname, &QLineEdit::textChanged, this, &JoinNetplaySessionDialog::updateState); + connect(m_ui.nicknameTraversal, &QLineEdit::textChanged, this, &JoinNetplaySessionDialog::updateState); connect(m_ui.password, &QLineEdit::textChanged, this, &JoinNetplaySessionDialog::updateState); + connect(m_ui.passwordTraversal, &QLineEdit::textChanged, this, &JoinNetplaySessionDialog::updateState); connect(m_ui.hostname, &QLineEdit::textChanged, this, &JoinNetplaySessionDialog::updateState); + connect(m_ui.hostCode, &QLineEdit::textChanged, this, &JoinNetplaySessionDialog::updateState); + connect(m_ui.tabConnectMode, &QTabWidget::currentChanged, this, &JoinNetplaySessionDialog::updateState); connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &JoinNetplaySessionDialog::accept); @@ -80,18 +86,22 @@ JoinNetplaySessionDialog::~JoinNetplaySessionDialog() = default; void JoinNetplaySessionDialog::accept() { - if (!validate()) + const bool direct_mode = !m_ui.tabDirect->isHidden(); + const bool valid = direct_mode ? validate() : validateTraversal(); + if (!valid) return; - const int port = m_ui.port->value(); - const int inputdelay = m_ui.inputDelay->value(); - const QString& nickname = m_ui.nickname->text(); + int port = m_ui.port->value(); + int inputdelay = direct_mode ? m_ui.inputDelay->value() : m_ui.inputDelayTraversal->value(); + const QString& nickname = direct_mode ? m_ui.nickname->text() : m_ui.nicknameTraversal->text(); + const QString& password = direct_mode ? m_ui.password->text() : m_ui.passwordTraversal->text(); const QString& hostname = m_ui.hostname->text(); - const QString& password = m_ui.password->text(); + const QString& hostcode = m_ui.hostCode->text(); const bool spectating = m_ui.spectating->isChecked(); QDialog::accept(); - g_emu_thread->joinNetplaySession(nickname.trimmed(), hostname.trimmed(), port, password, spectating, inputdelay); + g_emu_thread->joinNetplaySession(nickname.trimmed(), hostname.trimmed(), port, password, spectating, inputdelay, + !direct_mode, hostcode.trimmed()); } bool JoinNetplaySessionDialog::validate() @@ -100,10 +110,20 @@ bool JoinNetplaySessionDialog::validate() const int inputdelay = m_ui.inputDelay->value(); const QString& nickname = m_ui.nickname->text(); const QString& hostname = m_ui.hostname->text(); - return (!nickname.isEmpty() && !hostname.isEmpty() && port > 0 && port <= 65535 && inputdelay >= 0 && inputdelay <= 10); + return (!nickname.isEmpty() && !hostname.isEmpty() && port > 0 && port <= 65535 && inputdelay >= 0 && + inputdelay <= 10); +} + +bool JoinNetplaySessionDialog::validateTraversal() +{ + const int inputdelay = m_ui.inputDelayTraversal->value(); + const QString& nickname = m_ui.nicknameTraversal->text(); + const QString& hostcode = m_ui.hostCode->text(); + return (!nickname.isEmpty() && !hostcode.isEmpty() && inputdelay >= 0 && inputdelay <= 10); } void JoinNetplaySessionDialog::updateState() { - m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(validate()); + m_ui.buttonBox->button(QDialogButtonBox::Ok) + ->setEnabled(!m_ui.tabDirect->isHidden() ? validate() : validateTraversal()); } diff --git a/src/duckstation-qt/netplaydialogs.h b/src/duckstation-qt/netplaydialogs.h index 2e5e3f5a7..986a319b7 100644 --- a/src/duckstation-qt/netplaydialogs.h +++ b/src/duckstation-qt/netplaydialogs.h @@ -44,6 +44,7 @@ private Q_SLOTS: private: bool validate(); + bool validateTraversal(); private: Ui::JoinNetplaySessionDialog m_ui; diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index abb5c491d..fbba8fad7 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1071,13 +1071,13 @@ void EmuThread::reloadPostProcessingShaders() System::ReloadPostProcessingShaders(); } -void EmuThread::createNetplaySession(const QString& nickname, qint32 port, qint32 max_players, const QString& password, int inputdelay) +void EmuThread::createNetplaySession(const QString& nickname, qint32 port, qint32 max_players, const QString& password, int inputdelay, bool traversal) { if (!isOnThread()) { QMetaObject::invokeMethod(this, "createNetplaySession", Qt::QueuedConnection, Q_ARG(const QString&, nickname), Q_ARG(qint32, port), Q_ARG(qint32, max_players), Q_ARG(const QString&, password), - Q_ARG(int, inputdelay)); + Q_ARG(int, inputdelay), Q_ARG(bool, traversal)); return; } @@ -1085,7 +1085,7 @@ void EmuThread::createNetplaySession(const QString& nickname, qint32 port, qint3 if (!System::IsValid()) return; - if (!Netplay::CreateSession(nickname.toStdString(), port, max_players, password.toStdString(), inputdelay)) + if (!Netplay::CreateSession(nickname.toStdString(), port, max_players, password.toStdString(), inputdelay, traversal)) { errorReported(tr("Netplay Error"), tr("Failed to create netplay session. The log may contain more information.")); return; @@ -1093,18 +1093,19 @@ void EmuThread::createNetplaySession(const QString& nickname, qint32 port, qint3 } void EmuThread::joinNetplaySession(const QString& nickname, const QString& hostname, qint32 port, - const QString& password, bool spectating, int inputdelay) + const QString& password, bool spectating, int inputdelay, bool traversal, + const QString& hostcode) { if (!isOnThread()) { QMetaObject::invokeMethod(this, "joinNetplaySession", Qt::QueuedConnection, Q_ARG(const QString&, nickname), Q_ARG(const QString&, hostname), Q_ARG(qint32, port), Q_ARG(const QString&, password), - Q_ARG(bool, spectating), Q_ARG(int, inputdelay)); + Q_ARG(bool, spectating), Q_ARG(int, inputdelay), Q_ARG(bool, traversal), + Q_ARG(const QString&, hostcode)); return; } - if (!Netplay::JoinSession(nickname.toStdString(), hostname.toStdString(), port, password.toStdString(), spectating, - inputdelay)) + if (!Netplay::JoinSession(nickname.toStdString(), hostname.toStdString(), port, password.toStdString(), spectating, inputdelay, traversal, hostcode.toStdString())) { errorReported(tr("Netplay Error"), tr("Failed to join netplay session. The log may contain more information.")); return; @@ -2256,11 +2257,11 @@ int main(int argc, char* argv[]) params->override_fast_boot = true; params->fast_forward_to_first_frame = true; g_emu_thread->bootSystem(std::move(params)); - g_emu_thread->createNetplaySession(nickname, port, 2, QString(), 0); + g_emu_thread->createNetplaySession(nickname, port, 2, QString(), 0, false); } else { - g_emu_thread->joinNetplaySession(nickname, remote, port, QString(), false, 0); + g_emu_thread->joinNetplaySession(nickname, remote, port, QString(), false, 0, false, ""); } }); } diff --git a/src/duckstation-qt/qthost.h b/src/duckstation-qt/qthost.h index 4f01f83c3..793c261fd 100644 --- a/src/duckstation-qt/qthost.h +++ b/src/duckstation-qt/qthost.h @@ -188,9 +188,9 @@ public Q_SLOTS: void applyCheat(quint32 index); void reloadPostProcessingShaders(); void createNetplaySession(const QString& nickname, qint32 port, qint32 max_players, const QString& password, - int inputdelay); + int inputdelay, bool traversal); void joinNetplaySession(const QString& nickname, const QString& hostname, qint32 port, const QString& password, - bool spectating, int inputdelay); + bool spectating, int inputdelay, bool traversal, const QString& hostcode); void clearInputBindStateFromSource(InputBindingKey key); private Q_SLOTS: diff --git a/src/frontend-common/imgui_netplay.cpp b/src/frontend-common/imgui_netplay.cpp index f5881db04..3502e8845 100644 --- a/src/frontend-common/imgui_netplay.cpp +++ b/src/frontend-common/imgui_netplay.cpp @@ -141,7 +141,12 @@ void ImGuiManager::DrawNetplayStats() // We'll probably want to draw a graph too.. LargeString text; - text.AppendFmtString("Ping: {}", Netplay::GetPing()); + text.AppendFmtString("Ping: {}\n", Netplay::GetPing()); + + // temporary show the hostcode here for now + auto hostcode = Netplay::GetHostCode(); + if (!hostcode.empty()) + text.AppendFmtString("Host Code: {}", hostcode); const float scale = ImGuiManager::GetGlobalScale(); const float shadow_offset = 1.0f * scale;