1
0
forked from 0ad/0ad

Split off StructuredClone from ScriptInterface

Follows 34b1920e7b.

This separates StructuredClone & DeepCopy logic into its own header,
reducing the size of the monolithic ScriptInterface header.

Differential Revision: https://code.wildfiregames.com/D3922
This was SVN commit r25419.
This commit is contained in:
wraitii 2021-05-10 11:51:32 +00:00
parent ad62707eef
commit 6fbf036ae4
29 changed files with 266 additions and 180 deletions

View File

@ -225,7 +225,7 @@ double CMapGeneratorWorker::GetMicroseconds()
return JS_Now(); return JS_Now();
} }
ScriptInterface::StructuredClone CMapGeneratorWorker::GetResults() Script::StructuredClone CMapGeneratorWorker::GetResults()
{ {
std::lock_guard<std::mutex> lock(m_WorkerMutex); std::lock_guard<std::mutex> lock(m_WorkerMutex);
return m_MapData; return m_MapData;
@ -235,7 +235,7 @@ void CMapGeneratorWorker::ExportMap(JS::HandleValue data)
{ {
// Copy results // Copy results
std::lock_guard<std::mutex> lock(m_WorkerMutex); std::lock_guard<std::mutex> lock(m_WorkerMutex);
m_MapData = m_ScriptInterface->WriteStructuredClone(data); m_MapData = Script::WriteStructuredClone(ScriptRequest(m_ScriptInterface), data);
m_Progress = 0; m_Progress = 0;
} }
@ -422,7 +422,7 @@ int CMapGenerator::GetProgress()
return m_Worker->GetProgress(); return m_Worker->GetProgress();
} }
ScriptInterface::StructuredClone CMapGenerator::GetResults() Script::StructuredClone CMapGenerator::GetResults()
{ {
return m_Worker->GetResults(); return m_Worker->GetResults();
} }

View File

