From 314e2a58cf2bfa200ff2d208d7e66b4e404196e3 Mon Sep 17 00:00:00 2001 From: phosit Date: Tue, 3 Mar 2026 19:09:17 +0100 Subject: [PATCH] Remove UpdateInitAttributes from CNetClient The init-attributes can only be changed before the worker runs. It isn't used before the worker runs. This changes it so that it has to be passed when the server starts. With this the `m_InitAttributesQueue` can be removed. --- source/network/NetServer.cpp | 47 +++++++++++---------------------- source/network/NetServer.h | 18 ++++--------- source/network/tests/test_Net.h | 13 ++++----- 3 files changed, 26 insertions(+), 52 deletions(-) diff --git a/source/network/NetServer.cpp b/source/network/NetServer.cpp index addc0ade0e..951d93ad2f 100644 --- a/source/network/NetServer.cpp +++ b/source/network/NetServer.cpp @@ -162,7 +162,7 @@ bool CNetServerWorker::CheckPassword(const std::string& password, const std::str } -bool CNetServerWorker::SetupConnection(const u16 port) +bool CNetServerWorker::SetupConnection(const u16 port, std::string initAttributes) { ENSURE(m_State == SERVER_STATE_UNCONNECTED); ENSURE(!m_Host); @@ -187,7 +187,8 @@ bool CNetServerWorker::SetupConnection(const u16 port) m_State = SERVER_STATE_PREGAME; // Launch the worker thread - m_WorkerThread = std::thread(Threading::HandleExceptions::Wrapper, this); + m_WorkerThread = std::thread{Threading::HandleExceptions::Wrapper, this, + std::move(initAttributes)}; #if CONFIG2_MINIUPNPC // Launch the UPnP thread @@ -383,14 +384,14 @@ bool CNetServerWorker::Multicast(const CNetMessage* message, return ok; } -void CNetServerWorker::RunThread(CNetServerWorker* data) +void CNetServerWorker::RunThread(CNetServerWorker* data, const std::string& initAttributes) { debug_SetThreadName("NetServer"); - data->Run(); + data->Run(initAttributes); } -void CNetServerWorker::Run() +void CNetServerWorker::Run(const std::string& initAttributes) { // The script context uses the profiler and therefore the thread must be registered before the context is created g_Profiler2.RegisterCurrentThread("Net server"); @@ -400,6 +401,14 @@ void CNetServerWorker::Run() m_ScriptInterface = new ScriptInterface("Engine", "Net server", netServerContext); m_InitAttributes.init(m_ScriptInterface->GetGeneralJSContext(), JS::UndefinedValue()); + if (!initAttributes.empty()) + { + ScriptRequest rq(m_ScriptInterface); + JS::RootedValue gameAttributesVal(rq.cx); + Script::ParseJSON(rq, std::move(initAttributes), &gameAttributesVal); + m_InitAttributes = gameAttributesVal; + } + while (true) { if (!RunStep()) @@ -426,7 +435,6 @@ bool CNetServerWorker::RunStep() ScriptRequest rq(m_ScriptInterface); std::vector newStartGame; - std::vector newGameAttributes; std::vector> newLobbyAuths; std::vector newTurnLength; @@ -437,23 +445,10 @@ bool CNetServerWorker::RunStep() return false; newStartGame.swap(m_StartGameQueue); - newGameAttributes.swap(m_InitAttributesQueue); newLobbyAuths.swap(m_LobbyAuthQueue); newTurnLength.swap(m_TurnLengthQueue); } - if (!newGameAttributes.empty()) - { - if (m_State != SERVER_STATE_UNCONNECTED && m_State != SERVER_STATE_PREGAME) - LOGERROR("NetServer: Init Attributes cannot be changed after the server starts loading."); - else - { - JS::RootedValue gameAttributesVal(rq.cx); - Script::ParseJSON(rq, newGameAttributes.back(), &gameAttributesVal); - m_InitAttributes = gameAttributesVal; - } - } - if (!newTurnLength.empty()) SetTurnLength(newTurnLength.back()); @@ -1703,9 +1698,9 @@ bool CNetServer::UseLobbyAuth() const return m_LobbyAuth; } -bool CNetServer::SetupConnection(const u16 port) +bool CNetServer::SetupConnection(const u16 port, std::string initAttributes) { - return m_Worker->SetupConnection(port); + return m_Worker->SetupConnection(port, std::move(initAttributes)); } CStr CNetServer::GetPublicIp() const @@ -1762,16 +1757,6 @@ void CNetServer::StartGame() m_Worker->m_StartGameQueue.push_back(true); } -void CNetServer::UpdateInitAttributes(JS::MutableHandleValue attrs, const ScriptRequest& rq) -{ - // Pass the attributes as JSON, since that's the easiest safe - // cross-thread way of passing script data - std::string attrsJSON = Script::StringifyJSON(rq, attrs, false); - - std::lock_guard lock(m_Worker->m_WorkerMutex); - m_Worker->m_InitAttributesQueue.push_back(attrsJSON); -} - void CNetServer::OnLobbyAuth(const CStr& name, const CStr& token) { std::lock_guard lock(m_Worker->m_WorkerMutex); diff --git a/source/network/NetServer.h b/source/network/NetServer.h index 1973daf322..dd8db09d83 100644 --- a/source/network/NetServer.h +++ b/source/network/NetServer.h @@ -121,21 +121,14 @@ public: * This function is synchronous (it won't return until the connection is established). * @return true on success, false on error (e.g. port already in use) */ - bool SetupConnection(const u16 port); + bool SetupConnection(const u16 port, std::string initAttributes = {}); /** * Call from the GUI to asynchronously notify all clients that they should start loading the game. - * UpdateInitAttributes must be called at least once. + * SetupConnection must be called at least once. */ void StartGame(); - /** - * Call from the GUI to update the game setup attributes. - * The changes won't be propagated to clients until game start. - * @param attrs init attributes, in the script context of rq - */ - void UpdateInitAttributes(JS::MutableHandleValue attrs, const ScriptRequest& rq); - /** * Set the turn length to a fixed value. * TODO: we should replace this with some adapative lag-dependent computation. @@ -237,7 +230,7 @@ private: * Begin listening for network connections. * @return true on success, false on error (e.g. port already in use) */ - bool SetupConnection(const u16 port); + bool SetupConnection(const u16 port, std::string initAttributes); /** * The given GUID will be (re)assigned to the given player ID. @@ -428,8 +421,8 @@ private: std::thread m_UPnPThread; #endif - static void RunThread(CNetServerWorker* data); - void Run(); + static void RunThread(CNetServerWorker* data, const std::string& initAttributes); + void Run(const std::string& initAttributes); bool RunStep(); std::thread m_WorkerThread; @@ -440,7 +433,6 @@ private: // Queues for messages sent by the game thread (protected by m_WorkerMutex): std::vector m_StartGameQueue; - std::vector m_InitAttributesQueue; std::vector> m_LobbyAuthQueue; std::vector m_TurnLengthQueue; }; diff --git a/source/network/tests/test_Net.h b/source/network/tests/test_Net.h index 0fc8956b41..b593b10a55 100644 --- a/source/network/tests/test_Net.h +++ b/source/network/tests/test_Net.h @@ -33,6 +33,7 @@ #include "ps/Game.h" #include "ps/Loader.h" #include "ps/XML/Xeromyces.h" +#include "scriptinterface/JSON.h" #include "scriptinterface/Object.h" #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptRequest.h" @@ -87,9 +88,9 @@ public: return true; } - void connect(CNetServer& server, const std::vector& clients) + void connect(CNetServer& server, const std::vector& clients, std::string initAttributes) { - TS_ASSERT(server.SetupConnection(PS_DEFAULT_PORT)); + TS_ASSERT(server.SetupConnection(PS_DEFAULT_PORT, std::move(initAttributes))); for (CNetClient* client: clients) { TS_ASSERT(client->SetupConnection(nullptr)); @@ -179,8 +180,6 @@ public: "mapPath", "maps/scenarios/", "thing", "example"); - server.UpdateInitAttributes(&attrs, scriptInterface); - CNetClient client1(&client1Game, "127.0.0.1", PS_DEFAULT_PORT); CNetClient client2(&client2Game, "127.0.0.1", PS_DEFAULT_PORT); CNetClient client3(&client3Game, "127.0.0.1", PS_DEFAULT_PORT); @@ -189,7 +188,7 @@ public: clients.push_back(&client2); clients.push_back(&client3); - connect(server, clients); + connect(server, clients, Script::StringifyJSON(rq, &attrs, false)); debug_printf("%s", client1.TestReadGuiMessages().c_str()); server.StartGame(); @@ -258,8 +257,6 @@ public: "mapPath", "maps/scenarios/", "thing", "example"); - server.UpdateInitAttributes(&attrs, scriptInterface); - CNetClient client1(&client1Game, "127.0.0.1", PS_DEFAULT_PORT, L"alice"); CNetClient client2(&client2Game, "127.0.0.1", PS_DEFAULT_PORT, L"bob"); CNetClient client3(&client3Game, "127.0.0.1", PS_DEFAULT_PORT, L"charlie"); @@ -268,7 +265,7 @@ public: clients.push_back(&client2); clients.push_back(&client3); - connect(server, clients); + connect(server, clients, Script::StringifyJSON(rq, &attrs, false)); debug_printf("%s", client1.TestReadGuiMessages().c_str()); server.StartGame();