Pyrogenesis  trunk
TurnManager.h
Go to the documentation of this file.
1 /* Copyright (C) 2021 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 #ifndef INCLUDED_TURNMANAGER
19 #define INCLUDED_TURNMANAGER
20 
21 #include "ps/CStr.h"
23 
24 #include <list>
25 #include <map>
26 #include <vector>
27 #include <deque>
28 
29 class CSimulationMessage;
30 class CSimulation2;
31 class IReplayLogger;
32 
33 /**
34  * This file defines the base class of the turn managers for clients, local games and replays.
35  * The basic idea of our turn managing system across a network is as in this article:
36  * http://www.gamasutra.com/view/feature/3094/1500_archers_on_a_288_network_.php?print=1
37  *
38  * Each player performs the simulation for turn N.
39  * User input is translated into commands scheduled for execution in turn N+2 which are
40  * distributed to all other clients.
41  * After a while, a client wants to perform the simulation for turn N+1,
42  * which first requires that it has all the other clients' commands for turn N+1.
43  * In that case, it does the simulation and tells all the other clients (via the server)
44  * it has finished sending commands for turn N+2, and it starts sending commands for turn N+3.
45  *
46  * Commands are redistributed immediately by the server.
47  * To ensure a consistent execution of commands, they are each associated with a
48  * client session ID (which is globally unique and consistent), which is used to sort them.
49  */
50 
51 /**
52  * Default turn length in SP & MP.
53  * This value should be as low as possible, while not introducing un-necessary lag.
54  */
55 inline constexpr u32 DEFAULT_TURN_LENGTH = 200;
56 
57 /**
58  * In single-player, commands are directly scheduled for the next turn.
59  */
60 inline constexpr u32 COMMAND_DELAY_SP = 1;
61 
62 /**
63  * In multi-player, clients can only compute turn N if all clients have finished sending commands for it,
64  * i.e. N < CurrentTurn + COMMAND_DELAY for all clients.
65  * Commands are sent from client to server to client, and both client and network can lag.
66  * If a client reaches turn CURRENT_TURN + COMMAND_DELAY - 1, it'll freeze while waiting for commands.
67  * To avoid that, we increase the command-delay to make sure that in general players will have received all commands
68  * by the time they reach a given turn. Keep in mind the minimum delay is one turn.
69  * This value should be as low as possible while avoiding 'freezing' in general usage.
70  * TODO:
71  * - this command-delay could vary based on server-client pings
72  * - it ought be possible to send commands in a P2P fashion (with server verification), which would lower the ping.
73  */
74 inline constexpr u32 COMMAND_DELAY_MP = 4;
75 
76 /**
77  * Common turn system (used by clients and offline games).
78  */
80 {
82 public:
83  /**
84  * Construct for a given network session ID.
85  */
86  CTurnManager(CSimulation2& simulation, u32 defaultTurnLength, u32 commandDelay, int clientId, IReplayLogger& replay);
87 
88  virtual ~CTurnManager() { }
89 
90  void ResetState(u32 newCurrentTurn, u32 newReadyTurn);
91 
92  /**
93  * Set the current user's player ID, which will be added into command messages.
94  */
95  void SetPlayerID(int playerId);
96 
97  /**
98  * Advance the simulation by a certain time. If this brings us past the current
99  * turn length, the next turns are processed and the function returns true.
100  * Otherwise, nothing happens and it returns false.
101  *
102  * @param simFrameLength Length of the previous frame, in simulation seconds
103  * @param maxTurns Maximum number of turns to simulate at once
104  */
105  bool Update(float simFrameLength, size_t maxTurns);
106 
107  /**
108  * Advance the simulation by as much as possible. Intended for catching up
109  * over a small number of turns when rejoining a multiplayer match.
110  * Returns true if it advanced by at least one turn.
111  */
112  bool UpdateFastForward();
113 
114  /**
115  * Advance the graphics by a certain time.
116  * @param simFrameLength Length of the previous frame, in simulation seconds
117  * @param realFrameLength Length of the previous frame, in real time seconds
118  */
119  void Interpolate(float simFrameLength, float realFrameLength);
120 
121  /**
122  * Called by networking code when a simulation message is received.
123  */
124  virtual void OnSimulationMessage(CSimulationMessage* msg) = 0;
125 
126  /**
127  * Called by simulation code, to add a new command to be distributed to all clients and executed soon.
128  */
129  virtual void PostCommand(JS::HandleValue data) = 0;
130 
131  /**
132  * Called when all commands for a given turn have been received.
133  * This allows Update to progress to that turn.
134  */
135  void FinishedAllCommands(u32 turn, u32 turnLength);
136 
137  /**
138  * Enables the recording of state snapshots every @p numTurns,
139  * which can be jumped back to via RewindTimeWarp().
140  * If @p numTurns is 0 then recording is disabled.
141  */
142  void EnableTimeWarpRecording(size_t numTurns);
143 
144  /**
145  * Jumps back to the latest recorded state snapshot (if any).
146  */
147  void RewindTimeWarp();
148 
149  void QuickSave(JS::HandleValue GUIMetadata);
150  void QuickLoad();
151 
152  u32 GetCurrentTurn() const { return m_CurrentTurn; }
153 
154  /**
155  * @return how many turns are ready to be computed.
156  * (used to detect players/observers that fall behind the live game.
157  */
159 
160 protected:
161  /**
162  * Store a command to be executed at a given turn.
163  */
164  void AddCommand(int client, int player, JS::HandleValue data, u32 turn);
165 
166  /**
167  * Called when this client has finished sending all its commands scheduled for the given turn.
168  */
169  virtual void NotifyFinishedOwnCommands(u32 turn) = 0;
170 
171  /**
172  * Called when this client has finished a simulation update.
173  */
174  virtual void NotifyFinishedUpdate(u32 turn) = 0;
175 
176  /**
177  * Returns whether we should compute a complete state hash for the given turn,
178  * instead of a quick less-complete hash.
179  */
180  bool TurnNeedsFullHash(u32 turn) const;
181 
183 
184  /// The turn that we have most recently executed
186 
187  // Current command delay (commands are scheduled for m_CurrentTurn + m_CommandDelay)
189 
190  /// The latest turn for which we have received all commands from all clients
192 
193  // Current turn length
195 
196  /// Commands queued at each turn (index 0 is for m_CurrentTurn+1)
197  std::deque<std::map<u32, std::vector<SimulationCommand>>> m_QueuedCommands;
198 
201 
202  /// Simulation time remaining until we ought to execute the next turn (as a negative value to
203  /// add elapsed time increments to until we reach 0).
205 
207 
208  // The number of the last turn that is allowed to be executed (used for replays)
210 
211 private:
212  static const CStr EventNameSavegameLoaded;
213 
214  size_t m_TimeWarpNumTurns; // 0 if disabled
215  std::list<std::string> m_TimeWarpStates;
216  std::string m_QuickSaveState; // TODO: should implement a proper disk-based quicksave system
217  JS::PersistentRootedValue m_QuickSaveMetadata;
218 };
219 
220 #endif // INCLUDED_TURNMANAGER
bool TurnNeedsFullHash(u32 turn) const
Returns whether we should compute a complete state hash for the given turn, instead of a quick less-c...
Definition: TurnManager.cpp:243
u32 m_CurrentTurn
The turn that we have most recently executed.
Definition: TurnManager.h:185
CSimulation2 & m_Simulation2
Definition: TurnManager.h:182
int m_PlayerId
Definition: TurnManager.h:199
bool Update(float simFrameLength, size_t maxTurns)
Advance the simulation by a certain time.
Definition: TurnManager.cpp:65
uint m_ClientId
Definition: TurnManager.h:200
virtual void NotifyFinishedUpdate(u32 turn)=0
Called when this client has finished a simulation update.
u32 GetPendingTurns() const
Definition: TurnManager.h:158
u32 m_CommandDelay
Definition: TurnManager.h:188
void AddCommand(int client, int player, JS::HandleValue data, u32 turn)
Store a command to be executed at a given turn.
Definition: TurnManager.cpp:209
NONCOPYABLE(CTurnManager)
bool UpdateFastForward()
Advance the simulation by as much as possible.
Definition: TurnManager.cpp:157
virtual void OnSimulationMessage(CSimulationMessage *msg)=0
Called by networking code when a simulation message is received.
void QuickLoad()
Definition: TurnManager.cpp:303
u32 m_ReadyTurn
The latest turn for which we have received all commands from all clients.
Definition: TurnManager.h:191
Replay log recorder interface.
Definition: Replay.h:35
static const CStr EventNameSavegameLoaded
Definition: TurnManager.h:212
IReplayLogger & m_Replay
Definition: TurnManager.h:206
void RewindTimeWarp()
Jumps back to the latest recorded state snapshot (if any).
Definition: TurnManager.cpp:265
virtual ~CTurnManager()
Definition: TurnManager.h:88
Common turn system (used by clients and offline games).
Definition: TurnManager.h:79
u32 m_FinalTurn
Definition: TurnManager.h:209
Public API for simulation system.
Definition: Simulation2.h:46
std::deque< std::map< u32, std::vector< SimulationCommand > > > m_QueuedCommands
Commands queued at each turn (index 0 is for m_CurrentTurn+1)
Definition: TurnManager.h:197
void Interpolate(float simFrameLength, float realFrameLength)
Advance the graphics by a certain time.
Definition: TurnManager.cpp:195
uint32_t u32
Definition: types.h:39
float m_DeltaSimTime
Simulation time remaining until we ought to execute the next turn (as a negative value to add elapsed...
Definition: TurnManager.h:204
void EnableTimeWarpRecording(size_t numTurns)
Enables the recording of state snapshots every numTurns, which can be jumped back to via RewindTimeWa...
Definition: TurnManager.cpp:259
constexpr u32 COMMAND_DELAY_SP
In single-player, commands are directly scheduled for the next turn.
Definition: TurnManager.h:60
constexpr u32 COMMAND_DELAY_MP
In multi-player, clients can only compute turn N if all clients have finished sending commands for it...
Definition: TurnManager.h:74
std::string m_QuickSaveState
Definition: TurnManager.h:216
void SetPlayerID(int playerId)
Set the current user&#39;s player ID, which will be added into command messages.
Definition: TurnManager.cpp:60
u32 GetCurrentTurn() const
Definition: TurnManager.h:152
void QuickSave(JS::HandleValue GUIMetadata)
Definition: TurnManager.cpp:281
constexpr u32 DEFAULT_TURN_LENGTH
This file defines the base class of the turn managers for clients, local games and replays...
Definition: TurnManager.h:55
std::list< std::string > m_TimeWarpStates
Definition: TurnManager.h:215
JS::PersistentRootedValue m_QuickSaveMetadata
Definition: TurnManager.h:217
size_t m_TimeWarpNumTurns
Definition: TurnManager.h:214
u32 m_TurnLength
Definition: TurnManager.h:194
unsigned int uint
Definition: types.h:42
void ResetState(u32 newCurrentTurn, u32 newReadyTurn)
Definition: TurnManager.cpp:50
CTurnManager(CSimulation2 &simulation, u32 defaultTurnLength, u32 commandDelay, int clientId, IReplayLogger &replay)
Construct for a given network session ID.
Definition: TurnManager.cpp:40
void FinishedAllCommands(u32 turn, u32 turnLength)
Called when all commands for a given turn have been received.
Definition: TurnManager.cpp:234
virtual void PostCommand(JS::HandleValue data)=0
Called by simulation code, to add a new command to be distributed to all clients and executed soon...
virtual void NotifyFinishedOwnCommands(u32 turn)=0
Called when this client has finished sending all its commands scheduled for the given turn...
Special message type for simulation commands.
Definition: NetMessage.h:113