@ -21,7 +21,7 @@
#include "lib/posix/posix_pthread.h" #include "lib/posix/posix_pthread.h"
#include "ps/FileIo.h" #include "ps/FileIo.h"
#include "ps/TemplateLoader.h" #include "ps/TemplateLoader.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
#include <boost/random/linear_congruential.hpp> #include <boost/random/linear_congruential.hpp>
@ -67,7 +67,7 @@ public:
* *
* @return StructuredClone containing map data * @return StructuredClone containing map data
*/ */
ScriptInterface::StructuredClone GetResults(); Script::StructuredClone GetResults();
private: private:
CMapGeneratorWorker* m_Worker; CMapGeneratorWorker* m_Worker;
@ -110,7 +110,7 @@ public:
* *
* @return StructuredClone containing map data * @return StructuredClone containing map data
*/ */
ScriptInterface::StructuredClone GetResults(); Script::StructuredClone GetResults();
/** /**
* Set initial seed, callback data. * Set initial seed, callback data.
@ -196,7 +196,7 @@ private:
/** /**
* Result of the mapscript generation including terrain, entities and environment settings. * Result of the mapscript generation including terrain, entities and environment settings.
*/ */
ScriptInterface::StructuredClone m_MapData; Script::StructuredClone m_MapData;
/** /**
* Deterministic random number generator. * Deterministic random number generator.

View File

@ -40,6 +40,7 @@
#include "renderer/SkyManager.h" #include "renderer/SkyManager.h"
#include "renderer/WaterManager.h" #include "renderer/WaterManager.h"
#include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptContext.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpCinemaManager.h" #include "simulation2/components/ICmpCinemaManager.h"
#include "simulation2/components/ICmpGarrisonHolder.h" #include "simulation2/components/ICmpGarrisonHolder.h"
@ -1294,11 +1295,11 @@ int CMapReader::GenerateMap()
else if (progress == 0) else if (progress == 0)
{ {
// Finished, get results as StructuredClone object, which must be read to obtain the JS::Value // Finished, get results as StructuredClone object, which must be read to obtain the JS::Value
ScriptInterface::StructuredClone results = m_MapGen->GetResults(); Script::StructuredClone results = m_MapGen->GetResults();
// Parse data into simulation context // Parse data into simulation context
JS::RootedValue data(rq.cx); JS::RootedValue data(rq.cx);
pSimulation2->GetScriptInterface().ReadStructuredClone(results, &data); Script::ReadStructuredClone(rq, results, &data);
if (data.isUndefined()) if (data.isUndefined())
{ {

View File

@ -29,6 +29,7 @@
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptContext.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/StructuredClone.h"
CGUIManager* g_GUI = nullptr; CGUIManager* g_GUI = nullptr;
@ -88,17 +89,18 @@ void CGUIManager::SwitchPage(const CStrW& pageName, ScriptInterface* srcScriptIn
{ {
// The page stack is cleared (including the script context where initData came from), // The page stack is cleared (including the script context where initData came from),
// therefore we have to clone initData. // therefore we have to clone initData.
ScriptRequest rq(srcScriptInterface);
ScriptInterface::StructuredClone initDataClone; Script::StructuredClone initDataClone;
if (!initData.isUndefined()) if (!initData.isUndefined())
initDataClone = srcScriptInterface->WriteStructuredClone(initData); initDataClone = Script::WriteStructuredClone(rq, initData);
m_PageStack.clear(); m_PageStack.clear();
PushPage(pageName, initDataClone, JS::UndefinedHandleValue); PushPage(pageName, initDataClone, JS::UndefinedHandleValue);
} }
void CGUIManager::PushPage(const CStrW& pageName, ScriptInterface::StructuredClone initData, JS::HandleValue callbackFunction) void CGUIManager::PushPage(const CStrW& pageName, Script::StructuredClone initData, JS::HandleValue callbackFunction)
{ {
// Store the callback handler in the current GUI page before opening the new one // Store the callback handler in the current GUI page before opening the new one
if (!m_PageStack.empty() && !callbackFunction.isUndefined()) if (!m_PageStack.empty() && !callbackFunction.isUndefined())
@ -110,7 +112,7 @@ void CGUIManager::PushPage(const CStrW& pageName, ScriptInterface::StructuredClo
m_PageStack.back().LoadPage(m_ScriptContext); m_PageStack.back().LoadPage(m_ScriptContext);
} }
void CGUIManager::PopPage(ScriptInterface::StructuredClone args) void CGUIManager::PopPage(Script::StructuredClone args)
{ {
if (m_PageStack.size() < 2) if (m_PageStack.size() < 2)
{ {
@ -122,7 +124,7 @@ void CGUIManager::PopPage(ScriptInterface::StructuredClone args)
m_PageStack.back().PerformCallbackFunction(args); m_PageStack.back().PerformCallbackFunction(args);
} }
CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const ScriptInterface::StructuredClone initData) CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const Script::StructuredClone initData)
: m_Name(pageName), initData(initData), inputs(), gui(), callbackFunction() : m_Name(pageName), initData(initData), inputs(), gui(), callbackFunction()
{ {
} }
@ -130,7 +132,7 @@ CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const ScriptInterface::St
void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptContext> scriptContext) void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptContext> scriptContext)
{ {
// If we're hotloading then try to grab some data from the previous page // If we're hotloading then try to grab some data from the previous page
ScriptInterface::StructuredClone hotloadData; Script::StructuredClone hotloadData;
if (gui) if (gui)
{ {
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface(); shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
@ -139,7 +141,7 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptContext> scriptContext)
JS::RootedValue global(rq.cx, rq.globalValue()); JS::RootedValue global(rq.cx, rq.globalValue());
JS::RootedValue hotloadDataVal(rq.cx); JS::RootedValue hotloadDataVal(rq.cx);
ScriptFunction::Call(rq, global, "getHotloadData", &hotloadDataVal); ScriptFunction::Call(rq, global, "getHotloadData", &hotloadDataVal);
hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal); hotloadData = Script::WriteStructuredClone(rq, hotloadDataVal);
} }
g_CursorName = g_DefaultCursor; g_CursorName = g_DefaultCursor;
@ -207,10 +209,10 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptContext> scriptContext)
JS::RootedValue global(rq.cx, rq.globalValue()); JS::RootedValue global(rq.cx, rq.globalValue());
if (initData) if (initData)
scriptInterface->ReadStructuredClone(initData, &initDataVal); Script::ReadStructuredClone(rq, initData, &initDataVal);
if (hotloadData) if (hotloadData)
scriptInterface->ReadStructuredClone(hotloadData, &hotloadDataVal); Script::ReadStructuredClone(rq, hotloadData, &hotloadDataVal);
if (scriptInterface->HasProperty(global, "init") && if (scriptInterface->HasProperty(global, "init") &&
!ScriptFunction::CallVoid(rq, global, "init", initDataVal, hotloadDataVal)) !ScriptFunction::CallVoid(rq, global, "init", initDataVal, hotloadDataVal))
@ -236,7 +238,7 @@ void CGUIManager::SGUIPage::SetCallbackFunction(ScriptInterface& scriptInterface
callbackFunction = std::make_shared<JS::PersistentRootedValue>(scriptInterface.GetGeneralJSContext(), callbackFunc); callbackFunction = std::make_shared<JS::PersistentRootedValue>(scriptInterface.GetGeneralJSContext(), callbackFunc);
} }
void CGUIManager::SGUIPage::PerformCallbackFunction(ScriptInterface::StructuredClone args) void CGUIManager::SGUIPage::PerformCallbackFunction(Script::StructuredClone args)
{ {
if (!callbackFunction) if (!callbackFunction)
return; return;
@ -253,7 +255,7 @@ void CGUIManager::SGUIPage::PerformCallbackFunction(ScriptInterface::StructuredC
JS::RootedValue argVal(rq.cx); JS::RootedValue argVal(rq.cx);
if (args) if (args)
scriptInterface->ReadStructuredClone(args, &argVal); Script::ReadStructuredClone(rq, args, &argVal);
JS::RootedValueVector paramData(rq.cx); JS::RootedValueVector paramData(rq.cx);
ignore_result(paramData.append(argVal)); ignore_result(paramData.append(argVal));

View File

@ -22,7 +22,7 @@
#include "lib/input.h" #include "lib/input.h"
#include "ps/CStr.h" #include "ps/CStr.h"
#include "ps/TemplateLoader.h" #include "ps/TemplateLoader.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
@ -68,13 +68,13 @@ public:
* user inputs. * user inputs.
* If given, the callbackHandler function will be executed once this page is closed. * If given, the callbackHandler function will be executed once this page is closed.
*/ */
void PushPage(const CStrW& pageName, ScriptInterface::StructuredClone initData, JS::HandleValue callbackFunc); void PushPage(const CStrW& pageName, Script::StructuredClone initData, JS::HandleValue callbackFunc);
/** /**
* Unload the currently active GUI page, and make the previous page active. * Unload the currently active GUI page, and make the previous page active.
* (There must be at least two pages when you call this.) * (There must be at least two pages when you call this.)
*/ */
void PopPage(ScriptInterface::StructuredClone args); void PopPage(Script::StructuredClone args);
/** /**
* Called when a file has been modified, to hotload changes. * Called when a file has been modified, to hotload changes.
@ -131,7 +131,7 @@ private:
/** /**
* Initializes the data that will be used to create the CGUI page one or multiple times (hotloading). * Initializes the data that will be used to create the CGUI page one or multiple times (hotloading).
*/ */
SGUIPage(const CStrW& pageName, const ScriptInterface::StructuredClone initData); SGUIPage(const CStrW& pageName, const Script::StructuredClone initData);
/** /**
* Create the CGUI with it's own ScriptInterface. Deletes the previous CGUI if it existed. * Create the CGUI with it's own ScriptInterface. Deletes the previous CGUI if it existed.
@ -146,11 +146,11 @@ private:
/** /**
* Execute the stored callback function with the given arguments. * Execute the stored callback function with the given arguments.
*/ */
void PerformCallbackFunction(ScriptInterface::StructuredClone args); void PerformCallbackFunction(Script::StructuredClone args);
CStrW m_Name; CStrW m_Name;
std::unordered_set<VfsPath> inputs; // for hotloading std::unordered_set<VfsPath> inputs; // for hotloading
ScriptInterface::StructuredClone initData; // data to be passed to the init() function Script::StructuredClone initData; // data to be passed to the init() function
shared_ptr<CGUI> gui; // the actual GUI page shared_ptr<CGUI> gui; // the actual GUI page
/** /**

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games. /* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -24,15 +24,15 @@
#include "gui/ObjectBases/IGUIObject.h" #include "gui/ObjectBases/IGUIObject.h"
#include "ps/GameSetup/Config.h" #include "ps/GameSetup/Config.h"
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
namespace JSI_GUIManager namespace JSI_GUIManager
{ {
// Note that the initData argument may only contain clonable data. // Note that the initData argument may only contain clonable data.
// Functions aren't supported for example! // Functions aren't supported for example!
void PushGuiPage(const ScriptInterface& scriptInterface, const std::wstring& name, JS::HandleValue initData, JS::HandleValue callbackFunction) void PushGuiPage(const ScriptRequest& rq, const std::wstring& name, JS::HandleValue initData, JS::HandleValue callbackFunction)
{ {
g_GUI->PushPage(name, scriptInterface.WriteStructuredClone(initData), callbackFunction); g_GUI->PushPage(name, Script::WriteStructuredClone(rq, initData), callbackFunction);
} }
void SwitchGuiPage(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstring& name, JS::HandleValue initData) void SwitchGuiPage(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstring& name, JS::HandleValue initData)
@ -40,16 +40,15 @@ void SwitchGuiPage(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstrin
g_GUI->SwitchPage(name, pCmptPrivate->pScriptInterface, initData); g_GUI->SwitchPage(name, pCmptPrivate->pScriptInterface, initData);
} }
void PopGuiPage(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleValue args) void PopGuiPage(const ScriptRequest& rq, JS::HandleValue args)
{ {
if (g_GUI->GetPageCount() < 2) if (g_GUI->GetPageCount() < 2)
{ {
ScriptRequest rq(pCmptPrivate->pScriptInterface);
ScriptException::Raise(rq, "Can't pop GUI pages when less than two pages are opened!"); ScriptException::Raise(rq, "Can't pop GUI pages when less than two pages are opened!");
return; return;
} }
g_GUI->PopPage(pCmptPrivate->pScriptInterface->WriteStructuredClone(args)); g_GUI->PopPage(Script::WriteStructuredClone(rq, args));
} }
std::wstring SetCursor(const std::wstring& name) std::wstring SetCursor(const std::wstring& name)

View File

@ -25,6 +25,7 @@
#include "ps/GameSetup/GameSetup.h" #include "ps/GameSetup/GameSetup.h"
#include "ps/Hotkey.h" #include "ps/Hotkey.h"
#include "ps/XML/Xeromyces.h" #include "ps/XML/Xeromyces.h"
#include "scriptinterface/StructuredClone.h"
#include <memory> #include <memory>
@ -63,7 +64,7 @@ public:
JS::RootedValue val(rq.cx); JS::RootedValue val(rq.cx);
scriptInterface.CreateObject(rq, &val); scriptInterface.CreateObject(rq, &val);
ScriptInterface::StructuredClone data = scriptInterface.WriteStructuredClone(JS::NullHandleValue); Script::StructuredClone data = Script::WriteStructuredClone(rq, JS::NullHandleValue);
g_GUI->PushPage(L"event/page_event.xml", data, JS::UndefinedHandleValue); g_GUI->PushPage(L"event/page_event.xml", data, JS::UndefinedHandleValue);
const ScriptInterface& pageScriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface()); const ScriptInterface& pageScriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface());
@ -127,7 +128,7 @@ public:
JS::RootedValue val(rq.cx); JS::RootedValue val(rq.cx);
scriptInterface.CreateObject(rq, &val); scriptInterface.CreateObject(rq, &val);
ScriptInterface::StructuredClone data = scriptInterface.WriteStructuredClone(JS::NullHandleValue); Script::StructuredClone data = Script::WriteStructuredClone(rq, JS::NullHandleValue);
g_GUI->PushPage(L"hotkey/page_hotkey.xml", data, JS::UndefinedHandleValue); g_GUI->PushPage(L"hotkey/page_hotkey.xml", data, JS::UndefinedHandleValue);
// Press 'a'. // Press 'a'.

View File

@ -20,7 +20,8 @@
#include "scriptinterface/ScriptTypes.h" #include "scriptinterface/ScriptTypes.h"
class ScriptInterface; class ScriptRequest;
namespace StunClient { namespace StunClient {
struct StunEndpoint; struct StunEndpoint;
} }
@ -58,8 +59,8 @@ public:
virtual JS::Value GUIGetBoardList(const ScriptInterface& scriptInterface) = 0; virtual JS::Value GUIGetBoardList(const ScriptInterface& scriptInterface) = 0;
virtual JS::Value GUIGetProfile(const ScriptInterface& scriptInterface) = 0; virtual JS::Value GUIGetProfile(const ScriptInterface& scriptInterface) = 0;
virtual JS::Value GuiPollNewMessages(const ScriptInterface& scriptInterface) = 0; virtual JS::Value GuiPollNewMessages(const ScriptInterface& guiInterface) = 0;
virtual JS::Value GuiPollHistoricMessages(const ScriptInterface& scriptInterface) = 0; virtual JS::Value GuiPollHistoricMessages(const ScriptInterface& guiInterface) = 0;
virtual bool GuiPollHasPlayerListUpdate() = 0; virtual bool GuiPollHasPlayerListUpdate() = 0;
virtual void SendMUCMessage(const std::string& message) = 0; virtual void SendMUCMessage(const std::string& message) = 0;

View File

@ -34,8 +34,8 @@
#include "ps/ConfigDB.h" #include "ps/ConfigDB.h"
#include "ps/GUID.h" #include "ps/GUID.h"
#include "ps/Pyrogenesis.h" #include "ps/Pyrogenesis.h"
#include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/StructuredClone.h"
#include <iostream> #include <iostream>
@ -734,7 +734,7 @@ bool XmppClient::GuiPollHasPlayerListUpdate()
return hasUpdate; return hasUpdate;
} }
JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface) JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& guiInterface)
{ {
if ((m_isConnected && !m_initialLoadComplete) || m_GuiMessageQueue.empty()) if ((m_isConnected && !m_initialLoadComplete) || m_GuiMessageQueue.empty())
return JS::UndefinedValue(); return JS::UndefinedValue();
@ -765,8 +765,8 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface)
if (level != "room-message" && level != "private-message") if (level != "room-message" && level != "private-message")
continue; continue;
JS::RootedValue historicMessage(rq.cx); JS::RootedValue historicMessage(rq.cx, Script::DeepCopy(rq, rootedMessage));
if (JS_StructuredClone(rq.cx, rootedMessage, &historicMessage, nullptr, nullptr)) if (true)
{ {
m_ScriptInterface->SetProperty(historicMessage, "historic", true); m_ScriptInterface->SetProperty(historicMessage, "historic", true);
m_ScriptInterface->FreezeObject(historicMessage, true); m_ScriptInterface->FreezeObject(historicMessage, true);
@ -778,10 +778,10 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface)
m_GuiMessageQueue.clear(); m_GuiMessageQueue.clear();
// Copy the messages over to the caller script interface. // Copy the messages over to the caller script interface.
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages); return Script::CloneValueFromOtherCompartment(guiInterface, *m_ScriptInterface, messages);
} }
JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInterface) JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& guiInterface)
{ {
if (m_HistoricGuiMessages.empty()) if (m_HistoricGuiMessages.empty())
return JS::UndefinedValue(); return JS::UndefinedValue();
@ -796,7 +796,7 @@ JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInter
m_ScriptInterface->SetPropertyInt(messages, j++, message); m_ScriptInterface->SetPropertyInt(messages, j++, message);
// Copy the messages over to the caller script interface. // Copy the messages over to the caller script interface.
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages); return Script::CloneValueFromOtherCompartment(guiInterface, *m_ScriptInterface, messages);
} }
/** /**

View File

@ -27,7 +27,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
class ScriptInterface; class ScriptRequest;
namespace glooxwrapper namespace glooxwrapper
{ {
@ -159,8 +159,8 @@ protected:
virtual void handleSessionInitiation(glooxwrapper::Jingle::Session& session, const glooxwrapper::Jingle::Session::Jingle& jingle); virtual void handleSessionInitiation(glooxwrapper::Jingle::Session& session, const glooxwrapper::Jingle::Session::Jingle& jingle);
public: public:
JS::Value GuiPollNewMessages(const ScriptInterface& scriptInterface); JS::Value GuiPollNewMessages(const ScriptInterface& guiInterface);
JS::Value GuiPollHistoricMessages(const ScriptInterface& scriptInterface); JS::Value GuiPollHistoricMessages(const ScriptInterface& guiInterface);
bool GuiPollHasPlayerListUpdate(); bool GuiPollHasPlayerListUpdate();
void SendMUCMessage(const std::string& message); void SendMUCMessage(const std::string& message);

View File

@ -32,7 +32,7 @@
#include "ps/GUID.h" #include "ps/GUID.h"
#include "ps/Util.h" #include "ps/Util.h"
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
#include "third_party/encryption/pkcs5_pbkdf2.h" #include "third_party/encryption/pkcs5_pbkdf2.h"
@ -210,7 +210,7 @@ CStr GetPlayerGUID()
return g_NetClient->GetGUID(); return g_NetClient->GetGUID();
} }
JS::Value PollNetworkClient(const ScriptInterface& scriptInterface) JS::Value PollNetworkClient(const ScriptInterface& guiInterface)
{ {
if (!g_NetClient) if (!g_NetClient)
return JS::UndefinedValue(); return JS::UndefinedValue();
@ -219,7 +219,7 @@ JS::Value PollNetworkClient(const ScriptInterface& scriptInterface)
ScriptRequest rqNet(g_NetClient->GetScriptInterface()); ScriptRequest rqNet(g_NetClient->GetScriptInterface());
JS::RootedValue pollNet(rqNet.cx); JS::RootedValue pollNet(rqNet.cx);
g_NetClient->GuiPoll(&pollNet); g_NetClient->GuiPoll(&pollNet);
return scriptInterface.CloneValueFromOtherCompartment(g_NetClient->GetScriptInterface(), pollNet); return Script::CloneValueFromOtherCompartment(guiInterface, g_NetClient->GetScriptInterface(), pollNet);
} }
void SendGameSetupMessage(const ScriptInterface& scriptInterface, JS::HandleValue attribs1) void SendGameSetupMessage(const ScriptInterface& scriptInterface, JS::HandleValue attribs1)

View File

@ -31,12 +31,12 @@
#include "ps/Game.h" #include "ps/Game.h"
#include "ps/Mod.h" #include "ps/Mod.h"
#include "ps/Pyrogenesis.h" #include "ps/Pyrogenesis.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
// TODO: we ought to check version numbers when loading files // TODO: we ought to check version numbers when loading files
Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone) Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const Script::StructuredClone& guiMetadataClone)
{ {
// Determine the filename to save under // Determine the filename to save under
const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d"); const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d");
@ -51,7 +51,7 @@ Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSi
return Save(filename.Filename().string(), description, simulation, guiMetadataClone); return Save(filename.Filename().string(), description, simulation, guiMetadataClone);
} }
Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone) Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const Script::StructuredClone& guiMetadataClone)
{ {
ScriptRequest rq(simulation.GetScriptInterface()); ScriptRequest rq(simulation.GetScriptInterface());
@ -93,7 +93,7 @@ Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation
"initAttributes", initAttributes); "initAttributes", initAttributes);
JS::RootedValue guiMetadata(rq.cx); JS::RootedValue guiMetadata(rq.cx);
simulation.GetScriptInterface().ReadStructuredClone(guiMetadataClone, &guiMetadata); Script::ReadStructuredClone(rq, guiMetadataClone, &guiMetadata);
// get some camera data // get some camera data
const CVector3D cameraPosition = g_Game->GetView()->GetCameraPosition(); const CVector3D cameraPosition = g_Game->GetView()->GetCameraPosition();

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games. /* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -18,7 +18,8 @@
#ifndef INCLUDED_SAVEDGAME #ifndef INCLUDED_SAVEDGAME
#define INCLUDED_SAVEDGAME #define INCLUDED_SAVEDGAME
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
class CSimulation2; class CSimulation2;
class CGUIManager; class CGUIManager;
@ -45,7 +46,7 @@ namespace SavedGames
* @param guiMetadataClone if not NULL, store some UI-related data with the saved game * @param guiMetadataClone if not NULL, store some UI-related data with the saved game
* @return INFO::OK if successfully saved, else an error Status * @return INFO::OK if successfully saved, else an error Status
*/ */
Status Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone); Status Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const Script::StructuredClone& guiMetadataClone);
/** /**
* Create new saved game archive with given prefix and simulation data * Create new saved game archive with given prefix and simulation data
@ -56,7 +57,7 @@ namespace SavedGames
* @param guiMetadataClone if not NULL, store some UI-related data with the saved game * @param guiMetadataClone if not NULL, store some UI-related data with the saved game
* @return INFO::OK if successfully saved, else an error Status * @return INFO::OK if successfully saved, else an error Status
*/ */
Status SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const ScriptInterface::StructuredClone& guiMetadataClone); Status SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const Script::StructuredClone& guiMetadataClone);
/** /**
* Load saved game archive with the given name * Load saved game archive with the given name

View File

@ -28,7 +28,7 @@
#include "ps/Replay.h" #include "ps/Replay.h"
#include "ps/World.h" #include "ps/World.h"
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
#include "simulation2/system/TurnManager.h" #include "simulation2/system/TurnManager.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
#include "soundmanager/SoundManager.h" #include "soundmanager/SoundManager.h"
@ -40,7 +40,7 @@ bool IsGameStarted()
return g_Game; return g_Game;
} }
void StartGame(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleValue attribs, int playerID) void StartGame(const ScriptInterface& guiInterface, JS::HandleValue attribs, int playerID)
{ {
ENSURE(!g_NetServer); ENSURE(!g_NetServer);
ENSURE(!g_NetClient); ENSURE(!g_NetClient);
@ -48,12 +48,11 @@ void StartGame(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleValue attri
g_Game = new CGame(true); g_Game = new CGame(true);
// Convert from GUI script context to sim script context // Convert from GUI script context to sim script context/
CSimulation2* sim = g_Game->GetSimulation2(); CSimulation2* sim = g_Game->GetSimulation2();
ScriptRequest rqSim(sim->GetScriptInterface()); ScriptRequest rqSim(sim->GetScriptInterface());
JS::RootedValue gameAttribs(rqSim.cx, JS::RootedValue gameAttribs(rqSim.cx, Script::CloneValueFromOtherCompartment(sim->GetScriptInterface(), guiInterface, attribs));
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), attribs));
g_Game->SetPlayerID(playerID); g_Game->SetPlayerID(playerID);
g_Game->StartGame(&gameAttribs, ""); g_Game->StartGame(&gameAttribs, "");

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games. /* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -25,7 +25,7 @@
#include "ps/Game.h" #include "ps/Game.h"
#include "ps/SavedGame.h" #include "ps/SavedGame.h"
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/StructuredClone.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
#include "simulation2/system/TurnManager.h" #include "simulation2/system/TurnManager.h"
@ -41,16 +41,16 @@ bool DeleteSavedGame(const std::wstring& name)
return SavedGames::DeleteSavedGame(name); return SavedGames::DeleteSavedGame(name);
} }
void SaveGame(const ScriptInterface& scriptInterface, const std::wstring& filename, const std::wstring& description, JS::HandleValue GUIMetadata) void SaveGame(const ScriptRequest& rq, const std::wstring& filename, const std::wstring& description, JS::HandleValue GUIMetadata)
{ {
ScriptInterface::StructuredClone GUIMetadataClone = scriptInterface.WriteStructuredClone(GUIMetadata); Script::StructuredClone GUIMetadataClone = Script::WriteStructuredClone(rq, GUIMetadata);
if (SavedGames::Save(filename, description, *g_Game->GetSimulation2(), GUIMetadataClone) < 0) if (SavedGames::Save(filename, description, *g_Game->GetSimulation2(), GUIMetadataClone) < 0)
LOGERROR("Failed to save game"); LOGERROR("Failed to save game");
} }
void SaveGamePrefix(const ScriptInterface& scriptInterface, const std::wstring& prefix, const std::wstring& description, JS::HandleValue GUIMetadata) void SaveGamePrefix(const ScriptRequest& rq, const std::wstring& prefix, const std::wstring& description, JS::HandleValue GUIMetadata)
{ {
ScriptInterface::StructuredClone GUIMetadataClone = scriptInterface.WriteStructuredClone(GUIMetadata); Script::StructuredClone GUIMetadataClone = Script::WriteStructuredClone(rq, GUIMetadata);
if (SavedGames::SavePrefix(prefix, description, *g_Game->GetSimulation2(), GUIMetadataClone) < 0) if (SavedGames::SavePrefix(prefix, description, *g_Game->GetSimulation2(), GUIMetadataClone) < 0)
LOGERROR("Failed to save game"); LOGERROR("Failed to save game");
} }
@ -101,8 +101,7 @@ JS::Value StartSavedGame(const ScriptInterface& scriptInterface, const std::wstr
CSimulation2* sim = g_Game->GetSimulation2(); CSimulation2* sim = g_Game->GetSimulation2();
ScriptRequest rqGame(sim->GetScriptInterface()); ScriptRequest rqGame(sim->GetScriptInterface());
JS::RootedValue gameContextMetadata(rqGame.cx, JS::RootedValue gameContextMetadata(rqGame.cx, Script::CloneValueFromOtherCompartment(sim->GetScriptInterface(), scriptInterface, guiContextMetadata));
sim->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, guiContextMetadata));
JS::RootedValue gameInitAttributes(rqGame.cx); JS::RootedValue gameInitAttributes(rqGame.cx);
sim->GetScriptInterface().GetProperty(gameContextMetadata, "initAttributes", &gameInitAttributes); sim->GetScriptInterface().GetProperty(gameContextMetadata, "initAttributes", &gameInitAttributes);

View File

@ -26,6 +26,7 @@
#include "ps/Game.h" #include "ps/Game.h"
#include "ps/GameSetup/GameSetup.h" #include "ps/GameSetup/GameSetup.h"
#include "ps/Loader.h" #include "ps/Loader.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpAIInterface.h" #include "simulation2/components/ICmpAIInterface.h"
#include "simulation2/components/ICmpTemplateManager.h" #include "simulation2/components/ICmpTemplateManager.h"

View File

@ -34,7 +34,7 @@ constexpr int DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER = 2 * 1024 * 1024;
* should only be used on a single thread. * should only be used on a single thread.
* *
* (One means to share data between threads and contexts is to create * (One means to share data between threads and contexts is to create
* a ScriptInterface::StructuredClone.) * a Script::StructuredClone.)
*/ */
class ScriptContext class ScriptContext

