forked from 0ad/0ad
Visual replay of command files, patch by elexis.
Works with the command line argument "-replay-visual=/path/to/commands.txt". It is not integrated to the main menu GUI yet. Refs #9. This was SVN commit r16727.
This commit is contained in:
parent
e9c27d4066
commit
be93b31411
@ -557,6 +557,16 @@ function onSimulationUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
function onReplayFinished()
|
||||
{
|
||||
closeMenu();
|
||||
closeOpenDialogs();
|
||||
pauseGame();
|
||||
var btCaptions = [translateWithContext("replayFinished", "Yes"), translateWithContext("replayFinished", "No")];
|
||||
var btCode = [leaveGame, resumeGame];
|
||||
messageBox(400, 200, translateWithContext("replayFinished", "The replay has finished. Do you want to quit?"), translateWithContext("replayFinished","Confirmation"), 0, btCaptions, btCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates a status bar on the GUI
|
||||
* nameOfBar: name of the bar
|
||||
|
@ -22,6 +22,10 @@
|
||||
onSimulationUpdate();
|
||||
</action>
|
||||
|
||||
<action on="ReplayFinished">
|
||||
onReplayFinished();
|
||||
</action>
|
||||
|
||||
<action on="Press">
|
||||
this.hidden = !this.hidden;
|
||||
</action>
|
||||
|
@ -442,6 +442,12 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
// run non-visual simulation replay if requested
|
||||
if (args.Has("replay"))
|
||||
{
|
||||
std::string replayFile = args.Get("replay");
|
||||
if (!FileExists(OsPath(replayFile)))
|
||||
{
|
||||
debug_printf("ERROR: The requested replay file '%s' does not exist!\n", replayFile.c_str());
|
||||
return;
|
||||
}
|
||||
Paths paths(args);
|
||||
g_VFS = CreateVfs(20 * MiB);
|
||||
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE);
|
||||
@ -449,7 +455,7 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
|
||||
{
|
||||
CReplayPlayer replay;
|
||||
replay.Load(args.Get("replay"));
|
||||
replay.Load(replayFile);
|
||||
replay.Replay(args.Has("serializationtest"), args.Has("ooslog"));
|
||||
}
|
||||
|
||||
@ -459,6 +465,17 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
return;
|
||||
}
|
||||
|
||||
// If visual replay file does not exist, quit before starting the renderer
|
||||
if (args.Has("replay-visual"))
|
||||
{
|
||||
std::string replayFile = args.Get("replay-visual");
|
||||
if (!FileExists(OsPath(replayFile)))
|
||||
{
|
||||
debug_printf("ERROR: The requested replay file '%s' does not exist!\n", replayFile.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// run in archive-building mode if requested
|
||||
if (args.Has("archivebuild"))
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
/* Copyright (C) 2015 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -225,26 +225,49 @@ void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash)
|
||||
// Only complain the first time
|
||||
if (m_HasSyncError)
|
||||
return;
|
||||
m_HasSyncError = true;
|
||||
|
||||
bool quick = !TurnNeedsFullHash(turn);
|
||||
std::string hash;
|
||||
bool ok = m_Simulation2.ComputeStateHash(hash, quick);
|
||||
ENSURE(ok);
|
||||
ENSURE(m_Simulation2.ComputeStateHash(hash, quick));
|
||||
|
||||
OsPath path = psLogDir()/"oos_dump.txt";
|
||||
std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
m_Simulation2.DumpDebugState(file);
|
||||
file.close();
|
||||
|
||||
hash = Hexify(hash);
|
||||
const std::string& expectedHashHex = Hexify(expectedHash);
|
||||
|
||||
DisplayOOSError(turn, hash, expectedHashHex, false, &path);
|
||||
}
|
||||
|
||||
void CNetTurnManager::DisplayOOSError(u32 turn, std::string& hash, const std::string& expectedHash, const bool isReplay, OsPath* path = NULL)
|
||||
{
|
||||
m_HasSyncError = true;
|
||||
|
||||
std::stringstream msg;
|
||||
msg << "Out of sync on turn " << turn << ": expected hash " << Hexify(expectedHash) << "\n\n";
|
||||
msg << "Current state: turn " << m_CurrentTurn << ", hash " << Hexify(hash) << "\n\n";
|
||||
msg << "Dumping current state to " << utf8_from_wstring(path.string());
|
||||
msg << "Out of sync on turn " << turn << ": expected hash " << expectedHash << "\n";
|
||||
|
||||
if (expectedHash != hash || m_CurrentTurn != turn)
|
||||
msg << "\nCurrent state: turn " << m_CurrentTurn << ", hash " << hash << "\n\n";
|
||||
|
||||
if (isReplay)
|
||||
msg << "\nThe current game state is different from the original game state.\n\n";
|
||||
else
|
||||
{
|
||||
if (expectedHash == hash)
|
||||
msg << "Your game state is identical to the hosts game state.\n\n";
|
||||
else
|
||||
msg << "Your game state is different from the hosts game state.\n\n";
|
||||
}
|
||||
|
||||
if (path)
|
||||
msg << "Dumping current state to " << utf8_from_wstring(OsPath(*path).string());
|
||||
|
||||
LOGERROR("%s", msg.str());
|
||||
|
||||
if (g_GUI)
|
||||
g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str()));
|
||||
else
|
||||
LOGERROR("%s", msg.str());
|
||||
}
|
||||
|
||||
void CNetTurnManager::Interpolate(float simFrameLength, float realFrameLength)
|
||||
@ -322,8 +345,7 @@ void CNetTurnManager::QuickSave()
|
||||
TIMER(L"QuickSave");
|
||||
|
||||
std::stringstream stream;
|
||||
bool ok = m_Simulation2.SerializeState(stream);
|
||||
if (!ok)
|
||||
if (!m_Simulation2.SerializeState(stream))
|
||||
{
|
||||
LOGERROR("Failed to quicksave game");
|
||||
return;
|
||||
@ -350,8 +372,7 @@ void CNetTurnManager::QuickLoad()
|
||||
}
|
||||
|
||||
std::stringstream stream(m_QuickSaveState);
|
||||
bool ok = m_Simulation2.DeserializeState(stream);
|
||||
if (!ok)
|
||||
if (!m_Simulation2.DeserializeState(stream))
|
||||
{
|
||||
LOGERROR("Failed to quickload game");
|
||||
return;
|
||||
@ -402,8 +423,7 @@ void CNetClientTurnManager::NotifyFinishedUpdate(u32 turn)
|
||||
std::string hash;
|
||||
{
|
||||
PROFILE3("state hash check");
|
||||
bool ok = m_Simulation2.ComputeStateHash(hash, quick);
|
||||
ENSURE(ok);
|
||||
ENSURE(m_Simulation2.ComputeStateHash(hash, quick));
|
||||
}
|
||||
|
||||
NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str()));
|
||||
@ -452,8 +472,7 @@ void CNetLocalTurnManager::NotifyFinishedUpdate(u32 UNUSED(turn))
|
||||
std::string hash;
|
||||
{
|
||||
PROFILE3("state hash check");
|
||||
bool ok = m_Simulation2.ComputeStateHash(hash);
|
||||
ENSURE(ok);
|
||||
ENSURE(m_Simulation2.ComputeStateHash(hash));
|
||||
}
|
||||
m_Replay.Hash(hash);
|
||||
#endif
|
||||
@ -464,8 +483,75 @@ void CNetLocalTurnManager::OnSimulationMessage(CSimulationMessage* UNUSED(msg))
|
||||
debug_warn(L"This should never be called");
|
||||
}
|
||||
|
||||
CNetReplayTurnManager::CNetReplayTurnManager(CSimulation2& simulation, IReplayLogger& replay) :
|
||||
CNetLocalTurnManager(simulation, replay)
|
||||
{
|
||||
}
|
||||
|
||||
void CNetReplayTurnManager::StoreReplayCommand(u32 turn, int player, const std::string& command)
|
||||
{
|
||||
m_ReplayCommands[turn][player].push_back(command);
|
||||
}
|
||||
|
||||
void CNetReplayTurnManager::StoreReplayHash(u32 turn, const std::string& hash, bool quick)
|
||||
{
|
||||
m_ReplayHash[turn] = std::make_pair(hash, quick);
|
||||
}
|
||||
|
||||
void CNetReplayTurnManager::StoreReplayTurnLength(u32 turn, u32 turnLength)
|
||||
{
|
||||
m_ReplayTurnLengths[turn] = turnLength;
|
||||
|
||||
// Initialize turn length
|
||||
if (turn == 0)
|
||||
m_TurnLength = m_ReplayTurnLengths[0];
|
||||
}
|
||||
|
||||
void CNetReplayTurnManager::StoreFinalReplayTurn(u32 turn)
|
||||
{
|
||||
m_FinalReplayTurn = turn;
|
||||
}
|
||||
|
||||
void CNetReplayTurnManager::NotifyFinishedUpdate(u32 turn)
|
||||
{
|
||||
if (turn > m_FinalReplayTurn)
|
||||
return;
|
||||
|
||||
debug_printf("Executing turn %d of %d\n", turn, m_FinalReplayTurn);
|
||||
DoTurn(turn);
|
||||
|
||||
// Compare hash if it exists in the replay and if we didn't have an oos already
|
||||
if (m_HasSyncError || m_ReplayHash.find(turn) == m_ReplayHash.end())
|
||||
return;
|
||||
|
||||
std::string expectedHash = m_ReplayHash[turn].first;
|
||||
bool quickHash = m_ReplayHash[turn].second;
|
||||
|
||||
// Compute hash
|
||||
std::string hash;
|
||||
ENSURE(m_Simulation2.ComputeStateHash(hash, quickHash));
|
||||
hash = Hexify(hash);
|
||||
|
||||
if (hash != expectedHash)
|
||||
DisplayOOSError(turn, hash, expectedHash, true);
|
||||
}
|
||||
|
||||
void CNetReplayTurnManager::DoTurn(u32 turn)
|
||||
{
|
||||
// Save turn length
|
||||
m_TurnLength = m_ReplayTurnLengths[turn];
|
||||
|
||||
// Simulate commands for that turn
|
||||
for (auto& command : m_ReplayCommands[turn])
|
||||
{
|
||||
for (size_t i = 0; i < command.second.size(); ++i)
|
||||
{
|
||||
JS::RootedValue data(m_Simulation2.GetScriptInterface().GetContext());
|
||||
m_Simulation2.GetScriptInterface().ParseJSON(command.second[i], &data);
|
||||
AddCommand(m_ClientId, command.first, data, m_CurrentTurn + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server) :
|
||||
m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
/* Copyright (C) 2015 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -19,9 +19,11 @@
|
||||
#define INCLUDED_NETTURNMANAGER
|
||||
|
||||
#include "simulation2/helpers/SimulationCommand.h"
|
||||
#include "lib/os_path.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class CNetServerWorker;
|
||||
class CNetClient;
|
||||
@ -107,6 +109,11 @@ public:
|
||||
*/
|
||||
virtual void OnSyncError(u32 turn, const std::string& expectedHash);
|
||||
|
||||
/**
|
||||
* Shows a message box when an out of sync error has been detected in the session or visual replay.
|
||||
*/
|
||||
virtual void DisplayOOSError(u32 turn, std::string& hash, const std::string& expectedHash, const bool isReplay, OsPath* path);
|
||||
|
||||
/**
|
||||
* Called by simulation code, to add a new command to be distributed to all clients and executed soon.
|
||||
*/
|
||||
@ -189,6 +196,7 @@ private:
|
||||
std::string m_QuickSaveMetadata;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of CNetTurnManager for network clients.
|
||||
*/
|
||||
@ -233,6 +241,42 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of CNetTurnManager for replay games.
|
||||
*/
|
||||
class CNetReplayTurnManager : public CNetLocalTurnManager
|
||||
{
|
||||
public:
|
||||
CNetReplayTurnManager(CSimulation2& simulation, IReplayLogger& replay);
|
||||
|
||||
void StoreReplayCommand(u32 turn, int player, const std::string& command);
|
||||
|
||||
void StoreReplayTurnLength(u32 turn, u32 turnLength);
|
||||
|
||||
void StoreReplayHash(u32 turn, const std::string& hash, bool quick);
|
||||
|
||||
void StoreFinalReplayTurn(u32 turn);
|
||||
|
||||
|
||||
protected:
|
||||
virtual void NotifyFinishedUpdate(u32 turn);
|
||||
|
||||
void DoTurn(u32 turn);
|
||||
|
||||
// Contains the commands of every player on each turn
|
||||
std::map<u32, std::map<int, std::vector<std::string> > > m_ReplayCommands;
|
||||
|
||||
// Contains the length of every turn
|
||||
std::map<u32, u32> m_ReplayTurnLengths;
|
||||
|
||||
// Contains all replay hash values and weather or not the quick hash method was used
|
||||
std::map<u32, std::pair<std::string, bool> > m_ReplayHash;
|
||||
|
||||
// The number of the last turn in the replay
|
||||
u32 m_FinalReplayTurn;
|
||||
|
||||
};
|
||||
/**
|
||||
* The server-side counterpart to CNetClientTurnManager.
|
||||
* Records the turn state of each client, and sends turn advancement messages
|
||||
|
@ -63,7 +63,7 @@ CGame *g_Game=NULL;
|
||||
* Constructor
|
||||
*
|
||||
**/
|
||||
CGame::CGame(bool disableGraphics):
|
||||
CGame::CGame(bool disableGraphics, bool replayLog):
|
||||
m_World(new CWorld(this)),
|
||||
m_Simulation2(new CSimulation2(&m_World->GetUnitManager(), g_ScriptRuntime, m_World->GetTerrain())),
|
||||
m_GameView(disableGraphics ? NULL : new CGameView(this)),
|
||||
@ -71,10 +71,15 @@ CGame::CGame(bool disableGraphics):
|
||||
m_Paused(false),
|
||||
m_SimRate(1.0f),
|
||||
m_PlayerID(-1),
|
||||
m_IsSavedGame(false)
|
||||
m_IsSavedGame(false),
|
||||
m_IsReplay(false),
|
||||
m_ReplayStream(NULL)
|
||||
{
|
||||
m_ReplayLogger = new CReplayLogger(m_Simulation2->GetScriptInterface());
|
||||
// TODO: should use CDummyReplayLogger unless activated by cmd-line arg, perhaps?
|
||||
if (replayLog)
|
||||
m_ReplayLogger = new CReplayLogger(m_Simulation2->GetScriptInterface());
|
||||
else
|
||||
m_ReplayLogger = new CDummyReplayLogger();
|
||||
|
||||
// Need to set the CObjectManager references after various objects have
|
||||
// been initialised, so do it here rather than via the initialisers above.
|
||||
@ -101,6 +106,7 @@ CGame::~CGame()
|
||||
delete m_Simulation2;
|
||||
delete m_World;
|
||||
delete m_ReplayLogger;
|
||||
delete m_ReplayStream;
|
||||
}
|
||||
|
||||
void CGame::SetTurnManager(CNetTurnManager* turnManager)
|
||||
@ -114,6 +120,76 @@ void CGame::SetTurnManager(CNetTurnManager* turnManager)
|
||||
m_TurnManager->SetPlayerID(m_PlayerID);
|
||||
}
|
||||
|
||||
int CGame::LoadReplayData()
|
||||
{
|
||||
ENSURE(m_IsReplay);
|
||||
ENSURE(!m_ReplayPath.empty());
|
||||
|
||||
CNetReplayTurnManager* replayTurnMgr = static_cast<CNetReplayTurnManager*>(GetTurnManager());
|
||||
|
||||
u32 currentTurn = 0;
|
||||
std::string type;
|
||||
while ((*m_ReplayStream >> type).good())
|
||||
{
|
||||
if (type == "turn")
|
||||
{
|
||||
u32 turn = 0;
|
||||
u32 turnLength = 0;
|
||||
*m_ReplayStream >> turn >> turnLength;
|
||||
ENSURE(turn == currentTurn);
|
||||
replayTurnMgr->StoreReplayTurnLength(currentTurn, turnLength);
|
||||
}
|
||||
else if (type == "cmd")
|
||||
{
|
||||
player_id_t player;
|
||||
*m_ReplayStream >> player;
|
||||
|
||||
std::string line;
|
||||
std::getline(*m_ReplayStream, line);
|
||||
replayTurnMgr->StoreReplayCommand(currentTurn, player, line);
|
||||
}
|
||||
else if (type == "hash" || type == "hash-quick")
|
||||
{
|
||||
bool quick = (type == "hash-quick");
|
||||
std::string replayHash;
|
||||
*m_ReplayStream >> replayHash;
|
||||
replayTurnMgr->StoreReplayHash(currentTurn, replayHash, quick);
|
||||
}
|
||||
else if (type == "end")
|
||||
{
|
||||
currentTurn++;
|
||||
}
|
||||
else
|
||||
{
|
||||
CancelLoad(L"Failed to load replay data (unrecognized content)");
|
||||
}
|
||||
}
|
||||
m_FinalReplayTurn = currentTurn;
|
||||
replayTurnMgr->StoreFinalReplayTurn(currentTurn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CGame::StartReplay(const std::string& replayPath)
|
||||
{
|
||||
m_IsReplay = true;
|
||||
ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface();
|
||||
|
||||
SetTurnManager(new CNetReplayTurnManager(*m_Simulation2, GetReplayLogger()));
|
||||
|
||||
m_ReplayPath = replayPath;
|
||||
m_ReplayStream = new std::ifstream(m_ReplayPath.c_str());
|
||||
|
||||
std::string type;
|
||||
ENSURE((*m_ReplayStream >> type).good() && type == "start");
|
||||
|
||||
std::string line;
|
||||
std::getline(*m_ReplayStream, line);
|
||||
JS::RootedValue attribs(scriptInterface.GetContext());
|
||||
scriptInterface.ParseJSON(line, &attribs);
|
||||
StartGame(&attribs, "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the game with the set of attributes provided.
|
||||
@ -176,6 +252,9 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
|
||||
if (m_IsSavedGame)
|
||||
RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000);
|
||||
|
||||
if (m_IsReplay)
|
||||
RegMemFun(this, &CGame::LoadReplayData, L"Loading replay data", 1000);
|
||||
|
||||
LDR_EndRegistering();
|
||||
}
|
||||
|
||||
@ -263,7 +342,7 @@ int CGame::GetPlayerID()
|
||||
return m_PlayerID;
|
||||
}
|
||||
|
||||
void CGame::SetPlayerID(int playerID)
|
||||
void CGame::SetPlayerID(player_id_t playerID)
|
||||
{
|
||||
m_PlayerID = playerID;
|
||||
if (m_TurnManager)
|
||||
@ -272,7 +351,9 @@ void CGame::SetPlayerID(int playerID)
|
||||
|
||||
void CGame::StartGame(JS::MutableHandleValue attribs, const std::string& savedState)
|
||||
{
|
||||
m_ReplayLogger->StartGame(attribs);
|
||||
if (m_ReplayLogger != false)
|
||||
m_ReplayLogger->StartGame(attribs);
|
||||
|
||||
RegisterInit(attribs, savedState);
|
||||
}
|
||||
|
||||
@ -310,6 +391,8 @@ bool CGame::Update(const double deltaRealTime, bool doInterpolate)
|
||||
PROFILE3("gui sim update");
|
||||
g_GUI->SendEventToAll("SimulationUpdate");
|
||||
}
|
||||
if (m_IsReplay && m_TurnManager->GetCurrentTurn() == m_FinalReplayTurn - 1)
|
||||
g_GUI->SendEventToAll("ReplayFinished");
|
||||
|
||||
GetView()->GetLOSTexture().MakeDirty();
|
||||
}
|
||||
@ -362,7 +445,7 @@ void CGame::CachePlayerColors()
|
||||
}
|
||||
|
||||
|
||||
CColor CGame::GetPlayerColor(int player) const
|
||||
CColor CGame::GetPlayerColor(player_id_t player) const
|
||||
{
|
||||
if (player < 0 || player >= (int)m_PlayerColors.size())
|
||||
return BrokenColor;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
/* Copyright (C) 2015 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 <vector>
|
||||
|
||||
#include "scriptinterface/ScriptVal.h"
|
||||
#include "simulation2/helpers/Player.h"
|
||||
|
||||
class CWorld;
|
||||
class CSimulation2;
|
||||
@ -60,12 +61,12 @@ class CGame
|
||||
**/
|
||||
float m_SimRate;
|
||||
|
||||
int m_PlayerID;
|
||||
player_id_t m_PlayerID;
|
||||
|
||||
CNetTurnManager* m_TurnManager;
|
||||
|
||||
public:
|
||||
CGame(bool disableGraphics = false);
|
||||
CGame(bool disableGraphics = false, bool replayLog = true);
|
||||
~CGame();
|
||||
|
||||
/**
|
||||
@ -76,6 +77,8 @@ public:
|
||||
void StartGame(JS::MutableHandleValue attribs, const std::string& savedState);
|
||||
PSRETURN ReallyStartGame();
|
||||
|
||||
bool StartReplay(const std::string& replayPath);
|
||||
|
||||
/**
|
||||
* Periodic heartbeat that controls the process. performs all per-frame updates.
|
||||
* Simulation update is called and game status update is called.
|
||||
@ -90,7 +93,7 @@ public:
|
||||
void Interpolate(float simFrameLength, float realFrameLength);
|
||||
|
||||
int GetPlayerID();
|
||||
void SetPlayerID(int playerID);
|
||||
void SetPlayerID(player_id_t playerID);
|
||||
|
||||
/**
|
||||
* Retrieving player colors from scripts is slow, so this updates an
|
||||
@ -100,7 +103,7 @@ public:
|
||||
*/
|
||||
void CachePlayerColors();
|
||||
|
||||
CColor GetPlayerColor(int player) const;
|
||||
CColor GetPlayerColor(player_id_t player) const;
|
||||
|
||||
/**
|
||||
* Get m_GameStarted.
|
||||
@ -171,6 +174,12 @@ private:
|
||||
int LoadInitialState();
|
||||
std::string m_InitialSavedState; // valid between RegisterInit and LoadInitialState
|
||||
bool m_IsSavedGame; // true if loading a saved game; false for a new game
|
||||
|
||||
int LoadReplayData();
|
||||
std::string m_ReplayPath;
|
||||
bool m_IsReplay;
|
||||
std::istream* m_ReplayStream;
|
||||
u32 m_FinalReplayTurn;
|
||||
};
|
||||
|
||||
extern CGame *g_Game;
|
||||
|
@ -881,6 +881,9 @@ void EarlyInit()
|
||||
|
||||
bool Autostart(const CmdLineArgs& args);
|
||||
|
||||
// Returns true if and only if the user has intended to replay a file
|
||||
bool VisualReplay(const std::string replayFile);
|
||||
|
||||
bool Init(const CmdLineArgs& args, int flags)
|
||||
{
|
||||
h_mgr_init();
|
||||
@ -1073,7 +1076,7 @@ void InitGraphics(const CmdLineArgs& args, int flags)
|
||||
|
||||
try
|
||||
{
|
||||
if (!Autostart(args))
|
||||
if (!VisualReplay(args.Get("replay-visual")) && !Autostart(args))
|
||||
{
|
||||
const bool setup_gui = ((flags & INIT_NO_GUI) == 0);
|
||||
// We only want to display the splash screen at startup
|
||||
@ -1470,6 +1473,27 @@ bool Autostart(const CmdLineArgs& args)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisualReplay(const std::string replayFile)
|
||||
{
|
||||
if (!FileExists(OsPath(replayFile)))
|
||||
return false;
|
||||
|
||||
g_Game = new CGame(false, false);
|
||||
g_Game->SetPlayerID(-1);
|
||||
g_Game->StartReplay(replayFile);
|
||||
|
||||
// TODO: Non progressive load can fail - need a decent way to handle this
|
||||
LDR_NonprogressiveLoad();
|
||||
|
||||
PSRETURN ret = g_Game->ReallyStartGame();
|
||||
ENSURE(ret == PSRETURN_OK);
|
||||
|
||||
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
|
||||
|
||||
InitPs(true, L"page_session.xml", &scriptInterface, JS::UndefinedHandleValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CancelLoad(const CStrW& message)
|
||||
{
|
||||
shared_ptr<ScriptInterface> pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
|
||||
|
@ -56,7 +56,7 @@ class CDummyReplayLogger : public IReplayLogger
|
||||
{
|
||||
public:
|
||||
virtual void StartGame(JS::MutableHandleValue UNUSED(attribs)) { }
|
||||
virtual void Turn(u32 UNUSED(n), u32 UNUSED(turnLength), const std::vector<SimulationCommand>& UNUSED(commands)) { }
|
||||
virtual void Turn(u32 UNUSED(n), u32 UNUSED(turnLength), std::vector<SimulationCommand>& UNUSED(commands)) { }
|
||||
virtual void Hash(const std::string& UNUSED(hash), bool UNUSED(quick)) { }
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user