1 /* Copyright (C) 2017 Wildfire Games.
2 * This file is part of 0 A.D.
3 *
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "precompiled.h"
19
20 #include "ReplayTurnManager.h"
21
22 #include "gui/GUIManager.h"
23 #include "ps/Util.h"
24 #include "simulation2/Simulation2.h"
25
CReplayTurnManager(CSimulation2 & simulation,IReplayLogger & replay)26 CReplayTurnManager::CReplayTurnManager(CSimulation2& simulation, IReplayLogger& replay)
27 : CLocalTurnManager(simulation, replay)
28 {
29 }
30
StoreReplayCommand(u32 turn,int player,const std::string & command)31 void CReplayTurnManager::StoreReplayCommand(u32 turn, int player, const std::string& command)
32 {
33 // Using the pair we make sure that commands per turn will be processed in the correct order
34 m_ReplayCommands[turn].emplace_back(player, command);
35 }
36
StoreReplayHash(u32 turn,const std::string & hash,bool quick)37 void CReplayTurnManager::StoreReplayHash(u32 turn, const std::string& hash, bool quick)
38 {
39 m_ReplayHash[turn] = std::make_pair(hash, quick);
40 }
41
StoreReplayTurnLength(u32 turn,u32 turnLength)42 void CReplayTurnManager::StoreReplayTurnLength(u32 turn, u32 turnLength)
43 {
44 m_ReplayTurnLengths[turn] = turnLength;
45
46 // Initialize turn length
47 if (turn == 0)
48 m_TurnLength = m_ReplayTurnLengths[0];
49 }
50
StoreFinalReplayTurn(u32 turn)51 void CReplayTurnManager::StoreFinalReplayTurn(u32 turn)
52 {
53 m_FinalTurn = turn;
54 }
55
NotifyFinishedUpdate(u32 turn)56 void CReplayTurnManager::NotifyFinishedUpdate(u32 turn)
57 {
58 if (turn == 1 && m_FinalTurn == 0)
59 g_GUI->SendEventToAll("ReplayFinished");
60
61 if (turn > m_FinalTurn)
62 return;
63
64 DoTurn(turn);
65
66 // Compare hash if it exists in the replay and if we didn't have an OOS already
67 std::map<u32, std::pair<std::string, bool>>::iterator turnHashIt = m_ReplayHash.find(turn);
68 if (m_HasSyncError || turnHashIt == m_ReplayHash.end())
69 return;
70
71 std::string expectedHash = turnHashIt->second.first;
72 bool quickHash = turnHashIt->second.second;
73
74 // Compute hash
75 std::string hash;
76 ENSURE(m_Simulation2.ComputeStateHash(hash, quickHash));
77 hash = Hexify(hash);
78
79 if (hash != expectedHash)
80 {
81 m_HasSyncError = true;
82 LOGERROR("Replay out of sync on turn %d", turn);
83 g_GUI->SendEventToAll("ReplayOutOfSync");
84 }
85 }
86
DoTurn(u32 turn)87 void CReplayTurnManager::DoTurn(u32 turn)
88 {
89 debug_printf("Executing turn %u of %u\n", turn, m_FinalTurn);
90
91 m_TurnLength = m_ReplayTurnLengths[turn];
92
93 JSContext* cx = m_Simulation2.GetScriptInterface().GetContext();
94 JSAutoRequest rq(cx);
95
96 // Simulate commands for that turn
97 for (const std::pair<player_id_t, std::string>& p : m_ReplayCommands[turn])
98 {
99 JS::RootedValue command(cx);
100 m_Simulation2.GetScriptInterface().ParseJSON(p.second, &command);
101 AddCommand(m_ClientId, p.first, command, m_CurrentTurn + 1);
102 }
103
104 if (turn == m_FinalTurn)
105 g_GUI->SendEventToAll("ReplayFinished");
106 }
107