View File

@ -58,7 +58,6 @@
#include "js/GCHashTable.h" #include "js/GCHashTable.h"
#include "js/JSON.h" #include "js/JSON.h"
#include "js/SourceText.h" #include "js/SourceText.h"
#include "js/StructuredClone.h"
#include "js/Proxy.h" #include "js/Proxy.h"
#include "js/Warnings.h" #include "js/Warnings.h"

View File

@ -22,6 +22,7 @@
#include "ScriptExtraHeaders.h" #include "ScriptExtraHeaders.h"
#include "ScriptInterface.h" #include "ScriptInterface.h"
#include "ScriptStats.h" #include "ScriptStats.h"
#include "StructuredClone.h"
#include "lib/debug.h" #include "lib/debug.h"
#include "lib/utf8.h" #include "lib/utf8.h"
@ -187,8 +188,8 @@ JS::Value deepcopy(const ScriptRequest& rq, JS::HandleValue val)
return JS::UndefinedValue(); return JS::UndefinedValue();
} }
JS::RootedValue ret(rq.cx); JS::RootedValue ret(rq.cx, Script::DeepCopy(rq, val));
if (!JS_StructuredClone(rq.cx, val, &ret, NULL, NULL)) if (ret.isNullOrUndefined())
{ {
ScriptException::Raise(rq, "deepcopy StructureClone copy failed."); ScriptException::Raise(rq, "deepcopy StructureClone copy failed.");
return JS::UndefinedValue(); return JS::UndefinedValue();
@ -343,7 +344,7 @@ ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugN
ScriptRequest rq(this); ScriptRequest rq(this);
m_CmptPrivate.pScriptInterface = this; m_CmptPrivate.pScriptInterface = this;
JS_SetCompartmentPrivate(js::GetObjectCompartment(rq.glob), (void*)&m_CmptPrivate); JS::SetRealmPrivate(JS::GetObjectRealmOrNull(rq.glob), (void*)&m_CmptPrivate);
} }
ScriptInterface::~ScriptInterface() ScriptInterface::~ScriptInterface()
@ -362,7 +363,7 @@ void ScriptInterface::SetCallbackData(void* pCBData)
ScriptInterface::CmptPrivate* ScriptInterface::GetScriptInterfaceAndCBData(JSContext* cx) ScriptInterface::CmptPrivate* ScriptInterface::GetScriptInterfaceAndCBData(JSContext* cx)
{ {
CmptPrivate* pCmptPrivate = (CmptPrivate*)JS_GetCompartmentPrivate(js::GetContextCompartment(cx)); CmptPrivate* pCmptPrivate = (CmptPrivate*)JS::GetRealmPrivate(JS::GetCurrentRealmOrNull(cx));
return pCmptPrivate; return pCmptPrivate;
} }
@ -963,36 +964,3 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
ScriptFunction::Call(rq, obj, "toSource", source); ScriptFunction::Call(rq, obj, "toSource", source);
return utf8_from_wstring(source); return utf8_from_wstring(source);
} }
JS::Value ScriptInterface::CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const
{
PROFILE("CloneValueFromOtherCompartment");
ScriptRequest rq(this);
JS::RootedValue out(rq.cx);
ScriptInterface::StructuredClone structuredClone = otherCompartment.WriteStructuredClone(val);
ReadStructuredClone(structuredClone, &out);
return out.get();
}
ScriptInterface::StructuredClone ScriptInterface::WriteStructuredClone(JS::HandleValue v) const
{
ScriptRequest rq(this);
ScriptInterface::StructuredClone ret(new JSStructuredCloneData(JS::StructuredCloneScope::SameProcess));
JS::CloneDataPolicy policy;
if (!JS_WriteStructuredClone(rq.cx, v, ret.get(), JS::StructuredCloneScope::SameProcess, policy, nullptr, nullptr, JS::UndefinedHandleValue))
{
debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!");
ScriptException::CatchPending(rq);
return ScriptInterface::StructuredClone();
}
return ret;
}
void ScriptInterface::ReadStructuredClone(const ScriptInterface::StructuredClone& ptr, JS::MutableHandleValue ret) const
{
ScriptRequest rq(this);
JS::CloneDataPolicy policy;
if (!JS_ReadStructuredClone(rq.cx, *ptr, JS_STRUCTURED_CLONE_VERSION, ptr->scope(), ret, policy, nullptr, nullptr))
ScriptException::CatchPending(rq);
}

