diff --git a/binaries/data/mods/public/gui/savegame/save.js b/binaries/data/mods/public/gui/savegame/save.js index 1325e7750e..4814034e1d 100644 --- a/binaries/data/mods/public/gui/savegame/save.js +++ b/binaries/data/mods/public/gui/savegame/save.js @@ -82,10 +82,3 @@ function closeSave() { Engine.PopGuiPage(); } - -// HACK: Engine.SaveGame* expects this function to be defined on the current page. -// That's why we have to pass the data to this page even if we don't need it. -function getSavedGameData() -{ - return g_SavedGameData; -} diff --git a/binaries/data/mods/public/gui/session/hotkeys/misc.xml b/binaries/data/mods/public/gui/session/hotkeys/misc.xml index 28c3b17288..89f96d65be 100644 --- a/binaries/data/mods/public/gui/session/hotkeys/misc.xml +++ b/binaries/data/mods/public/gui/session/hotkeys/misc.xml @@ -56,7 +56,7 @@ - Engine.QuickSave(); + Engine.QuickSave(getSavedGameData()); diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml index dbecc7b75f..a41d83ab79 100644 --- a/binaries/data/mods/public/gui/session/session.xml +++ b/binaries/data/mods/public/gui/session/session.xml @@ -15,6 +15,10 @@ onWindowResized(); + + restoreSavedGameData(arguments[0]); + + onSimulationUpdate(); diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index f6fb9f479c..be59e24dc3 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -290,30 +290,6 @@ void CGUIManager::ResetCursor() g_CursorName = g_DefaultCursor; } -std::string CGUIManager::GetSavedGameData() -{ - shared_ptr scriptInterface = top()->GetScriptInterface(); - JSContext* cx = scriptInterface->GetContext(); - JSAutoRequest rq(cx); - - JS::RootedValue data(cx); - JS::RootedValue global(cx, top()->GetGlobalObject()); - scriptInterface->CallFunction(global, "getSavedGameData", &data); - return scriptInterface->StringifyJSON(&data, false); -} - -void CGUIManager::RestoreSavedGameData(const std::string& jsonData) -{ - shared_ptr scriptInterface = top()->GetScriptInterface(); - JSContext* cx = scriptInterface->GetContext(); - JSAutoRequest rq(cx); - - JS::RootedValue global(cx, top()->GetGlobalObject()); - JS::RootedValue dataVal(cx); - scriptInterface->ParseJSON(jsonData, &dataVal); - scriptInterface->CallFunctionVoid(global, "restoreSavedGameData", dataVal); -} - InReaction CGUIManager::HandleEvent(const SDL_Event_* ev) { // We want scripts to have access to the raw input events, so they can do complex diff --git a/source/gui/GUIManager.h b/source/gui/GUIManager.h index 7cd9d2e24f..9dacb601bf 100644 --- a/source/gui/GUIManager.h +++ b/source/gui/GUIManager.h @@ -122,13 +122,6 @@ public: */ void UpdateResolution(); - /** - * Calls the current page's script function getSavedGameData() and returns the result. - */ - std::string GetSavedGameData(); - - void RestoreSavedGameData(const std::string& jsonData); - /** * Check if a template with this name exists */ diff --git a/source/ps/scripting/JSInterface_SavedGame.cpp b/source/ps/scripting/JSInterface_SavedGame.cpp index 47c76650ec..1c3fff57b7 100644 --- a/source/ps/scripting/JSInterface_SavedGame.cpp +++ b/source/ps/scripting/JSInterface_SavedGame.cpp @@ -52,14 +52,20 @@ void JSI_SavedGame::SaveGamePrefix(ScriptInterface::CxPrivate* pCxPrivate, const LOGERROR("Failed to save game"); } -void JSI_SavedGame::QuickSave(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) +void JSI_SavedGame::QuickSave(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), JS::HandleValue GUIMetadata) { - g_Game->GetTurnManager()->QuickSave(); + if (g_Game) + g_Game->GetTurnManager()->QuickSave(GUIMetadata); + else + LOGERROR("Can't store quicksave if game is not running!"); } void JSI_SavedGame::QuickLoad(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) { - g_Game->GetTurnManager()->QuickLoad(); + if (g_Game) + g_Game->GetTurnManager()->QuickLoad(); + else + LOGERROR("Can't load quicksave if game is not running!"); } JS::Value JSI_SavedGame::StartSavedGame(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name) @@ -111,7 +117,7 @@ void JSI_SavedGame::RegisterScriptFunctions(const ScriptInterface& scriptInterfa scriptInterface.RegisterFunction("DeleteSavedGame"); scriptInterface.RegisterFunction("SaveGame"); scriptInterface.RegisterFunction("SaveGamePrefix"); - scriptInterface.RegisterFunction("QuickSave"); + scriptInterface.RegisterFunction("QuickSave"); scriptInterface.RegisterFunction("QuickLoad"); scriptInterface.RegisterFunction("StartSavedGame"); } diff --git a/source/ps/scripting/JSInterface_SavedGame.h b/source/ps/scripting/JSInterface_SavedGame.h index 7eed8f992b..532947ef28 100644 --- a/source/ps/scripting/JSInterface_SavedGame.h +++ b/source/ps/scripting/JSInterface_SavedGame.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,7 +26,7 @@ namespace JSI_SavedGame bool DeleteSavedGame(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name); void SaveGame(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename, const std::wstring& description, JS::HandleValue GUIMetadata); void SaveGamePrefix(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& prefix, const std::wstring& description, JS::HandleValue GUIMetadata); - void QuickSave(ScriptInterface::CxPrivate* pCxPrivate); + void QuickSave(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue GUIMetadata); void QuickLoad(ScriptInterface::CxPrivate* pCxPrivate); JS::Value StartSavedGame(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name); diff --git a/source/simulation2/system/TurnManager.cpp b/source/simulation2/system/TurnManager.cpp index d147eb04c3..c9965ad7f7 100644 --- a/source/simulation2/system/TurnManager.cpp +++ b/source/simulation2/system/TurnManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -43,7 +43,8 @@ const int COMMAND_DELAY = 2; CTurnManager::CTurnManager(CSimulation2& simulation, u32 defaultTurnLength, int clientId, IReplayLogger& replay) : m_Simulation2(simulation), m_CurrentTurn(0), m_ReadyTurn(1), m_TurnLength(defaultTurnLength), m_PlayerId(-1), m_ClientId(clientId), m_DeltaSimTime(0), m_HasSyncError(false), m_Replay(replay), - m_FinalTurn(std::numeric_limits::max()), m_TimeWarpNumTurns(0) + m_FinalTurn(std::numeric_limits::max()), m_TimeWarpNumTurns(0), + m_QuickSaveMetadata(m_Simulation2.GetScriptInterface().GetContext()) { // When we are on turn n, we schedule new commands for n+2. // We know that all other clients have finished scheduling commands for n (else we couldn't have got here). @@ -290,7 +291,7 @@ void CTurnManager::RewindTimeWarp() ResetState(0, 1); } -void CTurnManager::QuickSave() +void CTurnManager::QuickSave(JS::HandleValue GUIMetadata) { TIMER(L"QuickSave"); @@ -302,13 +303,21 @@ void CTurnManager::QuickSave() } m_QuickSaveState = stream.str(); - if (g_GUI) - m_QuickSaveMetadata = g_GUI->GetSavedGameData(); + + JSContext* cx = m_Simulation2.GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + + if (JS_StructuredClone(cx, GUIMetadata, &m_QuickSaveMetadata, nullptr, nullptr)) + { + m_Simulation2.GetScriptInterface().FreezeObject(m_QuickSaveMetadata, true); + } else - m_QuickSaveMetadata = std::string(); + { + LOGERROR("Could not copy savegame GUI metadata"); + m_QuickSaveMetadata = JS::UndefinedValue(); + } LOGMESSAGERENDER("Quicksaved game"); - } void CTurnManager::QuickLoad() @@ -328,11 +337,18 @@ void CTurnManager::QuickLoad() return; } - if (g_GUI && !m_QuickSaveMetadata.empty()) - g_GUI->RestoreSavedGameData(m_QuickSaveMetadata); - - LOGMESSAGERENDER("Quickloaded game"); - // See RewindTimeWarp ResetState(0, 1); + + if (!g_GUI) + return; + + JSContext* cx = m_Simulation2.GetScriptInterface().GetContext(); + JSAutoRequest rq(cx); + + JS::AutoValueArray<1> paramData(cx); + paramData[0].set(m_QuickSaveMetadata); + g_GUI->SendEventToAll("SavegameLoaded", paramData); + + LOGMESSAGERENDER("Quickloaded game"); } diff --git a/source/simulation2/system/TurnManager.h b/source/simulation2/system/TurnManager.h index 92d228785d..10bf4372cd 100644 --- a/source/simulation2/system/TurnManager.h +++ b/source/simulation2/system/TurnManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -130,7 +130,7 @@ public: */ void RewindTimeWarp(); - void QuickSave(); + void QuickSave(JS::HandleValue GUIMetadata); void QuickLoad(); u32 GetCurrentTurn() { return m_CurrentTurn; } @@ -189,7 +189,7 @@ private: size_t m_TimeWarpNumTurns; // 0 if disabled std::list m_TimeWarpStates; std::string m_QuickSaveState; // TODO: should implement a proper disk-based quicksave system - std::string m_QuickSaveMetadata; + JS::PersistentRootedValue m_QuickSaveMetadata; }; #endif // INCLUDED_TURNMANAGER