1
0
forked from mirrors/0ad

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.
This commit is contained in:
phosit
2026-03-03 19:09:17 +01:00
parent 578aea3b09
commit 314e2a58cf
3 changed files with 26 additions and 52 deletions
+16 -31
View File
@@ -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<RunThread>::Wrapper, this);
m_WorkerThread = std::thread{Threading::HandleExceptions<RunThread>::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<bool> newStartGame;
std::vector<std::string> newGameAttributes;
std::vector<std::pair<CStr, CStr>> newLobbyAuths;
std::vector<u32> 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<std::mutex> lock(m_Worker->m_WorkerMutex);
m_Worker->m_InitAttributesQueue.push_back(attrsJSON);
}
void CNetServer::OnLobbyAuth(const CStr& name, const CStr& token)
{
std::lock_guard<std::mutex> lock(m_Worker->m_WorkerMutex);
+5 -13
View File
@@ -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<bool> m_StartGameQueue;
std::vector<std::string> m_InitAttributesQueue;
std::vector<std::pair<CStr, CStr>> m_LobbyAuthQueue;
std::vector<u32> m_TurnLengthQueue;
};
+5 -8
View File
@@ -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<CNetClient*>& clients)
void connect(CNetServer& server, const std::vector<CNetClient*>& 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();