View File

@ -48,8 +48,6 @@ ERROR_TYPE(Scripting_DefineType, CreationFailed);
// but as large as necessary for all wrapped functions) // but as large as necessary for all wrapped functions)
#define SCRIPT_INTERFACE_MAX_ARGS 8 #define SCRIPT_INTERFACE_MAX_ARGS 8
class JSStructuredCloneData;
class ScriptInterface; class ScriptInterface;
struct ScriptInterface_impl; struct ScriptInterface_impl;
@ -314,26 +312,6 @@ public:
*/ */
bool MathRandom(double& nbr); bool MathRandom(double& nbr);
/**
* Structured clones are a way to serialize 'simple' JS::Values into a buffer
* that can safely be passed between compartments and between threads.
* A StructuredClone can be stored and read multiple times if desired.
* We wrap them in shared_ptr so memory management is automatic and
* thread-safe.
*/
using StructuredClone = shared_ptr<JSStructuredCloneData>;
StructuredClone WriteStructuredClone(JS::HandleValue v) const;
void ReadStructuredClone(const StructuredClone& ptr, JS::MutableHandleValue ret) const;
/**
* Construct a new value (usable in this ScriptInterface's compartment) by cloning
* a value from a different compartment.
* Complex values (functions, XML, etc) won't be cloned correctly, but basic
* types and cyclic references should be fine.
*/
JS::Value CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const;
/** /**
* Retrieve the private data field of a JSObject that is an instance of the given JSClass. * Retrieve the private data field of a JSObject that is an instance of the given JSClass.
*/ */

