Ticket #9: t0009_visualreplay_v2_16707.patch

File t0009_visualreplay_v2_16707.patch, 21.8 KB (added by elexis, 9 years ago)

Cleaner code; quits early if file doesn't exist; displays popup on oos; clean exit when finished replaying.

  • binaries/data/mods/public/gui/session/session.js

     
    555555        if (battleState)
    556556            global.music.setState(global.music.states[battleState]);
    557557    }
    558558}
    559559
     560function onReplayFinished()
     561{
     562    closeMenu();
     563    closeOpenDialogs();
     564    pauseGame();
     565    var btCaptions = ["Yes", "No"];
     566    var btCode = [leaveGame, resumeGame];
     567    messageBox(400, 200, "The replay has finished. Do you want to quit?", "Confirmation", 0, btCaptions, btCode);
     568}
     569
    560570/**
    561571* updates a status bar on the GUI
    562572* nameOfBar: name of the bar
    563573* points: points to show
    564574* maxPoints: max points
  • binaries/data/mods/public/gui/session/session.xml

     
    2020
    2121    <action on="SimulationUpdate">
    2222        onSimulationUpdate();
    2323    </action>
    2424
     25    <action on="ReplayFinished">
     26        onReplayFinished();
     27    </action>
     28
    2529    <action on="Press">
    2630        this.hidden = !this.hidden;
    2731    </action>
    2832
    2933    <!-- ================================  ================================ -->
  • source/main.cpp

     
    440440        return;
    441441
    442442    // run non-visual simulation replay if requested
    443443    if (args.Has("replay"))
    444444    {
     445        std::string replayFile = args.Get("replay");
     446        if (!FileExists(OsPath(replayFile)))
     447        {
     448            debug_printf("ERROR: The requested replay file '%s' does not exist!\n", replayFile.c_str());
     449            return;
     450        }
    445451        Paths paths(args);
    446452        g_VFS = CreateVfs(20 * MiB);
    447453        g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE);
    448454        MountMods(paths, GetMods(args, INIT_MODS));
    449455
    450456        {
    451457            CReplayPlayer replay;
    452             replay.Load(args.Get("replay"));
     458            replay.Load(replayFile);
    453459            replay.Replay(args.Has("serializationtest"), args.Has("ooslog"));
    454460        }
    455461
    456462        g_VFS.reset();
    457463
    458464        CXeromyces::Terminate();
    459465        return;
    460466    }
    461467
     468    // If visual replay file does not exist, quit before starting the renderer
     469    if (args.Has("replay-visual"))
     470    {
     471        std::string replayFile = args.Get("replay-visual");
     472        if (!FileExists(OsPath(replayFile)))
     473        {
     474            debug_printf("ERROR: The requested replay file '%s' does not exist!\n", replayFile.c_str());
     475            return;
     476        }
     477    }
     478
     479
    462480    // run in archive-building mode if requested
    463481    if (args.Has("archivebuild"))
    464482    {
    465483        Paths paths(args);
    466484
  • source/network/NetTurnManager.cpp

     
    2929#include "ps/Profile.h"
    3030#include "ps/Pyrogenesis.h"
    3131#include "ps/Replay.h"
    3232#include "ps/SavedGame.h"
    3333#include "scriptinterface/ScriptInterface.h"
     34#include "simulation2/helpers/Player.h"
    3435#include "simulation2/Simulation2.h"
    3536
    3637#include <sstream>
    3738#include <fstream>
    3839#include <iomanip>
     
    227228        return;
    228229    m_HasSyncError = true;
    229230
    230231    bool quick = !TurnNeedsFullHash(turn);
    231232    std::string hash;
    232     bool ok = m_Simulation2.ComputeStateHash(hash, quick);
    233     ENSURE(ok);
     233    ENSURE(m_Simulation2.ComputeStateHash(hash, quick));
    234234
    235235    OsPath path = psLogDir()/"oos_dump.txt";
    236236    std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc);
    237237    m_Simulation2.DumpDebugState(file);
    238238    file.close();
    239239
     240    hash = Hexify(hash);
     241    const std::string& expectedHashHex = Hexify(expectedHash);
     242
     243    DisplayOOSError(turn, hash, expectedHashHex, false, &path);
     244}
     245
     246void CNetTurnManager::DisplayOOSError(u32 turn, std::string& hash, const std::string& expectedHash, const bool isReplay, OsPath* path = NULL)
     247{
    240248    std::stringstream msg;
    241     msg << "Out of sync on turn " << turn << ": expected hash " << Hexify(expectedHash) << "\n\n";
    242     msg << "Current state: turn " << m_CurrentTurn << ", hash " << Hexify(hash) << "\n\n";
    243     msg << "Dumping current state to " << utf8_from_wstring(path.string());
     249    msg << "Out of sync on turn " << turn << ": expected hash " << expectedHash << "\n\n";
     250
     251    if ((expectedHash != hash) || (m_CurrentTurn != turn))
     252        msg << "Current state: turn " << m_CurrentTurn << ", hash " << hash << "\n\n";
     253
     254    if (isReplay)
     255        msg << "The current game state is different from the original game state.\n\n";
     256    else
     257    {
     258        if (expectedHash == hash)
     259            msg << "Your game state is identical to the hosts game state.\n\n";
     260        else
     261            msg << "Your game state is different from the hosts game state.\n\n";
     262    }
     263
     264    if (path != NULL)
     265        msg << "Dumping current state to " << utf8_from_wstring(OsPath(*path).string());
     266
    244267    if (g_GUI)
    245268        g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str()));
    246269    else
    247270        LOGERROR("%s", msg.str());
    248271}
     
    320343void CNetTurnManager::QuickSave()
    321344{
    322345    TIMER(L"QuickSave");
    323346   
    324347    std::stringstream stream;
    325     bool ok = m_Simulation2.SerializeState(stream);
    326     if (!ok)
     348    if (!m_Simulation2.SerializeState(stream))
    327349    {
    328350        LOGERROR("Failed to quicksave game");
    329351        return;
    330352    }
    331353
     
    348370        LOGERROR("Cannot quickload game - no game was quicksaved");
    349371        return;
    350372    }
    351373
    352374    std::stringstream stream(m_QuickSaveState);
    353     bool ok = m_Simulation2.DeserializeState(stream);
    354     if (!ok)
     375    if (!m_Simulation2.DeserializeState(stream))
    355376    {
    356377        LOGERROR("Failed to quickload game");
    357378        return;
    358379    }
    359380
     
    400421{
    401422    bool quick = !TurnNeedsFullHash(turn);
    402423    std::string hash;
    403424    {
    404425        PROFILE3("state hash check");
    405         bool ok = m_Simulation2.ComputeStateHash(hash, quick);
    406         ENSURE(ok);
     426        ENSURE(m_Simulation2.ComputeStateHash(hash, quick));
    407427    }
    408428
    409429    NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str()));
    410430
    411431    m_Replay.Hash(hash, quick);
     
    450470{
    451471#if 0 // this hurts performance and is only useful for verifying log replays
    452472    std::string hash;
    453473    {
    454474        PROFILE3("state hash check");
    455         bool ok = m_Simulation2.ComputeStateHash(hash);
    456         ENSURE(ok);
     475        ENSURE(m_Simulation2.ComputeStateHash(hash));
    457476    }
    458477    m_Replay.Hash(hash);
    459478#endif
    460479}
    461480
    462481void CNetLocalTurnManager::OnSimulationMessage(CSimulationMessage* UNUSED(msg))
    463482{
    464483    debug_warn(L"This should never be called");
    465484}
    466485
     486CNetReplayTurnManager::CNetReplayTurnManager(CSimulation2& simulation, IReplayLogger& replay) :
     487    CNetLocalTurnManager(simulation, replay)
     488{
     489}
     490
     491void CNetReplayTurnManager::StoreReplayCommand(u32 turn, int player, const std::string& command)
     492{
     493    m_ReplayCommands[turn][player].push_back(command);
     494}
     495
     496void CNetReplayTurnManager::StoreReplayHash(u32 turn, const std::string& hash, bool quick)
     497{
     498    m_ReplayHash[turn] = std::make_pair(hash, quick);
     499}
     500
     501void CNetReplayTurnManager::StoreReplayTurnLength(u32 turn, u32 turnLength)
     502{
     503    m_ReplayTurnLengths[turn] = turnLength;
     504
     505    // Initialize turn length
     506    if (turn == 0)
     507        m_TurnLength = m_ReplayTurnLengths[0];
     508}
     509
     510void CNetReplayTurnManager::StoreFinalReplayTurn(u32 turn)
     511{
     512    m_FinalReplayTurn = turn;
     513}
     514void CNetReplayTurnManager::NotifyFinishedUpdate(u32 turn)
     515{
     516    if (turn > m_FinalReplayTurn)
     517        return;
     518
     519    debug_printf("Executing turn %d of %d\n", turn, m_FinalReplayTurn);
     520    DoTurn(turn);
     521
     522    // Compare hash, if it exists in the replay
     523    if (m_ReplayHash.count(turn) == 0)
     524        return;
    467525
     526    std::string expectedHash = m_ReplayHash[turn].first;
     527    bool quickHash = m_ReplayHash[turn].second;
     528
     529    // Compute hash
     530    std::string hash;
     531    ENSURE(m_Simulation2.ComputeStateHash(hash, quickHash));
     532    hash = Hexify(hash);
    468533
     534    if (hash != expectedHash)
     535        DisplayOOSError(turn, hash, expectedHash, true);
     536}
     537
     538void CNetReplayTurnManager::DoTurn(u32 turn)
     539{
     540    // Save turn length
     541    m_TurnLength = m_ReplayTurnLengths[turn];
     542
     543    // Simulate commands for that turn
     544    for (auto& command : m_ReplayCommands[turn])
     545        for (size_t i = 0; i < command.second.size(); ++i)
     546        {
     547            JS::RootedValue data(m_Simulation2.GetScriptInterface().GetContext());
     548            m_Simulation2.GetScriptInterface().ParseJSON(command.second[i], &data);
     549            AddCommand(m_ClientId, command.first, data, m_CurrentTurn + 1);
     550        }
     551}
    469552
    470553CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server) :
    471554    m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP)
    472555{
    473556    // The first turn we will actually execute is number 2,
  • source/network/NetTurnManager.h

     
    1717
    1818#ifndef INCLUDED_NETTURNMANAGER
    1919#define INCLUDED_NETTURNMANAGER
    2020
    2121#include "simulation2/helpers/SimulationCommand.h"
     22#include "lib/os_path.h"
    2223
    2324#include <list>
    2425#include <map>
     26#include <vector>
    2527
    2628class CNetServerWorker;
    2729class CNetClient;
    2830class CSimulationMessage;
    2931class CSimulation2;
     
    106108     * Called when there has been an out-of-sync error.
    107109     */
    108110    virtual void OnSyncError(u32 turn, const std::string& expectedHash);
    109111
    110112    /**
     113     * Shows a message box when an out of sync error has been detected in the session or visual replay.
     114     */
     115    virtual void DisplayOOSError(u32 turn, std::string& hash, const std::string& expectedHash, const bool isReplay, OsPath* path);
     116
     117    /**
    111118     * Called by simulation code, to add a new command to be distributed to all clients and executed soon.
    112119     */
    113120    virtual void PostCommand(JS::HandleValue data) = 0;
    114121
    115122    /**
     
    187194    std::list<std::string> m_TimeWarpStates;
    188195    std::string m_QuickSaveState; // TODO: should implement a proper disk-based quicksave system
    189196    std::string m_QuickSaveMetadata;
    190197};
    191198
     199
    192200/**
    193201 * Implementation of CNetTurnManager for network clients.
    194202 */
    195203class CNetClientTurnManager : public CNetTurnManager
    196204{
     
    231239
    232240    virtual void NotifyFinishedUpdate(u32 turn);
    233241};
    234242
    235243
     244
     245/**
     246 * Implementation of CNetTurnManager for replay games.
     247 */
     248class CNetReplayTurnManager : public CNetLocalTurnManager
     249{
     250public:
     251    CNetReplayTurnManager(CSimulation2& simulation, IReplayLogger& replay);
     252
     253    void StoreReplayCommand(u32 turn, int player, const std::string& command);
     254
     255    void StoreReplayTurnLength(u32 turn, u32 turnLength);
     256
     257    void StoreReplayHash(u32 turn, const std::string& hash, bool quick);
     258
     259    void StoreFinalReplayTurn(u32 turn);
     260
     261
     262protected:
     263    virtual void NotifyFinishedUpdate(u32 turn);
     264
     265    void DoTurn(u32 turn);
     266
     267    // Contains the commands of every player on each turn
     268    std::map<u32, std::map<int, std::vector<std::string> > > m_ReplayCommands;
     269
     270    // Contains the length of every turn
     271    std::map<u32, u32> m_ReplayTurnLengths;
     272
     273    // Contains all replay hash values and weather or not the quick hash method was used
     274    std::map<u32, std::pair<std::string, bool> > m_ReplayHash;
     275
     276    // The number of the last turn in the replay
     277    u32 m_FinalReplayTurn;
     278
     279};
    236280/**
    237281 * The server-side counterpart to CNetClientTurnManager.
    238282 * Records the turn state of each client, and sends turn advancement messages
    239283 * when all clients are ready.
    240284 *
  • source/ps/Game.cpp

     
    4545#include "renderer/WaterManager.h"
    4646#include "scriptinterface/ScriptInterface.h"
    4747#include "simulation2/Simulation2.h"
    4848#include "simulation2/components/ICmpPlayer.h"
    4949#include "simulation2/components/ICmpPlayerManager.h"
     50#include "simulation2/helpers/Player.h"
    5051#include "soundmanager/ISoundManager.h"
    5152
    5253#include "tools/atlas/GameInterface/GameLoop.h"
    5354
    5455extern bool g_GameRestarted;
    5556extern GameLoopState* g_AtlasGameLoop;
     57extern void kill_mainloop(); // from main.cpp
    5658
    5759/**
    5860 * Globally accessible pointer to the CGame object.
    5961 **/
    6062CGame *g_Game=NULL;
    6163
    6264/**
    6365 * Constructor
    6466 *
    6567 **/
    66 CGame::CGame(bool disableGraphics):
     68CGame::CGame(bool disableGraphics, bool replayLog):
    6769    m_World(new CWorld(this)),
    6870    m_Simulation2(new CSimulation2(&m_World->GetUnitManager(), g_ScriptRuntime, m_World->GetTerrain())),
    6971    m_GameView(disableGraphics ? NULL : new CGameView(this)),
    7072    m_GameStarted(false),
    7173    m_Paused(false),
    7274    m_SimRate(1.0f),
    7375    m_PlayerID(-1),
    74     m_IsSavedGame(false)
     76    m_IsSavedGame(false),
     77    m_IsReplay(false),
     78    m_ReplayStream(NULL)
    7579{
    76     m_ReplayLogger = new CReplayLogger(m_Simulation2->GetScriptInterface());
    7780    // TODO: should use CDummyReplayLogger unless activated by cmd-line arg, perhaps?
     81    if (replayLog)
     82        m_ReplayLogger = new CReplayLogger(m_Simulation2->GetScriptInterface());
     83    else
     84        m_ReplayLogger = new CDummyReplayLogger();
    7885
    7986    // Need to set the CObjectManager references after various objects have
    8087    // been initialised, so do it here rather than via the initialisers above.
    8188    if (m_GameView)
    8289        m_World->GetUnitManager().SetObjectManager(m_GameView->GetObjectManager());
    8390
    8491    m_TurnManager = new CNetLocalTurnManager(*m_Simulation2, GetReplayLogger()); // this will get replaced if we're a net server/client
    8592
    8693    m_Simulation2->LoadDefaultScripts();
    8794}
     95int CGame::LoadReplayData()
     96{
     97    ENSURE(m_IsReplay);
     98    ENSURE(!m_ReplayPath.empty());
     99
     100    CNetReplayTurnManager* replayTurnMgr = static_cast<CNetReplayTurnManager*>(GetTurnManager());
     101
     102    u32 currentTurn = 0;
     103    std::string type;
     104    while ((*m_ReplayStream >> type).good())
     105    {
     106        if (type == "turn")
     107        {
     108            u32 turn = 0;
     109            u32 turnLength = 0;
     110            *m_ReplayStream >> turn >> turnLength;
     111            ENSURE(turn == currentTurn);
     112            replayTurnMgr->StoreReplayTurnLength(currentTurn, turnLength);
     113        }
     114        else if (type == "cmd")
     115        {
     116            player_id_t player;
     117            *m_ReplayStream >> player;
     118
     119            std::string line;
     120            std::getline(*m_ReplayStream, line);
     121            replayTurnMgr->StoreReplayCommand(currentTurn, player, line);
     122        }
     123        else if (type == "hash" || type == "hash-quick")
     124        {
     125            bool quick = (type == "hash-quick");
     126            std::string replayHash;
     127            *m_ReplayStream >> replayHash;
     128            replayTurnMgr->StoreReplayHash(currentTurn, replayHash, quick);
     129        }
     130        else if (type == "end")
     131        {
     132            currentTurn++;
     133        }
     134        else
     135        {
     136            CancelLoad(L"Failed to load replay data (unrecognized content)");
     137        }
     138    }
     139    m_FinalReplayTurn = currentTurn;
     140    replayTurnMgr->StoreFinalReplayTurn(currentTurn);
     141    return 0;
     142}
     143bool CGame::StartReplay(const std::string& replayPath)
     144{
     145    m_IsReplay = true;
     146    ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface();
    88147
     148    SetTurnManager(new CNetReplayTurnManager(*m_Simulation2, GetReplayLogger()));
     149
     150    m_ReplayPath = replayPath;
     151    m_ReplayStream = new std::ifstream(m_ReplayPath.c_str());
     152
     153    std::string type;
     154    ENSURE((*m_ReplayStream >> type).good() && type == "start");
     155
     156    std::string line;
     157    std::getline(*m_ReplayStream, line);
     158    JS::RootedValue attribs(scriptInterface.GetContext());
     159    scriptInterface.ParseJSON(line, &attribs);
     160    StartGame(&attribs, "");
     161
     162    return true;
     163}
    89164/**
    90165 * Destructor
    91166 *
    92167 **/
    93168CGame::~CGame()
     
    99174    delete m_TurnManager;
    100175    delete m_GameView;
    101176    delete m_Simulation2;
    102177    delete m_World;
    103178    delete m_ReplayLogger;
     179    delete m_ReplayStream;
    104180}
    105181
    106182void CGame::SetTurnManager(CNetTurnManager* turnManager)
    107183{
    108184    if (m_TurnManager)
     
    174250        RegMemFun(g_Renderer.GetSingletonPtr()->GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80);
    175251
    176252    if (m_IsSavedGame)
    177253        RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000);
    178254
     255    if (m_IsReplay)
     256        RegMemFun(this, &CGame::LoadReplayData, L"Loading replay data", 1000);
     257
    179258    LDR_EndRegistering();
    180259}
    181260
    182261int CGame::LoadInitialState()
    183262{
     
    261340int CGame::GetPlayerID()
    262341{
    263342    return m_PlayerID;
    264343}
    265344
    266 void CGame::SetPlayerID(int playerID)
     345void CGame::SetPlayerID(player_id_t playerID)
    267346{
    268347    m_PlayerID = playerID;
    269348    if (m_TurnManager)
    270349        m_TurnManager->SetPlayerID(m_PlayerID);
    271350}
    272351
    273352void CGame::StartGame(JS::MutableHandleValue attribs, const std::string& savedState)
    274353{
    275     m_ReplayLogger->StartGame(attribs);
     354    if (m_ReplayLogger != false)
     355        m_ReplayLogger->StartGame(attribs);
     356
    276357    RegisterInit(attribs, savedState);
    277358}
    278359
    279360// TODO: doInterpolate is optional because Atlas interpolates explicitly,
    280361// so that it has more control over the update rate. The game might want to
     
    308389        {
    309390            {
    310391                PROFILE3("gui sim update");
    311392                g_GUI->SendEventToAll("SimulationUpdate");
    312393            }
     394             if (m_IsReplay && m_TurnManager->GetCurrentTurn() == m_FinalReplayTurn - 1)
     395                 g_GUI->SendEventToAll("ReplayFinished");
    313396
    314397            GetView()->GetLOSTexture().MakeDirty();
    315398        }
    316399       
    317400        if (CRenderer::IsInitialised())
     
    360443            m_PlayerColors[i] = cmpPlayer->GetColor();
    361444    }
    362445}
    363446
    364447
    365 CColor CGame::GetPlayerColor(int player) const
     448CColor CGame::GetPlayerColor(player_id_t player) const
    366449{
    367450    if (player < 0 || player >= (int)m_PlayerColors.size())
    368451        return BrokenColor;
    369452
    370453    return m_PlayerColors[player];
  • source/ps/Game.h

     
    1919#define INCLUDED_GAME
    2020
    2121#include "ps/Errors.h"
    2222#include <vector>
    2323
     24#include <map>
    2425#include "scriptinterface/ScriptVal.h"
     26#include "simulation2/helpers/Player.h"
    2527
    2628class CWorld;
    2729class CSimulation2;
    2830class CGameView;
    2931class CNetTurnManager;
     
    5860    /**
    5961     * Timescale multiplier for simulation rate.
    6062     **/
    6163    float m_SimRate;
    6264
    63     int m_PlayerID;
     65    player_id_t m_PlayerID;
    6466
    6567    CNetTurnManager* m_TurnManager;
    6668
    6769public:
    68     CGame(bool disableGraphics = false);
     70    CGame(bool disableGraphics = false, bool replayLog = true);
    6971    ~CGame();
    7072
    7173    /**
    7274     * the game is paused and no updates will be performed if true.
    7375     **/
    7476    bool m_Paused;
    7577
    7678    void StartGame(JS::MutableHandleValue attribs, const std::string& savedState);
    7779    PSRETURN ReallyStartGame();
    7880
     81    bool StartReplay(const std::string& replayPath);
     82
    7983    /**
    8084     * Periodic heartbeat that controls the process. performs all per-frame updates.
    8185     * Simulation update is called and game status update is called.
    8286     *
    8387     * @param deltaRealTime Elapsed real time since last beat/frame, in seconds.
     
    8892    bool Update(const double deltaRealTime, bool doInterpolate = true);
    8993
    9094    void Interpolate(float simFrameLength, float realFrameLength);
    9195
    9296    int GetPlayerID();
    93     void SetPlayerID(int playerID);
     97    void SetPlayerID(player_id_t playerID);
    9498
    9599    /**
    96100     * Retrieving player colors from scripts is slow, so this updates an
    97101     * internal cache of all players' colors.
    98102     * Call this just before rendering, so it will always have the latest
    99103     * colors.
    100104     */
    101105    void CachePlayerColors();
    102106
    103     CColor GetPlayerColor(int player) const;
     107    CColor GetPlayerColor(player_id_t player) const;
    104108
    105109    /**
    106110     * Get m_GameStarted.
    107111     *
    108112     * @return bool the value of m_GameStarted.
     
    169173    std::vector<CColor> m_PlayerColors;
    170174
    171175    int LoadInitialState();
    172176    std::string m_InitialSavedState; // valid between RegisterInit and LoadInitialState
    173177    bool m_IsSavedGame; // true if loading a saved game; false for a new game
     178
     179    int LoadReplayData();
     180    std::string m_ReplayPath;
     181    bool m_IsReplay;
     182    std::istream* m_ReplayStream;
     183    u32 m_FinalReplayTurn;
    174184};
    175185
    176186extern CGame *g_Game;
    177187
    178188#endif
  • source/ps/GameSetup/GameSetup.cpp

     
    879879    srand(time(NULL));  // NOTE: this rand should *not* be used for simulation!
    880880}
    881881
    882882bool Autostart(const CmdLineArgs& args);
    883883
     884// Returns true if and only if the user has intended to replay a file
     885bool VisualReplay(const std::string replayFile);
     886
    884887bool Init(const CmdLineArgs& args, int flags)
    885888{
    886889    h_mgr_init();
    887890
    888891    // Do this as soon as possible, because it chdirs
     
    10711074
    10721075    ogl_WarnIfError();
    10731076
    10741077    try
    10751078    {
    1076         if (!Autostart(args))
     1079        if (!VisualReplay(args.Get("replay-visual")) && !Autostart(args))
    10771080        {
    10781081            const bool setup_gui = ((flags & INIT_NO_GUI) == 0);
    10791082            // We only want to display the splash screen at startup
    10801083            shared_ptr<ScriptInterface> scriptInterface = g_GUI->GetScriptInterface();
    10811084            JSContext* cx = scriptInterface->GetContext();
     
    14681471    }
    14691472
    14701473    return true;
    14711474}
    14721475
     1476bool VisualReplay(const std::string replayFile)
     1477{
     1478    if (!FileExists(OsPath(replayFile)))
     1479         return false;
     1480
     1481    g_Game = new CGame(false, false);
     1482    g_Game->SetPlayerID(-1);
     1483    g_Game->StartReplay(replayFile);
     1484
     1485    // TODO: Non progressive load can fail - need a decent way to handle this
     1486    LDR_NonprogressiveLoad();
     1487
     1488    PSRETURN ret = g_Game->ReallyStartGame();
     1489    ENSURE(ret == PSRETURN_OK);
     1490
     1491    ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
     1492
     1493    InitPs(true, L"page_session.xml", &scriptInterface, JS::UndefinedHandleValue);
     1494    return true;
     1495}
     1496
    14731497void CancelLoad(const CStrW& message)
    14741498{
    14751499    shared_ptr<ScriptInterface> pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
    14761500    JSContext* cx = pScriptInterface->GetContext();
    14771501    JSAutoRequest rq(cx);
  • source/ps/Replay.h

     
    5454 */
    5555class CDummyReplayLogger : public IReplayLogger
    5656{
    5757public:
    5858    virtual void StartGame(JS::MutableHandleValue UNUSED(attribs)) { }
    59     virtual void Turn(u32 UNUSED(n), u32 UNUSED(turnLength), const std::vector<SimulationCommand>& UNUSED(commands)) { }
     59    virtual void Turn(u32 UNUSED(n), u32 UNUSED(turnLength), std::vector<SimulationCommand>& UNUSED(commands)) { }
    6060    virtual void Hash(const std::string& UNUSED(hash), bool UNUSED(quick)) { }
    6161};
    6262
    6363/**
    6464 * Implementation of IReplayLogger that saves data to a file in the logs directory.