From 07e258fd58bc79b744fc7e2476bd713828198e47 Mon Sep 17 00:00:00 2001 From: Nora Date: Tue, 1 Mar 2022 14:18:11 -0500 Subject: [PATCH] Fix Netplay Traversal Error --- Source/Core/DolphinQt/MainWindow.cpp | 103 ++++++++++++++++++ Source/Core/DolphinQt/MainWindow.h | 1 + .../DolphinQt/NetPlay/NetPlaySetupDialog.cpp | 13 +-- 3 files changed, 110 insertions(+), 7 deletions(-) diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 321f9501d4..f33a77c6b1 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -944,6 +944,109 @@ bool MainWindow::RequestStop() return true; } +bool MainWindow::RequestStopNetplay() +{ + if (!Core::IsRunning()) + { + Core::QueueHostJob([this] { OnStopComplete(); }, true); + return true; + } + + const bool rendered_widget_was_active = + m_render_widget->isActiveWindow() && !m_render_widget->isFullScreen(); + QWidget* confirm_parent = (!m_rendering_to_main && rendered_widget_was_active) ? + m_render_widget : + static_cast(this); + const bool was_cursor_locked = m_render_widget->IsCursorLocked(); + + if (!m_render_widget->isFullScreen()) + m_render_widget_geometry = m_render_widget->saveGeometry(); + else + FullScreen(); + + if (Config::Get(Config::MAIN_CONFIRM_ON_STOP)) + { + if (std::exchange(m_stop_confirm_showing, true)) + return true; + + Common::ScopeGuard confirm_lock([this] { m_stop_confirm_showing = false; }); + + const Core::State state = Core::GetState(); + + // Only pause the game, if NetPlay is not running + bool pause = !Settings::Instance().GetNetPlayClient(); + + if (pause) + Core::SetState(Core::State::Paused); + + if (rendered_widget_was_active) + { + // We have to do this before creating the message box, otherwise we might receive the window + // activation event before we know we need to lock the cursor again. + m_render_widget->SetCursorLockedOnNextActivation(was_cursor_locked); + } + + // This is to avoid any "race conditions" between the "Window Activate" message and the + // message box returning, which could break cursor locking depending on the order + m_render_widget->SetWaitingForMessageBox(true); + auto confirm = ModalMessageBox::question( + confirm_parent, tr("Confirm"), + m_stop_requested ? tr("A user disconnected from the netplay lobby" + "Netplay session has ended due to someone crashing" + "before NetPlay complete." + "All players control Player 1 and have been seperated") : + tr("Do you want to stop the current emulation?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton, Qt::ApplicationModal); + + // If a user confirmed stopping the emulation, we do not capture the cursor again, + // even if the render widget will stay alive for a while. + // If a used rejected stopping the emulation, we instead capture the cursor again, + // and let them continue playing as if nothing had happened + // (assuming cursor locking is on). + if (confirm != QMessageBox::Yes) + { + m_render_widget->SetWaitingForMessageBox(false); + + if (pause) + Core::SetState(state); + + return false; + } + else + { + m_render_widget->SetCursorLockedOnNextActivation(false); + // This needs to be after SetCursorLockedOnNextActivation(false) as it depends on it + m_render_widget->SetWaitingForMessageBox(false); + } + } + + OnStopRecording(); + // TODO: Add Debugger shutdown + + if (!m_stop_requested && UICommon::TriggerSTMPowerEvent()) + { + m_stop_requested = true; + + // Unpause because gracefully shutting down needs the game to actually request a shutdown. + // TODO: Do not unpause in debug mode to allow debugging until the complete shutdown. + if (Core::GetState() == Core::State::Paused) + Core::SetState(Core::State::Running); + + // Tell NetPlay about the power event + if (NetPlay::IsNetPlayRunning()) + NetPlay::SendPowerButtonEvent(); + + return true; + } + + ForceStop(); +#ifdef Q_OS_WIN + // Allow windows to idle or turn off display again + SetThreadExecutionState(ES_CONTINUOUS); +#endif + return true; +} + void MainWindow::ForceStop() { Core::Stop(); diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index 6e53f2df10..d81b25baa3 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -87,6 +87,7 @@ private: // May ask for confirmation. Returns whether or not it actually stopped. bool RequestStop(); + bool RequestStopNetplay(); void ForceStop(); void Reset(); void FrameAdvance(); diff --git a/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp index d0af4c0e1c..e7fb9e5cc3 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp +++ b/Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp @@ -507,12 +507,11 @@ void NetPlaySetupDialog::UpdateListBrowser() }); auto* hor_header = m_table_widget->horizontalHeader(); - hor_header->setSectionResizeMode(0, QHeaderView::Stretch); hor_header->setSectionResizeMode(1, QHeaderView::Stretch); - hor_header->setSectionResizeMode(2, QHeaderView::Stretch); + hor_header->setSectionResizeMode(2, QHeaderView::ResizeToContents); hor_header->setSectionResizeMode(3, QHeaderView::ResizeToContents); - hor_header->setSectionResizeMode(4, QHeaderView::ResizeToContents); + hor_header->setHighlightSections(false); m_table_widget->setRowCount(session_count); @@ -531,10 +530,10 @@ void NetPlaySetupDialog::UpdateListBrowser() for (const auto& item : {name, game_id, player_count, in_game}) item->setFlags(enabled ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags); - m_table_widget->setItem(i, 1, name); - m_table_widget->setItem(i, 2, game_id); - m_table_widget->setItem(i, 3, player_count); - m_table_widget->setItem(i, 4, in_game); + m_table_widget->setItem(i, 0, name); + m_table_widget->setItem(i, 1, game_id); + m_table_widget->setItem(i, 2, player_count); + m_table_widget->setItem(i, 3, in_game); }