View File

@ -0,0 +1,82 @@
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ScriptExceptions.h"
#include "ScriptInterface.h"
#include "ScriptRequest.h"
#include "StructuredClone.h"
// Ignore warnings in SM headers.
#if GCC_VERSION || CLANG_VERSION
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#elif MSC_VERSION
# pragma warning(push, 1)
#endif
#include "js/StructuredClone.h"
#if GCC_VERSION || CLANG_VERSION
# pragma GCC diagnostic pop
#elif MSC_VERSION
# pragma warning(pop)
#endif
Script::StructuredClone Script::WriteStructuredClone(const ScriptRequest& rq, JS::HandleValue v)
{
Script::StructuredClone ret(new JSStructuredCloneData(JS::StructuredCloneScope::SameProcess));
JS::CloneDataPolicy policy;
if (!JS_WriteStructuredClone(rq.cx, v, ret.get(), JS::StructuredCloneScope::SameProcess, policy, nullptr, nullptr, JS::UndefinedHandleValue))
{
debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!");
ScriptException::CatchPending(rq);
return StructuredClone();
}
return ret;
}
void Script::ReadStructuredClone(const ScriptRequest& rq, const Script::StructuredClone& ptr, JS::MutableHandleValue ret)
{
JS::CloneDataPolicy policy;
if (!JS_ReadStructuredClone(rq.cx, *ptr, JS_STRUCTURED_CLONE_VERSION, ptr->scope(), ret, policy, nullptr, nullptr))
ScriptException::CatchPending(rq);
}
JS::Value Script::CloneValueFromOtherCompartment(const ScriptInterface& to, const ScriptInterface& from, JS::HandleValue val)
{
PROFILE("CloneValueFromOtherCompartment");
Script::StructuredClone structuredClone;
{
ScriptRequest fromRq(from);
structuredClone = WriteStructuredClone(fromRq, val);
}
ScriptRequest toRq(to);
JS::RootedValue out(toRq.cx);
ReadStructuredClone(toRq, structuredClone, &out);
return out.get();
}
JS::Value Script::DeepCopy(const ScriptRequest& rq, JS::HandleValue val)
{
JS::RootedValue out(rq.cx);
ReadStructuredClone(rq, WriteStructuredClone(rq, val), &out);
return out.get();
}

