Index: ps/trunk/source/graphics/MapGenerator.h =================================================================== --- ps/trunk/source/graphics/MapGenerator.h +++ ps/trunk/source/graphics/MapGenerator.h @@ -21,7 +21,7 @@ #include "lib/posix/posix_pthread.h" #include "ps/FileIo.h" #include "ps/TemplateLoader.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include @@ -67,7 +67,7 @@ * * @return StructuredClone containing map data */ - ScriptInterface::StructuredClone GetResults(); + Script::StructuredClone GetResults(); private: CMapGeneratorWorker* m_Worker; @@ -110,7 +110,7 @@ * * @return StructuredClone containing map data */ - ScriptInterface::StructuredClone GetResults(); + Script::StructuredClone GetResults(); /** * Set initial seed, callback data. @@ -196,7 +196,7 @@ /** * Result of the mapscript generation including terrain, entities and environment settings. */ - ScriptInterface::StructuredClone m_MapData; + Script::StructuredClone m_MapData; /** * Deterministic random number generator. Index: ps/trunk/source/graphics/MapGenerator.cpp =================================================================== --- ps/trunk/source/graphics/MapGenerator.cpp +++ ps/trunk/source/graphics/MapGenerator.cpp @@ -225,7 +225,7 @@ return JS_Now(); } -ScriptInterface::StructuredClone CMapGeneratorWorker::GetResults() +Script::StructuredClone CMapGeneratorWorker::GetResults() { std::lock_guard lock(m_WorkerMutex); return m_MapData; @@ -235,7 +235,7 @@ { // Copy results std::lock_guard lock(m_WorkerMutex); - m_MapData = m_ScriptInterface->WriteStructuredClone(data); + m_MapData = Script::WriteStructuredClone(ScriptRequest(m_ScriptInterface), data); m_Progress = 0; } @@ -422,7 +422,7 @@ return m_Worker->GetProgress(); } -ScriptInterface::StructuredClone CMapGenerator::GetResults() +Script::StructuredClone CMapGenerator::GetResults() { return m_Worker->GetResults(); } Index: ps/trunk/source/graphics/MapReader.cpp =================================================================== --- ps/trunk/source/graphics/MapReader.cpp +++ ps/trunk/source/graphics/MapReader.cpp @@ -40,6 +40,7 @@ #include "renderer/SkyManager.h" #include "renderer/WaterManager.h" #include "scriptinterface/ScriptContext.h" +#include "scriptinterface/ScriptInterface.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpCinemaManager.h" #include "simulation2/components/ICmpGarrisonHolder.h" @@ -1294,11 +1295,11 @@ else if (progress == 0) { // 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 JS::RootedValue data(rq.cx); - pSimulation2->GetScriptInterface().ReadStructuredClone(results, &data); + Script::ReadStructuredClone(rq, results, &data); if (data.isUndefined()) { Index: ps/trunk/source/gui/GUIManager.h =================================================================== --- ps/trunk/source/gui/GUIManager.h +++ ps/trunk/source/gui/GUIManager.h @@ -22,7 +22,7 @@ #include "lib/input.h" #include "ps/CStr.h" #include "ps/TemplateLoader.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include #include @@ -68,13 +68,13 @@ * user inputs. * 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. * (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. @@ -131,7 +131,7 @@ /** * 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. @@ -146,11 +146,11 @@ /** * Execute the stored callback function with the given arguments. */ - void PerformCallbackFunction(ScriptInterface::StructuredClone args); + void PerformCallbackFunction(Script::StructuredClone args); CStrW m_Name; std::unordered_set 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 gui; // the actual GUI page /** Index: ps/trunk/source/gui/GUIManager.cpp =================================================================== --- ps/trunk/source/gui/GUIManager.cpp +++ ps/trunk/source/gui/GUIManager.cpp @@ -29,6 +29,7 @@ #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" CGUIManager* g_GUI = nullptr; @@ -88,17 +89,18 @@ { // The page stack is cleared (including the script context where initData came from), // therefore we have to clone initData. + ScriptRequest rq(srcScriptInterface); - ScriptInterface::StructuredClone initDataClone; + Script::StructuredClone initDataClone; if (!initData.isUndefined()) - initDataClone = srcScriptInterface->WriteStructuredClone(initData); + initDataClone = Script::WriteStructuredClone(rq, initData); m_PageStack.clear(); 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 if (!m_PageStack.empty() && !callbackFunction.isUndefined()) @@ -110,7 +112,7 @@ m_PageStack.back().LoadPage(m_ScriptContext); } -void CGUIManager::PopPage(ScriptInterface::StructuredClone args) +void CGUIManager::PopPage(Script::StructuredClone args) { if (m_PageStack.size() < 2) { @@ -122,7 +124,7 @@ 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() { } @@ -130,7 +132,7 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr scriptContext) { // If we're hotloading then try to grab some data from the previous page - ScriptInterface::StructuredClone hotloadData; + Script::StructuredClone hotloadData; if (gui) { shared_ptr scriptInterface = gui->GetScriptInterface(); @@ -139,7 +141,7 @@ JS::RootedValue global(rq.cx, rq.globalValue()); JS::RootedValue hotloadDataVal(rq.cx); ScriptFunction::Call(rq, global, "getHotloadData", &hotloadDataVal); - hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal); + hotloadData = Script::WriteStructuredClone(rq, hotloadDataVal); } g_CursorName = g_DefaultCursor; @@ -207,10 +209,10 @@ JS::RootedValue global(rq.cx, rq.globalValue()); if (initData) - scriptInterface->ReadStructuredClone(initData, &initDataVal); + Script::ReadStructuredClone(rq, initData, &initDataVal); if (hotloadData) - scriptInterface->ReadStructuredClone(hotloadData, &hotloadDataVal); + Script::ReadStructuredClone(rq, hotloadData, &hotloadDataVal); if (scriptInterface->HasProperty(global, "init") && !ScriptFunction::CallVoid(rq, global, "init", initDataVal, hotloadDataVal)) @@ -236,7 +238,7 @@ callbackFunction = std::make_shared(scriptInterface.GetGeneralJSContext(), callbackFunc); } -void CGUIManager::SGUIPage::PerformCallbackFunction(ScriptInterface::StructuredClone args) +void CGUIManager::SGUIPage::PerformCallbackFunction(Script::StructuredClone args) { if (!callbackFunction) return; @@ -253,7 +255,7 @@ JS::RootedValue argVal(rq.cx); if (args) - scriptInterface->ReadStructuredClone(args, &argVal); + Script::ReadStructuredClone(rq, args, &argVal); JS::RootedValueVector paramData(rq.cx); ignore_result(paramData.append(argVal)); Index: ps/trunk/source/gui/Scripting/JSInterface_GUIManager.cpp =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_GUIManager.cpp +++ ps/trunk/source/gui/Scripting/JSInterface_GUIManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* 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 @@ -24,15 +24,15 @@ #include "gui/ObjectBases/IGUIObject.h" #include "ps/GameSetup/Config.h" #include "scriptinterface/FunctionWrapper.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" namespace JSI_GUIManager { // Note that the initData argument may only contain clonable data. // 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) @@ -40,16 +40,15 @@ 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) { - ScriptRequest rq(pCmptPrivate->pScriptInterface); ScriptException::Raise(rq, "Can't pop GUI pages when less than two pages are opened!"); return; } - g_GUI->PopPage(pCmptPrivate->pScriptInterface->WriteStructuredClone(args)); + g_GUI->PopPage(Script::WriteStructuredClone(rq, args)); } std::wstring SetCursor(const std::wstring& name) Index: ps/trunk/source/gui/tests/test_GuiManager.h =================================================================== --- ps/trunk/source/gui/tests/test_GuiManager.h +++ ps/trunk/source/gui/tests/test_GuiManager.h @@ -25,6 +25,7 @@ #include "ps/GameSetup/GameSetup.h" #include "ps/Hotkey.h" #include "ps/XML/Xeromyces.h" +#include "scriptinterface/StructuredClone.h" #include @@ -63,7 +64,7 @@ JS::RootedValue val(rq.cx); 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); const ScriptInterface& pageScriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface()); @@ -127,7 +128,7 @@ JS::RootedValue val(rq.cx); 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); // Press 'a'. Index: ps/trunk/source/lobby/IXmppClient.h =================================================================== --- ps/trunk/source/lobby/IXmppClient.h +++ ps/trunk/source/lobby/IXmppClient.h @@ -20,7 +20,8 @@ #include "scriptinterface/ScriptTypes.h" -class ScriptInterface; +class ScriptRequest; + namespace StunClient { struct StunEndpoint; } @@ -58,8 +59,8 @@ virtual JS::Value GUIGetBoardList(const ScriptInterface& scriptInterface) = 0; virtual JS::Value GUIGetProfile(const ScriptInterface& scriptInterface) = 0; - virtual JS::Value GuiPollNewMessages(const ScriptInterface& scriptInterface) = 0; - virtual JS::Value GuiPollHistoricMessages(const ScriptInterface& scriptInterface) = 0; + virtual JS::Value GuiPollNewMessages(const ScriptInterface& guiInterface) = 0; + virtual JS::Value GuiPollHistoricMessages(const ScriptInterface& guiInterface) = 0; virtual bool GuiPollHasPlayerListUpdate() = 0; virtual void SendMUCMessage(const std::string& message) = 0; Index: ps/trunk/source/lobby/XmppClient.h =================================================================== --- ps/trunk/source/lobby/XmppClient.h +++ ps/trunk/source/lobby/XmppClient.h @@ -27,7 +27,7 @@ #include #include -class ScriptInterface; +class ScriptRequest; namespace glooxwrapper { @@ -159,8 +159,8 @@ virtual void handleSessionInitiation(glooxwrapper::Jingle::Session& session, const glooxwrapper::Jingle::Session::Jingle& jingle); public: - JS::Value GuiPollNewMessages(const ScriptInterface& scriptInterface); - JS::Value GuiPollHistoricMessages(const ScriptInterface& scriptInterface); + JS::Value GuiPollNewMessages(const ScriptInterface& guiInterface); + JS::Value GuiPollHistoricMessages(const ScriptInterface& guiInterface); bool GuiPollHasPlayerListUpdate(); void SendMUCMessage(const std::string& message); Index: ps/trunk/source/lobby/XmppClient.cpp =================================================================== --- ps/trunk/source/lobby/XmppClient.cpp +++ ps/trunk/source/lobby/XmppClient.cpp @@ -34,8 +34,8 @@ #include "ps/ConfigDB.h" #include "ps/GUID.h" #include "ps/Pyrogenesis.h" -#include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone #include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include @@ -734,7 +734,7 @@ return hasUpdate; } -JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface) +JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& guiInterface) { if ((m_isConnected && !m_initialLoadComplete) || m_GuiMessageQueue.empty()) return JS::UndefinedValue(); @@ -765,8 +765,8 @@ if (level != "room-message" && level != "private-message") continue; - JS::RootedValue historicMessage(rq.cx); - if (JS_StructuredClone(rq.cx, rootedMessage, &historicMessage, nullptr, nullptr)) + JS::RootedValue historicMessage(rq.cx, Script::DeepCopy(rq, rootedMessage)); + if (true) { m_ScriptInterface->SetProperty(historicMessage, "historic", true); m_ScriptInterface->FreezeObject(historicMessage, true); @@ -778,10 +778,10 @@ m_GuiMessageQueue.clear(); // 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()) return JS::UndefinedValue(); @@ -796,7 +796,7 @@ m_ScriptInterface->SetPropertyInt(messages, j++, message); // Copy the messages over to the caller script interface. - return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages); + return Script::CloneValueFromOtherCompartment(guiInterface, *m_ScriptInterface, messages); } /** Index: ps/trunk/source/network/scripting/JSInterface_Network.cpp =================================================================== --- ps/trunk/source/network/scripting/JSInterface_Network.cpp +++ ps/trunk/source/network/scripting/JSInterface_Network.cpp @@ -32,7 +32,7 @@ #include "ps/GUID.h" #include "ps/Util.h" #include "scriptinterface/FunctionWrapper.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include "third_party/encryption/pkcs5_pbkdf2.h" @@ -210,7 +210,7 @@ return g_NetClient->GetGUID(); } -JS::Value PollNetworkClient(const ScriptInterface& scriptInterface) +JS::Value PollNetworkClient(const ScriptInterface& guiInterface) { if (!g_NetClient) return JS::UndefinedValue(); @@ -219,7 +219,7 @@ ScriptRequest rqNet(g_NetClient->GetScriptInterface()); JS::RootedValue pollNet(rqNet.cx); 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) Index: ps/trunk/source/ps/SavedGame.h =================================================================== --- ps/trunk/source/ps/SavedGame.h +++ ps/trunk/source/ps/SavedGame.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* 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 @@ -18,7 +18,8 @@ #ifndef INCLUDED_SAVEDGAME #define INCLUDED_SAVEDGAME -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" + class CSimulation2; class CGUIManager; @@ -45,7 +46,7 @@ * @param guiMetadataClone if not NULL, store some UI-related data with the saved game * @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 @@ -56,7 +57,7 @@ * @param guiMetadataClone if not NULL, store some UI-related data with the saved game * @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 Index: ps/trunk/source/ps/SavedGame.cpp =================================================================== --- ps/trunk/source/ps/SavedGame.cpp +++ ps/trunk/source/ps/SavedGame.cpp @@ -31,12 +31,12 @@ #include "ps/Game.h" #include "ps/Mod.h" #include "ps/Pyrogenesis.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include "simulation2/Simulation2.h" // 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 const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d"); @@ -51,7 +51,7 @@ 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()); @@ -93,7 +93,7 @@ "initAttributes", initAttributes); JS::RootedValue guiMetadata(rq.cx); - simulation.GetScriptInterface().ReadStructuredClone(guiMetadataClone, &guiMetadata); + Script::ReadStructuredClone(rq, guiMetadataClone, &guiMetadata); // get some camera data const CVector3D cameraPosition = g_Game->GetView()->GetCameraPosition(); Index: ps/trunk/source/ps/scripting/JSInterface_Game.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_Game.cpp +++ ps/trunk/source/ps/scripting/JSInterface_Game.cpp @@ -28,7 +28,7 @@ #include "ps/Replay.h" #include "ps/World.h" #include "scriptinterface/FunctionWrapper.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include "simulation2/system/TurnManager.h" #include "simulation2/Simulation2.h" #include "soundmanager/SoundManager.h" @@ -40,7 +40,7 @@ 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_NetClient); @@ -48,12 +48,11 @@ 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(); ScriptRequest rqSim(sim->GetScriptInterface()); - JS::RootedValue gameAttribs(rqSim.cx, - sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), attribs)); + JS::RootedValue gameAttribs(rqSim.cx, Script::CloneValueFromOtherCompartment(sim->GetScriptInterface(), guiInterface, attribs)); g_Game->SetPlayerID(playerID); g_Game->StartGame(&gameAttribs, ""); Index: ps/trunk/source/ps/scripting/JSInterface_SavedGame.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_SavedGame.cpp +++ ps/trunk/source/ps/scripting/JSInterface_SavedGame.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* 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 @@ -25,7 +25,7 @@ #include "ps/Game.h" #include "ps/SavedGame.h" #include "scriptinterface/FunctionWrapper.h" -#include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include "simulation2/Simulation2.h" #include "simulation2/system/TurnManager.h" @@ -41,16 +41,16 @@ 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) 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) LOGERROR("Failed to save game"); } @@ -101,8 +101,7 @@ CSimulation2* sim = g_Game->GetSimulation2(); ScriptRequest rqGame(sim->GetScriptInterface()); - JS::RootedValue gameContextMetadata(rqGame.cx, - sim->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, guiContextMetadata)); + JS::RootedValue gameContextMetadata(rqGame.cx, Script::CloneValueFromOtherCompartment(sim->GetScriptInterface(), scriptInterface, guiContextMetadata)); JS::RootedValue gameInitAttributes(rqGame.cx); sim->GetScriptInterface().GetProperty(gameContextMetadata, "initAttributes", &gameInitAttributes); Index: ps/trunk/source/rlinterface/RLInterface.cpp =================================================================== --- ps/trunk/source/rlinterface/RLInterface.cpp +++ ps/trunk/source/rlinterface/RLInterface.cpp @@ -26,6 +26,7 @@ #include "ps/Game.h" #include "ps/GameSetup/GameSetup.h" #include "ps/Loader.h" +#include "scriptinterface/ScriptInterface.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpAIInterface.h" #include "simulation2/components/ICmpTemplateManager.h" Index: ps/trunk/source/scriptinterface/ScriptContext.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptContext.h +++ ps/trunk/source/scriptinterface/ScriptContext.h @@ -34,7 +34,7 @@ * should only be used on a single thread. * * (One means to share data between threads and contexts is to create - * a ScriptInterface::StructuredClone.) + * a Script::StructuredClone.) */ class ScriptContext Index: ps/trunk/source/scriptinterface/ScriptExtraHeaders.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptExtraHeaders.h +++ ps/trunk/source/scriptinterface/ScriptExtraHeaders.h @@ -58,7 +58,6 @@ #include "js/GCHashTable.h" #include "js/JSON.h" #include "js/SourceText.h" -#include "js/StructuredClone.h" #include "js/Proxy.h" #include "js/Warnings.h" Index: ps/trunk/source/scriptinterface/ScriptInterface.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptInterface.h +++ ps/trunk/source/scriptinterface/ScriptInterface.h @@ -48,8 +48,6 @@ // but as large as necessary for all wrapped functions) #define SCRIPT_INTERFACE_MAX_ARGS 8 -class JSStructuredCloneData; - class ScriptInterface; struct ScriptInterface_impl; @@ -315,26 +313,6 @@ 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; - - 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. */ template Index: ps/trunk/source/scriptinterface/ScriptInterface.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptInterface.cpp +++ ps/trunk/source/scriptinterface/ScriptInterface.cpp @@ -22,6 +22,7 @@ #include "ScriptExtraHeaders.h" #include "ScriptInterface.h" #include "ScriptStats.h" +#include "StructuredClone.h" #include "lib/debug.h" #include "lib/utf8.h" @@ -187,8 +188,8 @@ return JS::UndefinedValue(); } - JS::RootedValue ret(rq.cx); - if (!JS_StructuredClone(rq.cx, val, &ret, NULL, NULL)) + JS::RootedValue ret(rq.cx, Script::DeepCopy(rq, val)); + if (ret.isNullOrUndefined()) { ScriptException::Raise(rq, "deepcopy StructureClone copy failed."); return JS::UndefinedValue(); @@ -343,7 +344,7 @@ ScriptRequest rq(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() @@ -362,7 +363,7 @@ ScriptInterface::CmptPrivate* ScriptInterface::GetScriptInterfaceAndCBData(JSContext* cx) { - CmptPrivate* pCmptPrivate = (CmptPrivate*)JS_GetCompartmentPrivate(js::GetContextCompartment(cx)); + CmptPrivate* pCmptPrivate = (CmptPrivate*)JS::GetRealmPrivate(JS::GetCurrentRealmOrNull(cx)); return pCmptPrivate; } @@ -963,36 +964,3 @@ ScriptFunction::Call(rq, obj, "toSource", 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); -} Index: ps/trunk/source/scriptinterface/StructuredClone.h =================================================================== --- ps/trunk/source/scriptinterface/StructuredClone.h +++ ps/trunk/source/scriptinterface/StructuredClone.h @@ -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 . + */ + +#ifndef INCLUDED_SCRIPTINTERFACE_STRUCTUREDCLONE +#define INCLUDED_SCRIPTINTERFACE_STRUCTUREDCLONE + +#include "ScriptForward.h" + +#include + +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; + +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 Index: ps/trunk/source/scriptinterface/StructuredClone.cpp =================================================================== --- ps/trunk/source/scriptinterface/StructuredClone.cpp +++ ps/trunk/source/scriptinterface/StructuredClone.cpp @@ -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 . + */ + +#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(); +} Index: ps/trunk/source/scriptinterface/tests/test_ScriptInterface.h =================================================================== --- ps/trunk/source/scriptinterface/tests/test_ScriptInterface.h +++ ps/trunk/source/scriptinterface/tests/test_ScriptInterface.h @@ -19,6 +19,7 @@ #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include "ps/CLogger.h" @@ -73,7 +74,7 @@ { 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; TS_ASSERT(ScriptFunction::Call(rq2, obj2, "toSource", source)); @@ -95,7 +96,7 @@ { 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; TS_ASSERT(ScriptFunction::Call(rq2, obj2, "toSource", source)); @@ -115,7 +116,7 @@ { 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] JS::RootedValue prop_a(rq2.cx); @@ -244,7 +245,7 @@ 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. void test_function_override() { Index: ps/trunk/source/simulation2/Simulation2.cpp =================================================================== --- ps/trunk/source/simulation2/Simulation2.cpp +++ ps/trunk/source/simulation2/Simulation2.cpp @@ -22,6 +22,7 @@ #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include "simulation2/MessageTypes.h" #include "simulation2/system/ComponentManager.h" @@ -161,7 +162,7 @@ void InitRNGSeedSimulation(); void InitRNGSeedAI(); - static std::vector CloneCommandsFromOtherCompartment(const ScriptInterface& oldScript, const ScriptInterface& newScript, + static std::vector CloneCommandsFromOtherCompartment(const ScriptInterface& newScript, const ScriptInterface& oldScript, const std::vector& commands) { std::vector newCommands; @@ -170,7 +171,7 @@ ScriptRequest rqNew(newScript); 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); SimulationCommand cmd(command.player, rqNew.cx, tmpCommand); newCommands.emplace_back(std::move(cmd)); @@ -414,9 +415,9 @@ // Load the trigger scripts after we have loaded the simulation. { + ScriptRequest rq(scriptInterface); ScriptRequest rq2(m_SecondaryComponentManager->GetScriptInterface()); - JS::RootedValue mapSettingsCloned(rq2.cx, - m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, m_MapSettings)); + JS::RootedValue mapSettingsCloned(rq2.cx, Script::CloneValueFromOtherCompartment(m_SecondaryComponentManager->GetScriptInterface(), scriptInterface, m_MapSettings)); ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts.get())); } @@ -469,7 +470,7 @@ ENSURE(m_ComponentManager.ComputeStateHash(primaryStateAfter.hash, false)); UpdateComponents(*m_SecondaryContext, turnLengthFixed, - CloneCommandsFromOtherCompartment(scriptInterface, m_SecondaryComponentManager->GetScriptInterface(), commands)); + CloneCommandsFromOtherCompartment(m_SecondaryComponentManager->GetScriptInterface(), scriptInterface, commands)); SerializationTestState secondaryStateAfter; ENSURE(m_SecondaryComponentManager->SerializeState(secondaryStateAfter.state)); if (serializationTestHash) Index: ps/trunk/source/simulation2/components/CCmpAIManager.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpAIManager.cpp +++ ps/trunk/source/simulation2/components/CCmpAIManager.cpp @@ -34,6 +34,7 @@ #include "ps/Util.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptContext.h" +#include "scriptinterface/StructuredClone.h" #include "simulation2/components/ICmpAIInterface.h" #include "simulation2/components/ICmpCommandQueue.h" #include "simulation2/components/ICmpObstructionManager.h" @@ -67,7 +68,7 @@ * will block until it's actually completed, so the rest of the engine should avoid * 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 * sufficiently problematic to justify the complexity yet, but the CAIWorker interface @@ -204,14 +205,14 @@ shared_ptr m_ScriptInterface; JS::PersistentRootedValue m_Obj; - std::vector m_Commands; + std::vector m_Commands; }; public: struct SCommandSets { player_id_t player; - std::vector commands; + std::vector commands; }; CAIWorker() : @@ -291,11 +292,12 @@ void PostCommand(int playerid, JS::HandleValue cmd) { + ScriptRequest rq(m_ScriptInterface); for (size_t i=0; im_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; } } @@ -465,7 +467,7 @@ return true; } - bool RunGamestateInit(const ScriptInterface::StructuredClone& gameState, const Grid& passabilityMap, const Grid& territoryMap, + bool RunGamestateInit(const Script::StructuredClone& gameState, const Grid& passabilityMap, const Grid& territoryMap, const std::map& nonPathfindingPassClassMasks, const std::map& pathfindingPassClassMasks) { // this will be run last by InitGame.js, passing the full game representation. @@ -474,7 +476,7 @@ ScriptRequest rq(m_ScriptInterface); 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_TerritoryMapVal, territoryMap); @@ -501,7 +503,7 @@ return true; } - void UpdateGameState(const ScriptInterface::StructuredClone& gameState) + void UpdateGameState(const Script::StructuredClone& gameState) { ENSURE(m_CommandsComputed); m_GameState = gameState; @@ -661,7 +663,7 @@ for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j) { 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); } @@ -726,7 +728,7 @@ { JS::RootedValue val(rq.cx); 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); @@ -780,7 +782,7 @@ JS::RootedValue state(rq.cx); { 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, "territoryMap", m_TerritoryMapVal, true); } @@ -831,7 +833,7 @@ std::set m_LoadedModules; - ScriptInterface::StructuredClone m_GameState; + Script::StructuredClone m_GameState; Grid m_PassabilityMap; JS::PersistentRootedValue m_PassabilityMapVal; Grid m_TerritoryMap; @@ -959,7 +961,7 @@ if (cmpPathfinder) cmpPathfinder->GetPassabilityClasses(nonPathfindingPassClassMasks, pathfindingPassClassMasks); - m_Worker.RunGamestateInit(scriptInterface.WriteStructuredClone(state), + m_Worker.RunGamestateInit(Script::WriteStructuredClone(rq, state), *passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks); } @@ -985,7 +987,7 @@ LoadPathfinderClasses(state); // add the pathfinding classes to it // Update the game state - m_Worker.UpdateGameState(scriptInterface.WriteStructuredClone(state)); + m_Worker.UpdateGameState(Script::WriteStructuredClone(rq, state)); // Update the pathfinding data CmpPtr cmpPathfinder(GetSystemEntity()); @@ -1039,7 +1041,7 @@ { 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); } } Index: ps/trunk/source/simulation2/scripting/JSInterface_Simulation.cpp =================================================================== --- ps/trunk/source/simulation2/scripting/JSInterface_Simulation.cpp +++ ps/trunk/source/simulation2/scripting/JSInterface_Simulation.cpp @@ -26,6 +26,7 @@ #include "ps/Pyrogenesis.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptInterface.h" +#include "scriptinterface/StructuredClone.h" #include "simulation2/components/ICmpAIManager.h" #include "simulation2/components/ICmpCommandQueue.h" #include "simulation2/components/ICmpGuiInterface.h" @@ -55,11 +56,11 @@ return JS::UndefinedValue(); 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); 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) @@ -75,8 +76,7 @@ return; ScriptRequest rqSim(sim->GetScriptInterface()); - JS::RootedValue cmd2(rqSim.cx, - sim->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, cmd)); + JS::RootedValue cmd2(rqSim.cx, Script::CloneValueFromOtherCompartment(sim->GetScriptInterface(), scriptInterface, cmd)); cmpCommandQueue->PostNetworkCommand(cmd2); } Index: ps/trunk/source/simulation2/system/ReplayTurnManager.cpp =================================================================== --- ps/trunk/source/simulation2/system/ReplayTurnManager.cpp +++ ps/trunk/source/simulation2/system/ReplayTurnManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* 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 @@ -22,6 +22,7 @@ #include "gui/GUIManager.h" #include "ps/CLogger.h" #include "ps/Util.h" +#include "scriptinterface/ScriptInterface.h" #include "simulation2/Simulation2.h" const CStr CReplayTurnManager::EventNameReplayFinished = "ReplayFinished"; @@ -94,11 +95,11 @@ ignore_result(paramData.append(JS::NumberValue(turn))); JS::RootedValue hashVal(rq.cx); - scriptInterface.ToJSVal(rq, &hashVal, hash); + ScriptInterface::ToJSVal(rq, &hashVal, hash); ignore_result(paramData.append(hashVal)); JS::RootedValue expectedHashVal(rq.cx); - scriptInterface.ToJSVal(rq, &expectedHashVal, expectedHash); + ScriptInterface::ToJSVal(rq, &expectedHashVal, expectedHash); ignore_result(paramData.append(expectedHashVal)); g_GUI->SendEventToAll(EventNameReplayOutOfSync, paramData); Index: ps/trunk/source/simulation2/system/TurnManager.cpp =================================================================== --- ps/trunk/source/simulation2/system/TurnManager.cpp +++ ps/trunk/source/simulation2/system/TurnManager.cpp @@ -292,16 +292,9 @@ ScriptRequest rq(m_Simulation2.GetScriptInterface()); - if (JS_StructuredClone(rq.cx, GUIMetadata, &m_QuickSaveMetadata, nullptr, nullptr)) - { - // Freeze state to ensure that consectuvie loads don't modify the state - m_Simulation2.GetScriptInterface().FreezeObject(m_QuickSaveMetadata, true); - } - else - { - LOGERROR("Could not copy savegame GUI metadata"); - m_QuickSaveMetadata = JS::UndefinedValue(); - } + m_QuickSaveMetadata.set(Script::DeepCopy(rq, GUIMetadata)); + // Freeze state to ensure that consectuvie loads don't modify the state + m_Simulation2.GetScriptInterface().FreezeObject(m_QuickSaveMetadata, true); LOGMESSAGERENDER("Quicksaved game"); } @@ -332,12 +325,7 @@ ScriptRequest rq(m_Simulation2.GetScriptInterface()); // Provide a copy, so that GUI components don't have to clone to get mutable objects - JS::RootedValue quickSaveMetadataClone(rq.cx); - if (!JS_StructuredClone(rq.cx, m_QuickSaveMetadata, &quickSaveMetadataClone, nullptr, nullptr)) - { - LOGERROR("Failed to clone quicksave state!"); - return; - } + JS::RootedValue quickSaveMetadataClone(rq.cx, Script::DeepCopy(rq, m_QuickSaveMetadata)); JS::RootedValueArray<1> paramData(rq.cx); paramData[0].set(quickSaveMetadataClone); Index: ps/trunk/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp =================================================================== --- ps/trunk/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp +++ ps/trunk/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* 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 @@ -35,6 +35,7 @@ #include "ps/GameSetup/Config.h" #include "ps/GameSetup/GameSetup.h" #include "renderer/Renderer.h" +#include "scriptinterface/ScriptInterface.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpSoundManager.h"