forked from mirrors/0ad
+7
-2
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "lib/timer.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "maths/Size2D.h"
|
||||
#include "network/NetClient.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Errors.h"
|
||||
#include "ps/Filesystem.h"
|
||||
@@ -104,7 +105,11 @@ CGUI::CGUI(ScriptContext& context)
|
||||
m_ScriptInterface->LoadGlobalScripts();
|
||||
}
|
||||
|
||||
CGUI::~CGUI() = default;
|
||||
CGUI::~CGUI()
|
||||
{
|
||||
if (g_NetClient)
|
||||
g_NetClient->Unregister(*m_ScriptInterface);
|
||||
}
|
||||
|
||||
InReaction CGUI::HandleEvent(const SDL_Event_* ev)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "ps/Profile.h"
|
||||
#include "ps/Threading.h"
|
||||
#include "scriptinterface/JSON.h"
|
||||
#include "scriptinterface/ScriptContext.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/system/TurnManager.h"
|
||||
@@ -49,6 +50,7 @@
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <js/GCAPI.h>
|
||||
#include <js/Promise.h>
|
||||
#include <js/TracingAPI.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -323,6 +325,7 @@ void CNetClient::Poll()
|
||||
|
||||
CheckServerConnection();
|
||||
m_Session->ProcessPolledMessages();
|
||||
FetchMessage();
|
||||
}
|
||||
|
||||
void CNetClient::CheckServerConnection()
|
||||
@@ -357,15 +360,35 @@ void CNetClient::CheckServerConnection()
|
||||
}
|
||||
}
|
||||
|
||||
JS::Value CNetClient::GuiPoll(const ScriptRequest& rq)
|
||||
JSObject* CNetClient::GetNextGUIMessage(const ScriptInterface& guiInterface)
|
||||
{
|
||||
if (m_GuiMessageQueue.empty())
|
||||
return JS::UndefinedValue();
|
||||
const ScriptRequest rq{guiInterface};
|
||||
m_GuiMessagePoll.emplace(GuiPollData{guiInterface, {rq.cx, JS::NewPromiseObject(rq.cx, nullptr)}});
|
||||
|
||||
JS::RootedValue ret{rq.cx};
|
||||
Script::ReadStructuredClone(rq, m_GuiMessageQueue.front(), &ret);
|
||||
FetchMessage();
|
||||
return m_GuiMessagePoll.value().promise;
|
||||
}
|
||||
|
||||
void CNetClient::Unregister(const ScriptInterface& guiInterface)
|
||||
{
|
||||
if (m_GuiMessagePoll.has_value() && &m_GuiMessagePoll.value().interface == &guiInterface)
|
||||
m_GuiMessagePoll.reset();
|
||||
}
|
||||
|
||||
void CNetClient::FetchMessage()
|
||||
{
|
||||
if (m_GuiMessageQueue.empty() || !m_GuiMessagePoll.has_value() ||
|
||||
JS::GetPromiseState(m_GuiMessagePoll.value().promise) != JS::PromiseState::Pending)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const ScriptRequest rq{m_GuiMessagePoll.value().interface};
|
||||
JS::RootedValue message{rq.cx};
|
||||
Script::ReadStructuredClone(rq, std::move(m_GuiMessageQueue.front()), &message);
|
||||
m_GuiMessageQueue.pop_front();
|
||||
return ret;
|
||||
|
||||
JS::ResolvePromise(rq.cx, m_GuiMessagePoll.value().promise, message);
|
||||
}
|
||||
|
||||
std::string CNetClient::TestReadGuiMessages()
|
||||
@@ -375,9 +398,13 @@ std::string CNetClient::TestReadGuiMessages()
|
||||
std::string r;
|
||||
while (true)
|
||||
{
|
||||
JS::RootedValue msg{rq.cx, GuiPoll(rq)};
|
||||
if (msg.isUndefined())
|
||||
JS::RootedObject promise{rq.cx, GetNextGUIMessage(GetScriptInterface())};
|
||||
g_ScriptContext->RunJobs();
|
||||
|
||||
if (JS::GetPromiseState(promise) == JS::PromiseState::Pending)
|
||||
break;
|
||||
|
||||
JS::RootedValue msg{rq.cx, JS::GetPromiseResult(promise)};
|
||||
r += Script::ToString(rq, &msg) + "\n";
|
||||
}
|
||||
return r;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -144,19 +144,25 @@ public:
|
||||
|
||||
/**
|
||||
* Retrieves the next queued GUI message, and removes it from the queue.
|
||||
* The returned value is in the GetScriptInterface() JS context.
|
||||
* The returned value is in the JS context of the provided
|
||||
* @c ScriptInterface.
|
||||
*
|
||||
* This is the only mechanism for the networking code to send messages to
|
||||
* the GUI - it is pull-based (instead of push) so the engine code does not
|
||||
* need to know anything about the code structure of the GUI scripts.
|
||||
* the GUI.
|
||||
*
|
||||
* The structure of the messages is <code>{ "type": "...", ... }</code>.
|
||||
* The exact types and associated data are not specified anywhere - the
|
||||
* implementation and GUI scripts must make the same assumptions.
|
||||
*
|
||||
* @return next message, or the value 'undefined' if the queue is empty
|
||||
* @return a promise resolving to the next message.
|
||||
*/
|
||||
JS::Value GuiPoll(const ScriptRequest& rq);
|
||||
JSObject* GetNextGUIMessage(const ScriptInterface& guiInterface);
|
||||
|
||||
/**
|
||||
* Has to be called bevore the @c ScriptInterface gets destroied so that
|
||||
* no future messages are sent to it.
|
||||
*/
|
||||
void Unregister(const ScriptInterface& guiInterface);
|
||||
|
||||
/**
|
||||
* Add a message to the queue, to be read by GuiPoll.
|
||||
@@ -305,6 +311,8 @@ private:
|
||||
*/
|
||||
void PostPlayerAssignmentsToScript();
|
||||
|
||||
void FetchMessage();
|
||||
|
||||
CGame *m_Game;
|
||||
CStrW m_UserName;
|
||||
|
||||
@@ -346,6 +354,18 @@ private:
|
||||
/// Queue of messages for GuiPoll
|
||||
std::deque<Script::StructuredClone> m_GuiMessageQueue;
|
||||
|
||||
struct GuiPollData
|
||||
{
|
||||
const ScriptInterface& interface;
|
||||
/**
|
||||
* In the context of interface.
|
||||
* When the promise is pending @see Poll should fill it with a message.
|
||||
* When there it's fulfilled JavaScript code can take it.
|
||||
*/
|
||||
JS::PersistentRootedObject promise;
|
||||
};
|
||||
std::optional<GuiPollData> m_GuiMessagePoll;
|
||||
|
||||
/// Serialized game state received when joining an in-progress game
|
||||
std::string m_JoinSyncBuffer;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -196,9 +196,12 @@ CStr GetPlayerGUID()
|
||||
return g_NetClient->GetGUID();
|
||||
}
|
||||
|
||||
JS::Value PollNetworkClient(const ScriptRequest& rq)
|
||||
JS::Value PollNetworkClient(const ScriptInterface& guiInterface)
|
||||
{
|
||||
return g_NetClient ? g_NetClient->GuiPoll(rq) : JS::UndefinedValue();
|
||||
if (!g_NetClient)
|
||||
throw std::logic_error{"Network client not present"};
|
||||
|
||||
return JS::ObjectValue(*g_NetClient->GetNextGUIMessage(guiInterface));
|
||||
}
|
||||
|
||||
void SendGameSetupMessage(const ScriptInterface& scriptInterface, JS::HandleValue attribs1)
|
||||
|
||||
@@ -855,6 +855,7 @@ bool Autostart(const CmdLineArgs& args)
|
||||
while (!shouldQuit)
|
||||
{
|
||||
g_NetClient->Poll();
|
||||
g_ScriptContext->RunJobs();
|
||||
if (!ScriptFunction::Call(rq, global, "onTick", shouldQuit))
|
||||
return false;
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||
|
||||
Reference in New Issue
Block a user