View File

@ -0,0 +1,61 @@
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SCRIPTINTERFACE_STRUCTUREDCLONE
#define INCLUDED_SCRIPTINTERFACE_STRUCTUREDCLONE
#include "ScriptForward.h"
#include <memory>
class JSStructuredCloneData;
namespace Script
{
/**
* Structured clones are a way to serialize 'simple' JS::Values into a buffer
* that can safely be passed between compartments and between threads.
* A StructuredClone can be stored and read multiple times if desired.
* We wrap them in shared_ptr so memory management is automatic and
* thread-safe.
*/
using StructuredClone = std::shared_ptr<JSStructuredCloneData>;
StructuredClone WriteStructuredClone(const ScriptRequest& rq, JS::HandleValue v);
void ReadStructuredClone(const ScriptRequest& rq, const StructuredClone& ptr, JS::MutableHandleValue ret);
/**
* Construct a new value by cloning a value (possibly from a different Compartment).
* Complex values (functions, XML, etc) won't be cloned correctly, but basic
* types and cyclic references should be fine.
* Takes ScriptInterfaces to enter the correct realm.
* Caller beware - manipulating several compartments in the same function is tricky.
* @param to - ScriptInterface of the target. Should match the rooting context of the result.
* @param from - ScriptInterface of @a val.
*/
JS::Value CloneValueFromOtherCompartment(const ScriptInterface& to, const ScriptInterface& from, JS::HandleValue val);
/**
* Clone a JS value, ensuring that changes to the result
* won't affect the original value.
* Works by cloning, so the same restrictions as CloneValueFromOtherCompartment apply.
*/
JS::Value DeepCopy(const ScriptRequest& rq, JS::HandleValue val);
} // namespace Script
#endif // INCLUDED_SCRIPTINTERFACE_STRUCTUREDCLONE

View File

