Ticket #9: t0009_visualreplay_v3_16726.patch
File t0009_visualreplay_v3_16726.patch, 23.4 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/gui/session/session.js
555 555 if (battleState) 556 556 global.music.setState(global.music.states[battleState]); 557 557 } 558 558 } 559 559 560 function onReplayFinished() 561 { 562 closeMenu(); 563 closeOpenDialogs(); 564 pauseGame(); 565 var btCaptions = [translateWithContext("replayFinished", "Yes"), translateWithContext("replayFinished", "No")]; 566 var btCode = [leaveGame, resumeGame]; 567 messageBox(400, 200, translateWithContext("replayFinished", "The replay has finished. Do you want to quit?"), translateWithContext("replayFinished","Confirmation"), 0, btCaptions, btCode); 568 } 569 560 570 /** 561 571 * updates a status bar on the GUI 562 572 * nameOfBar: name of the bar 563 573 * points: points to show 564 574 * maxPoints: max points -
binaries/data/mods/public/gui/session/session.xml
20 20 21 21 <action on="SimulationUpdate"> 22 22 onSimulationUpdate(); 23 23 </action> 24 24 25 <action on="ReplayFinished"> 26 onReplayFinished(); 27 </action> 28 25 29 <action on="Press"> 26 30 this.hidden = !this.hidden; 27 31 </action> 28 32 29 33 <!-- ================================ ================================ --> -
build/premake/premake4.lua
603 603 "third_party/tinygettext/src", 604 604 } 605 605 extern_libs = { 606 606 "iconv", 607 607 "boost", 608 "tinygettext" 608 609 } 609 610 setup_third_party_static_lib_project("tinygettext", source_dirs, extern_libs, { } ) 610 611 611 612 -- it's an external library and we don't want to modify its source to fix warnings, so we just disable them to avoid noise in the compile output 612 613 if _ACTION == "vs2013" then -
source/main.cpp
440 440 return; 441 441 442 442 // run non-visual simulation replay if requested 443 443 if (args.Has("replay")) 444 444 { 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 } 445 451 Paths paths(args); 446 452 g_VFS = CreateVfs(20 * MiB); 447 453 g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE); 448 454 MountMods(paths, GetMods(args, INIT_MODS)); 449 455 450 456 { 451 457 CReplayPlayer replay; 452 replay.Load( args.Get("replay"));458 replay.Load(replayFile); 453 459 replay.Replay(args.Has("serializationtest"), args.Has("ooslog")); 454 460 } 455 461 456 462 g_VFS.reset(); 457 463 458 464 CXeromyces::Terminate(); 459 465 return; 460 466 } 461 467 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 462 480 // run in archive-building mode if requested 463 481 if (args.Has("archivebuild")) 464 482 { 465 483 Paths paths(args); 466 484 -
source/network/NetTurnManager.cpp
1 /* Copyright (C) 201 2Wildfire Games.1 /* Copyright (C) 2015 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … 223 223 NETTURN_LOG((L"OnSyncError(%d, %hs)\n", turn, Hexify(expectedHash).c_str())); 224 224 225 225 // Only complain the first time 226 226 if (m_HasSyncError) 227 227 return; 228 m_HasSyncError = true;229 228 230 229 bool quick = !TurnNeedsFullHash(turn); 231 230 std::string hash; 232 bool ok = m_Simulation2.ComputeStateHash(hash, quick); 233 ENSURE(ok); 231 ENSURE(m_Simulation2.ComputeStateHash(hash, quick)); 234 232 235 233 OsPath path = psLogDir()/"oos_dump.txt"; 236 234 std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); 237 235 m_Simulation2.DumpDebugState(file); 238 236 file.close(); 239 237 238 hash = Hexify(hash); 239 const std::string& expectedHashHex = Hexify(expectedHash); 240 241 DisplayOOSError(turn, hash, expectedHashHex, false, &path); 242 } 243 244 void CNetTurnManager::DisplayOOSError(u32 turn, std::string& hash, const std::string& expectedHash, const bool isReplay, OsPath* path = NULL) 245 { 246 m_HasSyncError = true; 247 240 248 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"; 250 251 if (expectedHash != hash || m_CurrentTurn != turn) 252 msg << "\nCurrent state: turn " << m_CurrentTurn << ", hash " << hash << "\n\n"; 253 254 if (isReplay) 255 msg << "\nThe 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) 265 msg << "Dumping current state to " << utf8_from_wstring(OsPath(*path).string()); 266 267 LOGERROR("%s", msg.str()); 268 244 269 if (g_GUI) 245 270 g_GUI->DisplayMessageBox(600, 350, L"Sync error", wstring_from_utf8(msg.str())); 246 else247 LOGERROR("%s", msg.str());248 271 } 249 272 250 273 void CNetTurnManager::Interpolate(float simFrameLength, float realFrameLength) 251 274 { 252 275 // TODO: using m_TurnLength might be a bit dodgy when length changes - maybe … … 320 343 void CNetTurnManager::QuickSave() 321 344 { 322 345 TIMER(L"QuickSave"); 323 346 324 347 std::stringstream stream; 325 bool ok = m_Simulation2.SerializeState(stream); 326 if (!ok) 348 if (!m_Simulation2.SerializeState(stream)) 327 349 { 328 350 LOGERROR("Failed to quicksave game"); 329 351 return; 330 352 } 331 353 … … 348 370 LOGERROR("Cannot quickload game - no game was quicksaved"); 349 371 return; 350 372 } 351 373 352 374 std::stringstream stream(m_QuickSaveState); 353 bool ok = m_Simulation2.DeserializeState(stream); 354 if (!ok) 375 if (!m_Simulation2.DeserializeState(stream)) 355 376 { 356 377 LOGERROR("Failed to quickload game"); 357 378 return; 358 379 } 359 380 … … 400 421 { 401 422 bool quick = !TurnNeedsFullHash(turn); 402 423 std::string hash; 403 424 { 404 425 PROFILE3("state hash check"); 405 bool ok = m_Simulation2.ComputeStateHash(hash, quick); 406 ENSURE(ok); 426 ENSURE(m_Simulation2.ComputeStateHash(hash, quick)); 407 427 } 408 428 409 429 NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str())); 410 430 411 431 m_Replay.Hash(hash, quick); … … 450 470 { 451 471 #if 0 // this hurts performance and is only useful for verifying log replays 452 472 std::string hash; 453 473 { 454 474 PROFILE3("state hash check"); 455 bool ok = m_Simulation2.ComputeStateHash(hash); 456 ENSURE(ok); 475 ENSURE(m_Simulation2.ComputeStateHash(hash)); 457 476 } 458 477 m_Replay.Hash(hash); 459 478 #endif 460 479 } 461 480 462 481 void CNetLocalTurnManager::OnSimulationMessage(CSimulationMessage* UNUSED(msg)) 463 482 { 464 483 debug_warn(L"This should never be called"); 465 484 } 466 485 486 CNetReplayTurnManager::CNetReplayTurnManager(CSimulation2& simulation, IReplayLogger& replay) : 487 CNetLocalTurnManager(simulation, replay) 488 { 489 } 467 490 491 void CNetReplayTurnManager::StoreReplayCommand(u32 turn, int player, const std::string& command) 492 { 493 m_ReplayCommands[turn][player].push_back(command); 494 } 495 496 void CNetReplayTurnManager::StoreReplayHash(u32 turn, const std::string& hash, bool quick) 497 { 498 m_ReplayHash[turn] = std::make_pair(hash, quick); 499 } 468 500 501 void 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 510 void CNetReplayTurnManager::StoreFinalReplayTurn(u32 turn) 511 { 512 m_FinalReplayTurn = turn; 513 } 514 515 void CNetReplayTurnManager::NotifyFinishedUpdate(u32 turn) 516 { 517 if (turn > m_FinalReplayTurn) 518 return; 519 520 debug_printf("Executing turn %d of %d\n", turn, m_FinalReplayTurn); 521 DoTurn(turn); 522 523 // Compare hash if it exists in the replay and if we didn't have an oos already 524 if (m_HasSyncError || m_ReplayHash.find(turn) == m_ReplayHash.end()) 525 return; 526 527 std::string expectedHash = m_ReplayHash[turn].first; 528 bool quickHash = m_ReplayHash[turn].second; 529 530 // Compute hash 531 std::string hash; 532 ENSURE(m_Simulation2.ComputeStateHash(hash, quickHash)); 533 hash = Hexify(hash); 534 535 if (hash != expectedHash) 536 DisplayOOSError(turn, hash, expectedHash, true); 537 } 538 539 void CNetReplayTurnManager::DoTurn(u32 turn) 540 { 541 // Save turn length 542 m_TurnLength = m_ReplayTurnLengths[turn]; 543 544 // Simulate commands for that turn 545 for (auto& command : m_ReplayCommands[turn]) 546 { 547 for (size_t i = 0; i < command.second.size(); ++i) 548 { 549 JS::RootedValue data(m_Simulation2.GetScriptInterface().GetContext()); 550 m_Simulation2.GetScriptInterface().ParseJSON(command.second[i], &data); 551 AddCommand(m_ClientId, command.first, data, m_CurrentTurn + 1); 552 } 553 } 554 } 469 555 470 556 CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server) : 471 557 m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP) 472 558 { 473 559 // The first turn we will actually execute is number 2, -
source/network/NetTurnManager.h
1 /* Copyright (C) 201 2Wildfire Games.1 /* Copyright (C) 2015 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … 17 17 18 18 #ifndef INCLUDED_NETTURNMANAGER 19 19 #define INCLUDED_NETTURNMANAGER 20 20 21 21 #include "simulation2/helpers/SimulationCommand.h" 22 #include "lib/os_path.h" 22 23 23 24 #include <list> 24 25 #include <map> 26 #include <vector> 25 27 26 28 class CNetServerWorker; 27 29 class CNetClient; 28 30 class CSimulationMessage; 29 31 class CSimulation2; … … 106 108 * Called when there has been an out-of-sync error. 107 109 */ 108 110 virtual void OnSyncError(u32 turn, const std::string& expectedHash); 109 111 110 112 /** 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 /** 111 118 * Called by simulation code, to add a new command to be distributed to all clients and executed soon. 112 119 */ 113 120 virtual void PostCommand(JS::HandleValue data) = 0; 114 121 115 122 /** … … 187 194 std::list<std::string> m_TimeWarpStates; 188 195 std::string m_QuickSaveState; // TODO: should implement a proper disk-based quicksave system 189 196 std::string m_QuickSaveMetadata; 190 197 }; 191 198 199 192 200 /** 193 201 * Implementation of CNetTurnManager for network clients. 194 202 */ 195 203 class CNetClientTurnManager : public CNetTurnManager 196 204 { … … 231 239 232 240 virtual void NotifyFinishedUpdate(u32 turn); 233 241 }; 234 242 235 243 244 245 /** 246 * Implementation of CNetTurnManager for replay games. 247 */ 248 class CNetReplayTurnManager : public CNetLocalTurnManager 249 { 250 public: 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 262 protected: 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 }; 236 280 /** 237 281 * The server-side counterpart to CNetClientTurnManager. 238 282 * Records the turn state of each client, and sends turn advancement messages 239 283 * when all clients are ready. 240 284 * -
source/ps/Game.cpp
61 61 62 62 /** 63 63 * Constructor 64 64 * 65 65 **/ 66 CGame::CGame(bool disableGraphics ):66 CGame::CGame(bool disableGraphics, bool replayLog): 67 67 m_World(new CWorld(this)), 68 68 m_Simulation2(new CSimulation2(&m_World->GetUnitManager(), g_ScriptRuntime, m_World->GetTerrain())), 69 69 m_GameView(disableGraphics ? NULL : new CGameView(this)), 70 70 m_GameStarted(false), 71 71 m_Paused(false), 72 72 m_SimRate(1.0f), 73 73 m_PlayerID(-1), 74 m_IsSavedGame(false) 74 m_IsSavedGame(false), 75 m_IsReplay(false), 76 m_ReplayStream(NULL) 75 77 { 76 m_ReplayLogger = new CReplayLogger(m_Simulation2->GetScriptInterface());77 78 // TODO: should use CDummyReplayLogger unless activated by cmd-line arg, perhaps? 79 if (replayLog) 80 m_ReplayLogger = new CReplayLogger(m_Simulation2->GetScriptInterface()); 81 else 82 m_ReplayLogger = new CDummyReplayLogger(); 78 83 79 84 // Need to set the CObjectManager references after various objects have 80 85 // been initialised, so do it here rather than via the initialisers above. 81 86 if (m_GameView) 82 87 m_World->GetUnitManager().SetObjectManager(m_GameView->GetObjectManager()); 83 88 84 89 m_TurnManager = new CNetLocalTurnManager(*m_Simulation2, GetReplayLogger()); // this will get replaced if we're a net server/client 85 90 86 91 m_Simulation2->LoadDefaultScripts(); 87 92 } 88 89 93 /** 90 94 * Destructor 91 95 * 92 96 **/ 93 97 CGame::~CGame() … … 99 103 delete m_TurnManager; 100 104 delete m_GameView; 101 105 delete m_Simulation2; 102 106 delete m_World; 103 107 delete m_ReplayLogger; 108 delete m_ReplayStream; 104 109 } 105 110 106 111 void CGame::SetTurnManager(CNetTurnManager* turnManager) 107 112 { 108 113 if (m_TurnManager) … … 112 117 113 118 if (m_TurnManager) 114 119 m_TurnManager->SetPlayerID(m_PlayerID); 115 120 } 116 121 122 int CGame::LoadReplayData() 123 { 124 ENSURE(m_IsReplay); 125 ENSURE(!m_ReplayPath.empty()); 126 127 CNetReplayTurnManager* replayTurnMgr = static_cast<CNetReplayTurnManager*>(GetTurnManager()); 128 129 u32 currentTurn = 0; 130 std::string type; 131 while ((*m_ReplayStream >> type).good()) 132 { 133 if (type == "turn") 134 { 135 u32 turn = 0; 136 u32 turnLength = 0; 137 *m_ReplayStream >> turn >> turnLength; 138 ENSURE(turn == currentTurn); 139 replayTurnMgr->StoreReplayTurnLength(currentTurn, turnLength); 140 } 141 else if (type == "cmd") 142 { 143 player_id_t player; 144 *m_ReplayStream >> player; 145 146 std::string line; 147 std::getline(*m_ReplayStream, line); 148 replayTurnMgr->StoreReplayCommand(currentTurn, player, line); 149 } 150 else if (type == "hash" || type == "hash-quick") 151 { 152 bool quick = (type == "hash-quick"); 153 std::string replayHash; 154 *m_ReplayStream >> replayHash; 155 replayTurnMgr->StoreReplayHash(currentTurn, replayHash, quick); 156 } 157 else if (type == "end") 158 { 159 currentTurn++; 160 } 161 else 162 { 163 CancelLoad(L"Failed to load replay data (unrecognized content)"); 164 } 165 } 166 m_FinalReplayTurn = currentTurn; 167 replayTurnMgr->StoreFinalReplayTurn(currentTurn); 168 return 0; 169 } 170 171 bool CGame::StartReplay(const std::string& replayPath) 172 { 173 m_IsReplay = true; 174 ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface(); 175 176 SetTurnManager(new CNetReplayTurnManager(*m_Simulation2, GetReplayLogger())); 177 178 m_ReplayPath = replayPath; 179 m_ReplayStream = new std::ifstream(m_ReplayPath.c_str()); 180 181 std::string type; 182 ENSURE((*m_ReplayStream >> type).good() && type == "start"); 183 184 std::string line; 185 std::getline(*m_ReplayStream, line); 186 JS::RootedValue attribs(scriptInterface.GetContext()); 187 scriptInterface.ParseJSON(line, &attribs); 188 StartGame(&attribs, ""); 189 190 return true; 191 } 117 192 118 193 /** 119 194 * Initializes the game with the set of attributes provided. 120 195 * Makes calls to initialize the game view, world, and simulation objects. 121 196 * Calls are made to facilitate progress reporting of the initialization. … … 174 249 RegMemFun(g_Renderer.GetSingletonPtr()->GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80); 175 250 176 251 if (m_IsSavedGame) 177 252 RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000); 178 253 254 if (m_IsReplay) 255 RegMemFun(this, &CGame::LoadReplayData, L"Loading replay data", 1000); 256 179 257 LDR_EndRegistering(); 180 258 } 181 259 182 260 int CGame::LoadInitialState() 183 261 { … … 261 339 int CGame::GetPlayerID() 262 340 { 263 341 return m_PlayerID; 264 342 } 265 343 266 void CGame::SetPlayerID( int playerID)344 void CGame::SetPlayerID(player_id_t playerID) 267 345 { 268 346 m_PlayerID = playerID; 269 347 if (m_TurnManager) 270 348 m_TurnManager->SetPlayerID(m_PlayerID); 271 349 } 272 350 273 351 void CGame::StartGame(JS::MutableHandleValue attribs, const std::string& savedState) 274 352 { 275 m_ReplayLogger->StartGame(attribs); 353 if (m_ReplayLogger != false) 354 m_ReplayLogger->StartGame(attribs); 355 276 356 RegisterInit(attribs, savedState); 277 357 } 278 358 279 359 // TODO: doInterpolate is optional because Atlas interpolates explicitly, 280 360 // so that it has more control over the update rate. The game might want to … … 308 388 { 309 389 { 310 390 PROFILE3("gui sim update"); 311 391 g_GUI->SendEventToAll("SimulationUpdate"); 312 392 } 393 if (m_IsReplay && m_TurnManager->GetCurrentTurn() == m_FinalReplayTurn - 1) 394 g_GUI->SendEventToAll("ReplayFinished"); 313 395 314 396 GetView()->GetLOSTexture().MakeDirty(); 315 397 } 316 398 317 399 if (CRenderer::IsInitialised()) … … 360 442 m_PlayerColors[i] = cmpPlayer->GetColor(); 361 443 } 362 444 } 363 445 364 446 365 CColor CGame::GetPlayerColor( int player) const447 CColor CGame::GetPlayerColor(player_id_t player) const 366 448 { 367 449 if (player < 0 || player >= (int)m_PlayerColors.size()) 368 450 return BrokenColor; 369 451 370 452 return m_PlayerColors[player]; -
source/ps/Game.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2015 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … 20 20 21 21 #include "ps/Errors.h" 22 22 #include <vector> 23 23 24 24 #include "scriptinterface/ScriptVal.h" 25 #include "simulation2/helpers/Player.h" 25 26 26 27 class CWorld; 27 28 class CSimulation2; 28 29 class CGameView; 29 30 class CNetTurnManager; … … 58 59 /** 59 60 * Timescale multiplier for simulation rate. 60 61 **/ 61 62 float m_SimRate; 62 63 63 int m_PlayerID;64 player_id_t m_PlayerID; 64 65 65 66 CNetTurnManager* m_TurnManager; 66 67 67 68 public: 68 CGame(bool disableGraphics = false );69 CGame(bool disableGraphics = false, bool replayLog = true); 69 70 ~CGame(); 70 71 71 72 /** 72 73 * the game is paused and no updates will be performed if true. 73 74 **/ 74 75 bool m_Paused; 75 76 76 77 void StartGame(JS::MutableHandleValue attribs, const std::string& savedState); 77 78 PSRETURN ReallyStartGame(); 78 79 80 bool StartReplay(const std::string& replayPath); 81 79 82 /** 80 83 * Periodic heartbeat that controls the process. performs all per-frame updates. 81 84 * Simulation update is called and game status update is called. 82 85 * 83 86 * @param deltaRealTime Elapsed real time since last beat/frame, in seconds. … … 88 91 bool Update(const double deltaRealTime, bool doInterpolate = true); 89 92 90 93 void Interpolate(float simFrameLength, float realFrameLength); 91 94 92 95 int GetPlayerID(); 93 void SetPlayerID( int playerID);96 void SetPlayerID(player_id_t playerID); 94 97 95 98 /** 96 99 * Retrieving player colors from scripts is slow, so this updates an 97 100 * internal cache of all players' colors. 98 101 * Call this just before rendering, so it will always have the latest 99 102 * colors. 100 103 */ 101 104 void CachePlayerColors(); 102 105 103 CColor GetPlayerColor( int player) const;106 CColor GetPlayerColor(player_id_t player) const; 104 107 105 108 /** 106 109 * Get m_GameStarted. 107 110 * 108 111 * @return bool the value of m_GameStarted. … … 169 172 std::vector<CColor> m_PlayerColors; 170 173 171 174 int LoadInitialState(); 172 175 std::string m_InitialSavedState; // valid between RegisterInit and LoadInitialState 173 176 bool m_IsSavedGame; // true if loading a saved game; false for a new game 177 178 int LoadReplayData(); 179 std::string m_ReplayPath; 180 bool m_IsReplay; 181 std::istream* m_ReplayStream; 182 u32 m_FinalReplayTurn; 174 183 }; 175 184 176 185 extern CGame *g_Game; 177 186 178 187 #endif -
source/ps/GameSetup/GameSetup.cpp
879 879 srand(time(NULL)); // NOTE: this rand should *not* be used for simulation! 880 880 } 881 881 882 882 bool Autostart(const CmdLineArgs& args); 883 883 884 // Returns true if and only if the user has intended to replay a file 885 bool VisualReplay(const std::string replayFile); 886 884 887 bool Init(const CmdLineArgs& args, int flags) 885 888 { 886 889 h_mgr_init(); 887 890 888 891 // Do this as soon as possible, because it chdirs … … 1071 1074 1072 1075 ogl_WarnIfError(); 1073 1076 1074 1077 try 1075 1078 { 1076 if (! Autostart(args))1079 if (!VisualReplay(args.Get("replay-visual")) && !Autostart(args)) 1077 1080 { 1078 1081 const bool setup_gui = ((flags & INIT_NO_GUI) == 0); 1079 1082 // We only want to display the splash screen at startup 1080 1083 shared_ptr<ScriptInterface> scriptInterface = g_GUI->GetScriptInterface(); 1081 1084 JSContext* cx = scriptInterface->GetContext(); … … 1468 1471 } 1469 1472 1470 1473 return true; 1471 1474 } 1472 1475 1476 bool 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 1473 1497 void CancelLoad(const CStrW& message) 1474 1498 { 1475 1499 shared_ptr<ScriptInterface> pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface(); 1476 1500 JSContext* cx = pScriptInterface->GetContext(); 1477 1501 JSAutoRequest rq(cx); -
source/ps/Replay.h
54 54 */ 55 55 class CDummyReplayLogger : public IReplayLogger 56 56 { 57 57 public: 58 58 virtual void StartGame(JS::MutableHandleValue UNUSED(attribs)) { } 59 virtual void Turn(u32 UNUSED(n), u32 UNUSED(turnLength), conststd::vector<SimulationCommand>& UNUSED(commands)) { }59 virtual void Turn(u32 UNUSED(n), u32 UNUSED(turnLength), std::vector<SimulationCommand>& UNUSED(commands)) { } 60 60 virtual void Hash(const std::string& UNUSED(hash), bool UNUSED(quick)) { } 61 61 }; 62 62 63 63 /** 64 64 * Implementation of IReplayLogger that saves data to a file in the logs directory.