Index: ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js +++ ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js @@ -82,17 +82,3 @@ Engine.ResetCursor(); } - -/** - * Also called from the C++ side when ending the game. - * The current page can be the summary screen or a message box, so it can't be moved to session/. - */ -function getReplayMetadata() -{ - let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState"); - return { - "timeElapsed": extendedSimState.timeElapsed, - "playerStates": extendedSimState.players, - "mapSettings": Engine.GetInitAttributes().settings - }; -} Index: ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json =================================================================== --- ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json +++ ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json @@ -109,6 +109,7 @@ {"nick": "idanwin"}, {"nick": "Imarok", "name": "J. S."}, {"nick": "infyquest", "name": "Vijay Kiran Kamuju"}, + {"nick": "irishninja", "name": "Brian Broll"}, {"nick": "IronNerd", "name": "Matthew McMullan"}, {"nick": "Itms", "name": "Nicolas Auvray"}, {"nick": "Jaison", "name": "Marco tom Suden"}, Index: ps/trunk/binaries/data/mods/public/gui/session/session.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/session.js +++ ps/trunk/binaries/data/mods/public/gui/session/session.js @@ -42,7 +42,7 @@ /** * Map, player and match settings set in gamesetup. */ -const g_GameAttributes = deepfreeze(Engine.GetInitAttributes()); +const g_GameAttributes = deepfreeze(Engine.GuiInterfaceCall("GetInitAttributes")); /** * True if this is a multiplayer game. @@ -733,7 +733,7 @@ // Before ending the game let replayDirectory = Engine.GetCurrentReplayDirectory(); - let simData = getReplayMetadata(); + let simData = Engine.GuiInterfaceCall("GetReplayMetadata"); let playerID = Engine.GetPlayerID(); Engine.EndGame(); Index: ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js +++ ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js @@ -191,6 +191,27 @@ return ret; }; +/** + * Returns the gamesettings that were chosen at the time the match started. + */ +GuiInterface.prototype.GetInitAttributes = function() +{ + return InitAttributes; +}; + +/** + * This data will be stored in the replay metadata file after a match has been finished recording. + */ +GuiInterface.prototype.GetReplayMetadata = function() +{ + let extendedSimState = this.GetExtendedSimulationState(); + return { + "timeElapsed": extendedSimState.timeElapsed, + "playerStates": extendedSimState.players, + "mapSettings": InitAttributes.settings + }; +}; + GuiInterface.prototype.GetRenamedEntities = function(player) { if (this.miragedEntities[player]) @@ -1917,6 +1938,8 @@ "GetSimulationState": 1, "GetExtendedSimulationState": 1, + "GetInitAttributes": 1, + "GetReplayMetadata": 1, "GetRenamedEntities": 1, "ClearRenamedEntities": 1, "GetEntityState": 1, Index: ps/trunk/source/ps/Game.cpp =================================================================== --- ps/trunk/source/ps/Game.cpp +++ ps/trunk/source/ps/Game.cpp @@ -102,6 +102,9 @@ if (CProfileManager::IsInitialised()) g_Profiler.StructuralReset(); + if (m_ReplayLogger) + m_ReplayLogger->SaveMetadata(*m_Simulation2); + delete m_TurnManager; delete m_GameView; delete m_Simulation2; Index: ps/trunk/source/ps/GameSetup/GameSetup.cpp =================================================================== --- ps/trunk/source/ps/GameSetup/GameSetup.cpp +++ ps/trunk/source/ps/GameSetup/GameSetup.cpp @@ -701,10 +701,6 @@ void EndGame() { - if (g_Game && g_Game->IsGameStarted() && !g_Game->IsVisualReplay() && - g_AtlasGameLoop && !g_AtlasGameLoop->running && CRenderer::IsInitialised()) - VisualReplay::SaveReplayMetadata(g_GUI->GetActiveGUI()->GetScriptInterface().get()); - SAFE_DELETE(g_NetClient); SAFE_DELETE(g_NetServer); SAFE_DELETE(g_Game); Index: ps/trunk/source/ps/Replay.h =================================================================== --- ps/trunk/source/ps/Replay.h +++ ps/trunk/source/ps/Replay.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 @@ -22,6 +22,7 @@ #include "scriptinterface/ScriptTypes.h" struct SimulationCommand; +class CSimulation2; class ScriptInterface; /** @@ -50,6 +51,11 @@ virtual void Hash(const std::string& hash, bool quick) = 0; /** + * Saves metadata.json containing part of the simulation state used for the summary screen. + */ + virtual void SaveMetadata(const CSimulation2& simulation) = 0; + + /** * Remember the directory containing the commands.txt file, so that we can save additional files to it. */ virtual OsPath GetDirectory() const = 0; @@ -64,6 +70,7 @@ virtual void StartGame(JS::MutableHandleValue UNUSED(attribs)) { } virtual void Turn(u32 UNUSED(n), u32 UNUSED(turnLength), std::vector& UNUSED(commands)) { } virtual void Hash(const std::string& UNUSED(hash), bool UNUSED(quick)) { } + virtual void SaveMetadata(const CSimulation2& UNUSED(simulation)) { }; virtual OsPath GetDirectory() const { return OsPath(); } }; @@ -80,6 +87,7 @@ virtual void StartGame(JS::MutableHandleValue attribs); virtual void Turn(u32 n, u32 turnLength, std::vector& commands); virtual void Hash(const std::string& hash, bool quick); + virtual void SaveMetadata(const CSimulation2& simulation); virtual OsPath GetDirectory() const; private: Index: ps/trunk/source/ps/Replay.cpp =================================================================== --- ps/trunk/source/ps/Replay.cpp +++ ps/trunk/source/ps/Replay.cpp @@ -37,8 +37,11 @@ #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptRuntime.h" #include "scriptinterface/ScriptStats.h" -#include "simulation2/Simulation2.h" +#include "simulation2/components/ICmpGuiInterface.h" +#include "simulation2/helpers/Player.h" #include "simulation2/helpers/SimulationCommand.h" +#include "simulation2/Simulation2.h" +#include "simulation2/system/CmpPtr.h" #include #include @@ -101,6 +104,32 @@ *m_Stream << "hash " << Hexify(hash) << "\n"; } +void CReplayLogger::SaveMetadata(const CSimulation2& simulation) +{ + CmpPtr cmpGuiInterface(simulation, SYSTEM_ENTITY); + if (!cmpGuiInterface) + { + LOGERROR("Could not save replay metadata!"); + return; + } + + ScriptInterface& scriptInterface = simulation.GetScriptInterface(); + JSContext* cx = scriptInterface.GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue arg(cx); + JS::RootedValue metadata(cx); + cmpGuiInterface->ScriptCall(INVALID_PLAYER, L"GetReplayMetadata", arg, &metadata); + + const OsPath fileName = g_Game->GetReplayLogger().GetDirectory() / L"metadata.json"; + CreateDirectories(fileName.Parent(), 0700); + + std::ofstream stream (OsString(fileName).c_str(), std::ofstream::out | std::ofstream::trunc); + stream << scriptInterface.StringifyJSON(&metadata, false); + stream.close(); + debug_printf("Saved replay metadata to %s\n", fileName.string8().c_str()); +} + OsPath CReplayLogger::GetDirectory() const { return m_Directory; Index: ps/trunk/source/ps/VisualReplay.h =================================================================== --- ps/trunk/source/ps/VisualReplay.h +++ ps/trunk/source/ps/VisualReplay.h @@ -115,11 +115,6 @@ JS::Value GetReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate, const OsPath& directoryName); /** - * Saves the metadata from the session to metadata.json. - */ -void SaveReplayMetadata(ScriptInterface* scriptInterface); - -/** * Adds a replay to the replayCache. */ void AddReplayToCache(const ScriptInterface& scriptInterface, const CStrW& directoryName); Index: ps/trunk/source/ps/VisualReplay.cpp =================================================================== --- ps/trunk/source/ps/VisualReplay.cpp +++ ps/trunk/source/ps/VisualReplay.cpp @@ -473,30 +473,6 @@ StoreCacheFile(scriptInterface, cachedReplaysObject); } -void VisualReplay::SaveReplayMetadata(ScriptInterface* scriptInterface) -{ - JSContext* cx = scriptInterface->GetContext(); - JSAutoRequest rq(cx); - - JS::RootedValue metadata(cx); - JS::RootedValue global(cx, scriptInterface->GetGlobalObject()); - - if (!scriptInterface->CallFunction(global, "getReplayMetadata", &metadata)) - { - LOGERROR("Could not save replay metadata!"); - return; - } - - // Get the directory of the currently active replay - const OsPath fileName = g_Game->GetReplayLogger().GetDirectory() / L"metadata.json"; - CreateDirectories(fileName.Parent(), 0700); - - std::ofstream stream (OsString(fileName).c_str(), std::ofstream::out | std::ofstream::trunc); - stream << scriptInterface->StringifyJSON(&metadata, false); - stream.close(); - debug_printf("Saved replay metadata to %s\n", fileName.string8().c_str()); -} - bool VisualReplay::HasReplayMetadata(const OsPath& directoryName) { const OsPath filePath(GetDirectoryPath() / directoryName / L"metadata.json"); Index: ps/trunk/source/simulation2/Simulation2.cpp =================================================================== --- ps/trunk/source/simulation2/Simulation2.cpp +++ ps/trunk/source/simulation2/Simulation2.cpp @@ -861,6 +861,9 @@ // Initialize here instead of in Update() GetScriptInterface().CallFunctionVoid(global, "LoadMapSettings", m->m_MapSettings); + GetScriptInterface().FreezeObject(m->m_InitAttributes, true); + GetScriptInterface().SetGlobal("InitAttributes", m->m_InitAttributes, true, true, true); + if (!m->m_StartupScript.empty()) GetScriptInterface().LoadScript(L"map startup script", m->m_StartupScript); Index: ps/trunk/source/simulation2/scripting/JSInterface_Simulation.h =================================================================== --- ps/trunk/source/simulation2/scripting/JSInterface_Simulation.h +++ ps/trunk/source/simulation2/scripting/JSInterface_Simulation.h @@ -23,7 +23,6 @@ namespace JSI_Simulation { - JS::Value GetInitAttributes(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GuiInterfaceCall(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue data); void PostNetworkCommand(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue cmd); entity_id_t PickEntityAtPoint(ScriptInterface::CxPrivate* pCxPrivate, int x, int y); 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 @@ -34,22 +34,6 @@ #include -JS::Value JSI_Simulation::GetInitAttributes(ScriptInterface::CxPrivate* pCxPrivate) -{ - if (!g_Game) - return JS::UndefinedValue(); - - JSContext* cx = g_Game->GetSimulation2()->GetScriptInterface().GetContext(); - JSAutoRequest rq(cx); - - JS::RootedValue initAttribs(cx); - g_Game->GetSimulation2()->GetInitAttributes(&initAttribs); - - return pCxPrivate->pScriptInterface->CloneValueFromOtherContext( - g_Game->GetSimulation2()->GetScriptInterface(), - initAttribs); -} - JS::Value JSI_Simulation::GuiInterfaceCall(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue data) { if (!g_Game) @@ -147,7 +131,6 @@ void JSI_Simulation::RegisterScriptFunctions(const ScriptInterface& scriptInterface) { - scriptInterface.RegisterFunction("GetInitAttributes"); scriptInterface.RegisterFunction("GuiInterfaceCall"); scriptInterface.RegisterFunction("PostNetworkCommand"); scriptInterface.RegisterFunction("DumpSimState");