@ -19,6 +19,7 @@
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/StructuredClone.h"
#include "ps/CLogger.h" #include "ps/CLogger.h"
@ -73,7 +74,7 @@ public:
{ {
ScriptRequest rq2(script2); ScriptRequest rq2(script2);
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); JS::RootedValue obj2(rq2.cx, Script::CloneValueFromOtherCompartment(script2, script1, obj1));
std::string source; std::string source;
TS_ASSERT(ScriptFunction::Call(rq2, obj2, "toSource", source)); TS_ASSERT(ScriptFunction::Call(rq2, obj2, "toSource", source));
@ -95,7 +96,7 @@ public:
{ {
ScriptRequest rq2(script2); ScriptRequest rq2(script2);
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); JS::RootedValue obj2(rq2.cx, Script::CloneValueFromOtherCompartment(script2, script1, obj1));
std::string source; std::string source;
TS_ASSERT(ScriptFunction::Call(rq2, obj2, "toSource", source)); TS_ASSERT(ScriptFunction::Call(rq2, obj2, "toSource", source));
@ -115,7 +116,7 @@ public:
{ {
ScriptRequest rq2(script2); ScriptRequest rq2(script2);
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); JS::RootedValue obj2(rq2.cx, Script::CloneValueFromOtherCompartment(script2, script1, obj1));
// Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0] // Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0]
JS::RootedValue prop_a(rq2.cx); JS::RootedValue prop_a(rq2.cx);
@ -244,7 +245,7 @@ public:
TS_ASSERT_STR_EQUALS(script.ToString(&val), "({x:1, z:[2, \"3\\u263A\\uD800\"], y:true})"); TS_ASSERT_STR_EQUALS(script.ToString(&val), "({x:1, z:[2, \"3\\u263A\\uD800\"], y:true})");
} }
// This function tests a common way to mod functions, by crating a wrapper that // This function tests a common way to mod functions, by creating a wrapper that
// extends the functionality and is then assigned to the name of the function. // extends the functionality and is then assigned to the name of the function.
void test_function_override() void test_function_override()
{ {

View File

@ -22,6 +22,7 @@
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptContext.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/StructuredClone.h"
#include "simulation2/MessageTypes.h" #include "simulation2/MessageTypes.h"
#include "simulation2/system/ComponentManager.h" #include "simulation2/system/ComponentManager.h"
@ -161,7 +162,7 @@ public:
void InitRNGSeedSimulation(); void InitRNGSeedSimulation();
void InitRNGSeedAI(); void InitRNGSeedAI();
static std::vector<SimulationCommand> CloneCommandsFromOtherCompartment(const ScriptInterface& oldScript, const ScriptInterface& newScript, static std::vector<SimulationCommand> CloneCommandsFromOtherCompartment(const ScriptInterface& newScript, const ScriptInterface& oldScript,
const std::vector<SimulationCommand>& commands) const std::vector<SimulationCommand>& commands)
{ {
std::vector<SimulationCommand> newCommands; std::vector<SimulationCommand> newCommands;
@ -170,7 +171,7 @@ public:
ScriptRequest rqNew(newScript); ScriptRequest rqNew(newScript);
for (const SimulationCommand& command : commands) for (const SimulationCommand& command : commands)
{ {
JS::RootedValue tmpCommand(rqNew.cx, newScript.CloneValueFromOtherCompartment(oldScript, command.data)); JS::RootedValue tmpCommand(rqNew.cx, Script::CloneValueFromOtherCompartment(newScript, oldScript, command.data));
newScript.FreezeObject(tmpCommand, true); newScript.FreezeObject(tmpCommand, true);
SimulationCommand cmd(command.player, rqNew.cx, tmpCommand); SimulationCommand cmd(command.player, rqNew.cx, tmpCommand);
newCommands.emplace_back(std::move(cmd)); newCommands.emplace_back(std::move(cmd));
@ -414,9 +415,9 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
// Load the trigger scripts after we have loaded the simulation. // Load the trigger scripts after we have loaded the simulation.
{ {
ScriptRequest rq(scriptInterface);
ScriptRequest rq2(m_SecondaryComponentManager->GetScriptInterface()); ScriptRequest rq2(m_SecondaryComponentManager->GetScriptInterface());
JS::RootedValue mapSettingsCloned(rq2.cx, JS::RootedValue mapSettingsCloned(rq2.cx, Script::CloneValueFromOtherCompartment(m_SecondaryComponentManager->GetScriptInterface(), scriptInterface, m_MapSettings));
m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, m_MapSettings));
ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts.get())); ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts.get()));
} }
@ -469,7 +470,7 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
ENSURE(m_ComponentManager.ComputeStateHash(primaryStateAfter.hash, false)); ENSURE(m_ComponentManager.ComputeStateHash(primaryStateAfter.hash, false));
UpdateComponents(*m_SecondaryContext, turnLengthFixed, UpdateComponents(*m_SecondaryContext, turnLengthFixed,
CloneCommandsFromOtherCompartment(scriptInterface, m_SecondaryComponentManager->GetScriptInterface(), commands)); CloneCommandsFromOtherCompartment(m_SecondaryComponentManager->GetScriptInterface(), scriptInterface, commands));
SerializationTestState secondaryStateAfter; SerializationTestState secondaryStateAfter;
ENSURE(m_SecondaryComponentManager->SerializeState(secondaryStateAfter.state)); ENSURE(m_SecondaryComponentManager->SerializeState(secondaryStateAfter.state));
if (serializationTestHash) if (serializationTestHash)

View File

@ -34,6 +34,7 @@
#include "ps/Util.h" #include "ps/Util.h"
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptContext.h"
#include "scriptinterface/StructuredClone.h"
#include "simulation2/components/ICmpAIInterface.h" #include "simulation2/components/ICmpAIInterface.h"
#include "simulation2/components/ICmpCommandQueue.h" #include "simulation2/components/ICmpCommandQueue.h"
#include "simulation2/components/ICmpObstructionManager.h" #include "simulation2/components/ICmpObstructionManager.h"
@ -67,7 +68,7 @@ extern void QuitEngine();
* will block until it's actually completed, so the rest of the engine should avoid * will block until it's actually completed, so the rest of the engine should avoid
* reading it for as long as possible. * reading it for as long as possible.
* *
* JS::Values are passed between the game and AI threads using ScriptInterface::StructuredClone. * JS::Values are passed between the game and AI threads using Script::StructuredClone.
* *
* TODO: actually the thread isn't implemented yet, because performance hasn't been * TODO: actually the thread isn't implemented yet, because performance hasn't been
* sufficiently problematic to justify the complexity yet, but the CAIWorker interface * sufficiently problematic to justify the complexity yet, but the CAIWorker interface
@ -204,14 +205,14 @@ private:
shared_ptr<ScriptInterface> m_ScriptInterface; shared_ptr<ScriptInterface> m_ScriptInterface;
JS::PersistentRootedValue m_Obj; JS::PersistentRootedValue m_Obj;
std::vector<ScriptInterface::StructuredClone > m_Commands; std::vector<Script::StructuredClone > m_Commands;
}; };
public: public:
struct SCommandSets struct SCommandSets
{ {
player_id_t player; player_id_t player;
std::vector<ScriptInterface::StructuredClone > commands; std::vector<Script::StructuredClone > commands;
}; };
CAIWorker() : CAIWorker() :
@ -291,11 +292,12 @@ public:
void PostCommand(int playerid, JS::HandleValue cmd) void PostCommand(int playerid, JS::HandleValue cmd)
{ {
ScriptRequest rq(m_ScriptInterface);
for (size_t i=0; i<m_Players.size(); i++) for (size_t i=0; i<m_Players.size(); i++)
{ {
if (m_Players[i]->m_Player == playerid) if (m_Players[i]->m_Player == playerid)
{ {
m_Players[i]->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(cmd)); m_Players[i]->m_Commands.push_back(Script::WriteStructuredClone(rq, cmd));
return; return;
} }
} }
@ -465,7 +467,7 @@ public:
return true; return true;
} }
bool RunGamestateInit(const ScriptInterface::StructuredClone& gameState, const Grid<NavcellData>& passabilityMap, const Grid<u8>& territoryMap, bool RunGamestateInit(const Script::StructuredClone& gameState, const Grid<NavcellData>& passabilityMap, const Grid<u8>& territoryMap,
const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks) const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks)
{ {
// this will be run last by InitGame.js, passing the full game representation. // this will be run last by InitGame.js, passing the full game representation.
@ -474,7 +476,7 @@ public:
ScriptRequest rq(m_ScriptInterface); ScriptRequest rq(m_ScriptInterface);
JS::RootedValue state(rq.cx); JS::RootedValue state(rq.cx);
m_ScriptInterface->ReadStructuredClone(gameState, &state); Script::ReadStructuredClone(rq, gameState, &state);
ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, passabilityMap); ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, passabilityMap);
ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, territoryMap); ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, territoryMap);
@ -501,7 +503,7 @@ public:
return true; return true;
} }
void UpdateGameState(const ScriptInterface::StructuredClone& gameState) void UpdateGameState(const Script::StructuredClone& gameState)
{ {
ENSURE(m_CommandsComputed); ENSURE(m_CommandsComputed);
m_GameState = gameState; m_GameState = gameState;
@ -661,7 +663,7 @@ public:
for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j) for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j)
{ {
JS::RootedValue val(rq.cx); JS::RootedValue val(rq.cx);
m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j], &val); Script::ReadStructuredClone(rq, m_Players[i]->m_Commands[j], &val);
serializer.ScriptVal("command", &val); serializer.ScriptVal("command", &val);
} }
@ -726,7 +728,7 @@ public:
{ {
JS::RootedValue val(rq.cx); JS::RootedValue val(rq.cx);
deserializer.ScriptVal("command", &val); deserializer.ScriptVal("command", &val);
m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val)); m_Players.back()->m_Commands.push_back(Script::WriteStructuredClone(rq, val));
} }
deserializer.ScriptObjectAssign("data", m_Players.back()->m_Obj); deserializer.ScriptObjectAssign("data", m_Players.back()->m_Obj);
@ -780,7 +782,7 @@ private:
JS::RootedValue state(rq.cx); JS::RootedValue state(rq.cx);
{ {
PROFILE3("AI compute read state"); PROFILE3("AI compute read state");
m_ScriptInterface->ReadStructuredClone(m_GameState, &state); Script::ReadStructuredClone(rq, m_GameState, &state);
m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true); m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true);
m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true); m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true);
} }
@ -831,7 +833,7 @@ private:
std::set<std::wstring> m_LoadedModules; std::set<std::wstring> m_LoadedModules;
ScriptInterface::StructuredClone m_GameState; Script::StructuredClone m_GameState;
Grid<NavcellData> m_PassabilityMap; Grid<NavcellData> m_PassabilityMap;
JS::PersistentRootedValue m_PassabilityMapVal; JS::PersistentRootedValue m_PassabilityMapVal;
Grid<u8> m_TerritoryMap; Grid<u8> m_TerritoryMap;
@ -959,7 +961,7 @@ public:
if (cmpPathfinder) if (cmpPathfinder)
cmpPathfinder->GetPassabilityClasses(nonPathfindingPassClassMasks, pathfindingPassClassMasks); cmpPathfinder->GetPassabilityClasses(nonPathfindingPassClassMasks, pathfindingPassClassMasks);
m_Worker.RunGamestateInit(scriptInterface.WriteStructuredClone(state), m_Worker.RunGamestateInit(Script::WriteStructuredClone(rq, state),
*passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks); *passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks);
} }
@ -985,7 +987,7 @@ public:
LoadPathfinderClasses(state); // add the pathfinding classes to it LoadPathfinderClasses(state); // add the pathfinding classes to it
// Update the game state // Update the game state
m_Worker.UpdateGameState(scriptInterface.WriteStructuredClone(state)); m_Worker.UpdateGameState(Script::WriteStructuredClone(rq, state));
// Update the pathfinding data // Update the pathfinding data
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
@ -1039,7 +1041,7 @@ public:
{ {
for (size_t j = 0; j < commands[i].commands.size(); ++j) for (size_t j = 0; j < commands[i].commands.size(); ++j)
{ {
scriptInterface.ReadStructuredClone(commands[i].commands[j], &clonedCommandVal); Script::ReadStructuredClone(rq, commands[i].commands[j], &clonedCommandVal);
cmpCommandQueue->PushLocalCommand(commands[i].player, clonedCommandVal); cmpCommandQueue->PushLocalCommand(commands[i].player, clonedCommandVal);
} }
} }

