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();