Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
NetTurnManager.h
Go to the documentation of this file.
1 /* Copyright (C) 2012 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_NETTURNMANAGER
19 #define INCLUDED_NETTURNMANAGER
20 
22 
23 #include <list>
24 #include <map>
25 
26 class CNetServerWorker;
27 class CNetClient;
28 class CSimulationMessage;
29 class CSimulation2;
30 class IReplayLogger;
31 
32 /*
33  * This file deals with the logic of the network turn system. The basic idea is as in
34  * http://www.gamasutra.com/view/feature/3094/1500_archers_on_a_288_network_.php?print=1
35  *
36  * Each player performs the simulation for turn N.
37  * User input is translated into commands scheduled for execution in turn N+2 which are
38  * distributed to all other clients.
39  * After a while, a player wants to perform the simulation for turn N+1,
40  * which first requires that it has all the other clients' commands for turn N+1.
41  * In that case, it does the simulation and tells all the other clients (via the server)
42  * it has finished sending commands for turn N+2, and it starts sending commands for turn N+3.
43  *
44  * Commands are redistributed immediately by the server.
45  * To ensure a consistent execution of commands, they are each associated with a
46  * client session ID (which is globally unique and consistent), which is used to sort them.
47  */
48 
49 /**
50  * Common network turn system (used by clients and offline games).
51  */
53 {
55 public:
56  /**
57  * Construct for a given network session ID.
58  */
59  CNetTurnManager(CSimulation2& simulation, u32 defaultTurnLength, int clientId, IReplayLogger& replay);
60 
61  virtual ~CNetTurnManager() { }
62 
63  void ResetState(u32 newCurrentTurn, u32 newReadyTurn);
64 
65  /**
66  * Set the current user's player ID, which will be added into command messages.
67  */
68  void SetPlayerID(int playerId);
69 
70  /**
71  * Advance the simulation by a certain time. If this brings us past the current
72  * turn length, the next turns are processed and the function returns true.
73  * Otherwise, nothing happens and it returns false.
74  *
75  * @param simFrameLength Length of the previous frame, in simulation seconds
76  * @param maxTurns Maximum number of turns to simulate at once
77  */
78  bool Update(float simFrameLength, size_t maxTurns);
79 
80  /**
81  * Advance the simulation by as much as possible. Intended for catching up
82  * over a small number of turns when rejoining a multiplayer match.
83  * Returns true if it advanced by at least one turn.
84  */
85  bool UpdateFastForward();
86 
87  /**
88  * Returns whether Update(simFrameLength, ...) will process at least one new turn.
89  * @param simFrameLength Length of the previous frame, in simulation seconds
90  */
91  bool WillUpdate(float simFrameLength);
92 
93  /**
94  * Advance the graphics by a certain time.
95  * @param simFrameLength Length of the previous frame, in simulation seconds
96  * @param realFrameLength Length of the previous frame, in real time seconds
97  */
98  void Interpolate(float simFrameLength, float realFrameLength);
99 
100  /**
101  * Called by networking code when a simulation message is received.
102  */
103  virtual void OnSimulationMessage(CSimulationMessage* msg) = 0;
104 
105  /**
106  * Called when there has been an out-of-sync error.
107  */
108  virtual void OnSyncError(u32 turn, const std::string& expectedHash);
109 
110  /**
111  * Called by simulation code, to add a new command to be distributed to all clients and executed soon.
112  */
113  virtual void PostCommand(CScriptValRooted data) = 0;
114 
115  /**
116  * Called when all commands for a given turn have been received.
117  * This allows Update to progress to that turn.
118  */
119  void FinishedAllCommands(u32 turn, u32 turnLength);
120 
121  /**
122  * Enables the recording of state snapshots every @p numTurns,
123  * which can be jumped back to via RewindTimeWarp().
124  * If @p numTurns is 0 then recording is disabled.
125  */
126  void EnableTimeWarpRecording(size_t numTurns);
127 
128  /**
129  * Jumps back to the latest recorded state snapshot (if any).
130  */
131  void RewindTimeWarp();
132 
133  void QuickSave();
134  void QuickLoad();
135 
137 
138 protected:
139  /**
140  * Store a command to be executed at a given turn.
141  */
142  void AddCommand(int client, int player, CScriptValRooted data, u32 turn);
143 
144  /**
145  * Called when this client has finished sending all its commands scheduled for the given turn.
146  */
147  virtual void NotifyFinishedOwnCommands(u32 turn) = 0;
148 
149  /**
150  * Called when this client has finished a simulation update.
151  */
152  virtual void NotifyFinishedUpdate(u32 turn) = 0;
153 
154  /**
155  * Returns whether we should compute a complete state hash for the given turn,
156  * instead of a quick less-complete hash.
157  */
158  bool TurnNeedsFullHash(u32 turn);
159 
161 
162  /// The turn that we have most recently executed
164 
165  /// The latest turn for which we have received all commands from all clients
167 
168  // Current turn length
170 
171  /// Commands queued at each turn (index 0 is for m_CurrentTurn+1)
172  std::deque<std::map<u32, std::vector<SimulationCommand> > > m_QueuedCommands;
173 
176 
177  /// Simulation time remaining until we ought to execute the next turn (as a negative value to
178  /// add elapsed time increments to until we reach 0).
180 
182 
184 
185 private:
186  size_t m_TimeWarpNumTurns; // 0 if disabled
187  std::list<std::string> m_TimeWarpStates;
188  std::string m_QuickSaveState; // TODO: should implement a proper disk-based quicksave system
189  std::string m_QuickSaveMetadata;
190 };
191 
192 /**
193  * Implementation of CNetTurnManager for network clients.
194  */
196 {
197 public:
198  CNetClientTurnManager(CSimulation2& simulation, CNetClient& client, int clientId, IReplayLogger& replay);
199 
200  virtual void OnSimulationMessage(CSimulationMessage* msg);
201 
202  virtual void PostCommand(CScriptValRooted data);
203 
204 protected:
205  virtual void NotifyFinishedOwnCommands(u32 turn);
206 
207  virtual void NotifyFinishedUpdate(u32 turn);
208 
210 };
211 
212 /**
213  * Implementation of CNetTurnManager for offline games.
214  */
216 {
217 public:
218  CNetLocalTurnManager(CSimulation2& simulation, IReplayLogger& replay);
219 
220  virtual void OnSimulationMessage(CSimulationMessage* msg);
221 
222  virtual void PostCommand(CScriptValRooted data);
223 
224 protected:
225  virtual void NotifyFinishedOwnCommands(u32 turn);
226 
227  virtual void NotifyFinishedUpdate(u32 turn);
228 };
229 
230 
231 /**
232  * The server-side counterpart to CNetClientTurnManager.
233  * Records the turn state of each client, and sends turn advancement messages
234  * when all clients are ready.
235  *
236  * Thread-safety:
237  * - This is constructed and used by CNetServerWorker in the network server thread.
238  */
240 {
242 public:
244 
245  void NotifyFinishedClientCommands(int client, u32 turn);
246 
247  void NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash);
248 
249  /**
250  * Inform the turn manager of a new client who will be sending commands.
251  */
252  void InitialiseClient(int client, u32 turn);
253 
254  /**
255  * Inform the turn manager that a previously-initialised client has left the game
256  * and will no longer be sending commands.
257  */
258  void UninitialiseClient(int client);
259 
260  void SetTurnLength(u32 msecs);
261 
262  /**
263  * Returns the latest turn for which all clients are ready;
264  * they will have already been told to execute this turn.
265  */
267 
268  /**
269  * Returns the turn length that was used for the given turn.
270  * Requires turn <= GetReadyTurn().
271  */
272  u32 GetSavedTurnLength(u32 turn);
273 
274 protected:
275  void CheckClientsReady();
276 
277  /// The latest turn for which we have received all commands from all clients
279 
280  // Client ID -> ready turn number (the latest turn for which all commands have been received from that client)
281  std::map<int, u32> m_ClientsReady;
282 
283  // Client ID -> last known simulated turn number (for which we have the state hash)
284  // (the client has reached the start of this turn, not done the update for it yet)
285  std::map<int, u32> m_ClientsSimulated;
286 
287  // Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted
288  std::map<u32, std::map<int, std::string> > m_ClientStateHashes;
289 
290  // Current turn length
292 
293  // Turn lengths for all previously executed turns
294  std::vector<u32> m_SavedTurnLengths;
295 
297 };
298 
299 #endif // INCLUDED_NETTURNMANAGER
std::map< u32, std::map< int, std::string > > m_ClientStateHashes
CNetTurnManager(CSimulation2 &simulation, u32 defaultTurnLength, int clientId, IReplayLogger &replay)
Construct for a given network session ID.
std::vector< u32 > m_SavedTurnLengths
CNetClientTurnManager(CSimulation2 &simulation, CNetClient &client, int clientId, IReplayLogger &replay)
NONCOPYABLE(CNetServerTurnManager)
void UninitialiseClient(int client)
Inform the turn manager that a previously-initialised client has left the game and will no longer be ...
virtual ~CNetTurnManager()
CNetLocalTurnManager(CSimulation2 &simulation, IReplayLogger &replay)
virtual void NotifyFinishedOwnCommands(u32 turn)
Called when this client has finished sending all its commands scheduled for the given turn...
std::list< std::string > m_TimeWarpStates
void EnableTimeWarpRecording(size_t numTurns)
Enables the recording of state snapshots every numTurns, which can be jumped back to via RewindTimeWa...
virtual void NotifyFinishedOwnCommands(u32 turn)
Called when this client has finished sending all its commands scheduled for the given turn...
float m_DeltaSimTime
Simulation time remaining until we ought to execute the next turn (as a negative value to add elapsed...
void NotifyFinishedClientUpdate(int client, u32 turn, const std::string &hash)
u32 m_ReadyTurn
The latest turn for which we have received all commands from all clients.
Replay log recorder interface.
Definition: Replay.h:29
Implementation of CNetTurnManager for offline games.
u32 GetSavedTurnLength(u32 turn)
Returns the turn length that was used for the given turn.
std::string m_QuickSaveState
virtual void NotifyFinishedUpdate(u32 turn)
Called when this client has finished a simulation update.
IReplayLogger & m_Replay
Public API for simulation system.
Definition: Simulation2.h:46
bool WillUpdate(float simFrameLength)
Returns whether Update(simFrameLength, ...) will process at least one new turn.
virtual void NotifyFinishedUpdate(u32 turn)
Called when this client has finished a simulation update.
void SetTurnLength(u32 msecs)
size_t m_TimeWarpNumTurns
u32 m_ReadyTurn
The latest turn for which we have received all commands from all clients.
void InitialiseClient(int client, u32 turn)
Inform the turn manager of a new client who will be sending commands.
virtual void OnSyncError(u32 turn, const std::string &expectedHash)
Called when there has been an out-of-sync error.
void ResetState(u32 newCurrentTurn, u32 newReadyTurn)
Common network turn system (used by clients and offline games).
virtual void NotifyFinishedUpdate(u32 turn)=0
Called when this client has finished a simulation update.
void AddCommand(int client, int player, CScriptValRooted data, u32 turn)
Store a command to be executed at a given turn.
virtual void PostCommand(CScriptValRooted data)
Called by simulation code, to add a new command to be distributed to all clients and executed soon...
virtual void PostCommand(CScriptValRooted data)
Called by simulation code, to add a new command to be distributed to all clients and executed soon...
NONCOPYABLE(CNetTurnManager)
std::deque< std::map< u32, std::vector< SimulationCommand > > > m_QueuedCommands
Commands queued at each turn (index 0 is for m_CurrentTurn+1)
bool Update(float simFrameLength, size_t maxTurns)
Advance the simulation by a certain time.
void FinishedAllCommands(u32 turn, u32 turnLength)
Called when all commands for a given turn have been received.
void NotifyFinishedClientCommands(int client, u32 turn)
void SetPlayerID(int playerId)
Set the current user&#39;s player ID, which will be added into command messages.
void Interpolate(float simFrameLength, float realFrameLength)
Advance the graphics by a certain time.
std::map< int, u32 > m_ClientsReady
CNetServerTurnManager(CNetServerWorker &server)
#define u32
Definition: types.h:41
CNetServerWorker & m_NetServer
Network client.
Definition: NetClient.h:57
std::string m_QuickSaveMetadata
bool UpdateFastForward()
Advance the simulation by as much as possible.
Implementation of CNetTurnManager for network clients.
u32 m_CurrentTurn
The turn that we have most recently executed.
virtual void OnSimulationMessage(CSimulationMessage *msg)
Called by networking code when a simulation message is received.
virtual void NotifyFinishedOwnCommands(u32 turn)=0
Called when this client has finished sending all its commands scheduled for the given turn...
std::map< int, u32 > m_ClientsSimulated
virtual void PostCommand(CScriptValRooted data)=0
Called by simulation code, to add a new command to be distributed to all clients and executed soon...
CNetClient & m_NetClient
virtual void OnSimulationMessage(CSimulationMessage *msg)
Called by networking code when a simulation message is received.
virtual void OnSimulationMessage(CSimulationMessage *msg)=0
Called by networking code when a simulation message is received.
u32 GetReadyTurn()
Returns the latest turn for which all clients are ready; they will have already been told to execute ...
void RewindTimeWarp()
Jumps back to the latest recorded state snapshot (if any).
Network server worker thread.
Definition: NetServer.h:160
bool TurnNeedsFullHash(u32 turn)
Returns whether we should compute a complete state hash for the given turn, instead of a quick less-c...
CSimulation2 & m_Simulation2
The server-side counterpart to CNetClientTurnManager.
Special message type for simulation commands.
Definition: NetMessage.h:113