View File

@ -26,6 +26,7 @@
#include "ps/Pyrogenesis.h" #include "ps/Pyrogenesis.h"
#include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/FunctionWrapper.h"
#include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/StructuredClone.h"
#include "simulation2/components/ICmpAIManager.h" #include "simulation2/components/ICmpAIManager.h"
#include "simulation2/components/ICmpCommandQueue.h" #include "simulation2/components/ICmpCommandQueue.h"
#include "simulation2/components/ICmpGuiInterface.h" #include "simulation2/components/ICmpGuiInterface.h"
@ -55,11 +56,11 @@ JS::Value GuiInterfaceCall(const ScriptInterface& scriptInterface, const std::ws
return JS::UndefinedValue(); return JS::UndefinedValue();
ScriptRequest rqSim(sim->GetScriptInterface()); ScriptRequest rqSim(sim->GetScriptInterface());
JS::RootedValue arg(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, data)); JS::RootedValue arg(rqSim.cx, Script::CloneValueFromOtherCompartment(sim->GetScriptInterface(), scriptInterface, data));
JS::RootedValue ret(rqSim.cx); JS::RootedValue ret(rqSim.cx);
cmpGuiInterface->ScriptCall(g_Game->GetViewedPlayerID(), name, arg, &ret); cmpGuiInterface->ScriptCall(g_Game->GetViewedPlayerID(), name, arg, &ret);
return scriptInterface.CloneValueFromOtherCompartment(sim->GetScriptInterface(), ret); return Script::CloneValueFromOtherCompartment(scriptInterface, sim->GetScriptInterface(), ret);
} }
void PostNetworkCommand(const ScriptInterface& scriptInterface, JS::HandleValue cmd) void PostNetworkCommand(const ScriptInterface& scriptInterface, JS::HandleValue cmd)
@ -75,8 +76,7 @@ void PostNetworkCommand(const ScriptInterface& scriptInterface, JS::HandleValue
return; return;
ScriptRequest rqSim(sim->GetScriptInterface()); ScriptRequest rqSim(sim->GetScriptInterface());
JS::RootedValue cmd2(rqSim.cx, JS::RootedValue cmd2(rqSim.cx, Script::CloneValueFromOtherCompartment(sim->GetScriptInterface(), scriptInterface, cmd));
sim->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, cmd));
cmpCommandQueue->PostNetworkCommand(cmd2); cmpCommandQueue->PostNetworkCommand(cmd2);
} }

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games. /* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -22,6 +22,7 @@
#include "gui/GUIManager.h" #include "gui/GUIManager.h"
#include "ps/CLogger.h" #include "ps/CLogger.h"
#include "ps/Util.h" #include "ps/Util.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
const CStr CReplayTurnManager::EventNameReplayFinished = "ReplayFinished"; const CStr CReplayTurnManager::EventNameReplayFinished = "ReplayFinished";
@ -94,11 +95,11 @@ void CReplayTurnManager::NotifyFinishedUpdate(u32 turn)
ignore_result(paramData.append(JS::NumberValue(turn))); ignore_result(paramData.append(JS::NumberValue(turn)));
JS::RootedValue hashVal(rq.cx); JS::RootedValue hashVal(rq.cx);
scriptInterface.ToJSVal(rq, &hashVal, hash); ScriptInterface::ToJSVal(rq, &hashVal, hash);
ignore_result(paramData.append(hashVal)); ignore_result(paramData.append(hashVal));
JS::RootedValue expectedHashVal(rq.cx); JS::RootedValue expectedHashVal(rq.cx);
scriptInterface.ToJSVal(rq, &expectedHashVal, expectedHash); ScriptInterface::ToJSVal(rq, &expectedHashVal, expectedHash);
ignore_result(paramData.append(expectedHashVal)); ignore_result(paramData.append(expectedHashVal));
g_GUI->SendEventToAll(EventNameReplayOutOfSync, paramData); g_GUI->SendEventToAll(EventNameReplayOutOfSync, paramData);

View File

@ -292,16 +292,9 @@ void CTurnManager::QuickSave(JS::HandleValue GUIMetadata)
ScriptRequest rq(m_Simulation2.GetScriptInterface()); ScriptRequest rq(m_Simulation2.GetScriptInterface());
if (JS_StructuredClone(rq.cx, GUIMetadata, &m_QuickSaveMetadata, nullptr, nullptr)) m_QuickSaveMetadata.set(Script::DeepCopy(rq, GUIMetadata));
{
// Freeze state to ensure that consectuvie loads don't modify the state // Freeze state to ensure that consectuvie loads don't modify the state
m_Simulation2.GetScriptInterface().FreezeObject(m_QuickSaveMetadata, true); m_Simulation2.GetScriptInterface().FreezeObject(m_QuickSaveMetadata, true);
}
else
{
LOGERROR("Could not copy savegame GUI metadata");
m_QuickSaveMetadata = JS::UndefinedValue();
}
LOGMESSAGERENDER("Quicksaved game"); LOGMESSAGERENDER("Quicksaved game");
} }
@ -332,12 +325,7 @@ void CTurnManager::QuickLoad()
ScriptRequest rq(m_Simulation2.GetScriptInterface()); ScriptRequest rq(m_Simulation2.GetScriptInterface());
// Provide a copy, so that GUI components don't have to clone to get mutable objects // Provide a copy, so that GUI components don't have to clone to get mutable objects
JS::RootedValue quickSaveMetadataClone(rq.cx); JS::RootedValue quickSaveMetadataClone(rq.cx, Script::DeepCopy(rq, m_QuickSaveMetadata));
if (!JS_StructuredClone(rq.cx, m_QuickSaveMetadata, &quickSaveMetadataClone, nullptr, nullptr))
{
LOGERROR("Failed to clone quicksave state!");
return;
}
JS::RootedValueArray<1> paramData(rq.cx); JS::RootedValueArray<1> paramData(rq.cx);
paramData[0].set(quickSaveMetadataClone); paramData[0].set(quickSaveMetadataClone);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games. /* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -35,6 +35,7 @@
#include "ps/GameSetup/Config.h" #include "ps/GameSetup/Config.h"
#include "ps/GameSetup/GameSetup.h" #include "ps/GameSetup/GameSetup.h"
#include "renderer/Renderer.h" #include "renderer/Renderer.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpSoundManager.h" #include "simulation2/components/ICmpSoundManager.h"