Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
NetTurnManager.cpp
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 #include "precompiled.h"
19 
20 #include "NetTurnManager.h"
21 
22 #include "network/NetServer.h"
23 #include "network/NetClient.h"
24 #include "network/NetMessage.h"
25 
26 #include "gui/GUIManager.h"
27 #include "maths/MathUtil.h"
28 #include "ps/CLogger.h"
29 #include "ps/Profile.h"
30 #include "ps/Pyrogenesis.h"
31 #include "ps/Replay.h"
32 #include "ps/SavedGame.h"
35 
36 #include <sstream>
37 #include <fstream>
38 #include <iomanip>
39 
40 static const int DEFAULT_TURN_LENGTH_MP = 500;
41 static const int DEFAULT_TURN_LENGTH_SP = 200;
42 
43 static const int COMMAND_DELAY = 2;
44 
45 #if 0
46 #define NETTURN_LOG(args) debug_printf args
47 #else
48 #define NETTURN_LOG(args)
49 #endif
50 
51 static std::wstring Hexify(const std::string& s)
52 {
53  std::wstringstream str;
54  str << std::hex;
55  for (size_t i = 0; i < s.size(); ++i)
56  str << std::setfill(L'0') << std::setw(2) << (int)(unsigned char)s[i];
57  return str.str();
58 }
59 
60 CNetTurnManager::CNetTurnManager(CSimulation2& simulation, u32 defaultTurnLength, int clientId, IReplayLogger& replay) :
61  m_Simulation2(simulation), m_CurrentTurn(0), m_ReadyTurn(1), m_TurnLength(defaultTurnLength), m_DeltaSimTime(0),
62  m_PlayerId(-1), m_ClientId(clientId), m_HasSyncError(false), m_Replay(replay),
63  m_TimeWarpNumTurns(0)
64 {
65  // When we are on turn n, we schedule new commands for n+2.
66  // We know that all other clients have finished scheduling commands for n (else we couldn't have got here).
67  // We know we have not yet finished scheduling commands for n+2.
68  // Hence other clients can be on turn n-1, n, n+1, and no other.
69  // So they can be sending us commands scheduled for n+1, n+2, n+3.
70  // So we need a 3-element buffer:
71  m_QueuedCommands.resize(COMMAND_DELAY + 1);
72 }
73 
74 void CNetTurnManager::ResetState(u32 newCurrentTurn, u32 newReadyTurn)
75 {
76  m_CurrentTurn = newCurrentTurn;
77  m_ReadyTurn = newReadyTurn;
78  m_DeltaSimTime = 0;
79  size_t queuedCommandsSize = m_QueuedCommands.size();
80  m_QueuedCommands.clear();
81  m_QueuedCommands.resize(queuedCommandsSize);
82 }
83 
84 void CNetTurnManager::SetPlayerID(int playerId)
85 {
86  m_PlayerId = playerId;
87 }
88 
89 bool CNetTurnManager::WillUpdate(float simFrameLength)
90 {
91  // Keep this in sync with the return value of Update()
92 
93  if (m_DeltaSimTime + simFrameLength < 0)
94  return false;
95 
97  return false;
98 
99  return true;
100 }
101 
102 bool CNetTurnManager::Update(float simFrameLength, size_t maxTurns)
103 {
104  m_DeltaSimTime += simFrameLength;
105 
106  // If we haven't reached the next turn yet, do nothing
107  if (m_DeltaSimTime < 0)
108  return false;
109 
110  NETTURN_LOG((L"Update current=%d ready=%d\n", m_CurrentTurn, m_ReadyTurn));
111 
112  // Check that the next turn is ready for execution
113  if (m_ReadyTurn <= m_CurrentTurn)
114  {
115  // Oops, we wanted to start the next turn but it's not ready yet -
116  // there must be too much network lag.
117  // TODO: complain to the user.
118  // TODO: send feedback to the server to increase the turn length.
119 
120  // Reset the next-turn timer to 0 so we try again next update but
121  // so we don't rush to catch up in subsequent turns.
122  // TODO: we should do clever rate adjustment instead of just pausing like this.
123  m_DeltaSimTime = 0;
124 
125  return false;
126  }
127 
128  maxTurns = std::max((size_t)1, maxTurns); // always do at least one turn
129 
130  for (size_t i = 0; i < maxTurns; ++i)
131  {
132  // Check that we've reached the i'th next turn
133  if (m_DeltaSimTime < 0)
134  break;
135 
136  // Check that the i'th next turn is still ready
137  if (m_ReadyTurn <= m_CurrentTurn)
138  break;
139 
141 
142  m_CurrentTurn += 1; // increase the turn number now, so Update can send new commands for a subsequent turn
143 
144  // Clean up any destroyed entities since the last turn (e.g. placement previews
145  // or rally point flags generated by the GUI). (Must do this before the time warp
146  // serialization.)
148 
149  // Save the current state for rewinding, if enabled
151  {
152  PROFILE3("time warp serialization");
153  std::stringstream stream;
155  m_TimeWarpStates.push_back(stream.str());
156  }
157 
158  // Put all the client commands into a single list, in a globally consistent order
159  std::vector<SimulationCommand> commands;
160  for (std::map<u32, std::vector<SimulationCommand> >::iterator it = m_QueuedCommands[0].begin(); it != m_QueuedCommands[0].end(); ++it)
161  {
162  commands.insert(commands.end(), it->second.begin(), it->second.end());
163  }
164  m_QueuedCommands.pop_front();
165  m_QueuedCommands.resize(m_QueuedCommands.size() + 1);
166 
167  m_Replay.Turn(m_CurrentTurn-1, m_TurnLength, commands);
168 
169  NETTURN_LOG((L"Running %d cmds\n", commands.size()));
170 
171  m_Simulation2.Update(m_TurnLength, commands);
172 
174 
175  // Set the time for the next turn update
176  m_DeltaSimTime -= m_TurnLength / 1000.f;
177  }
178 
179  return true;
180 }
181 
183 {
184  m_DeltaSimTime = 0;
185 
186  NETTURN_LOG((L"UpdateFastForward current=%d ready=%d\n", m_CurrentTurn, m_ReadyTurn));
187 
188  // Check that the next turn is ready for execution
189  if (m_ReadyTurn <= m_CurrentTurn)
190  return false;
191 
192  while (m_ReadyTurn > m_CurrentTurn)
193  {
194  // TODO: It would be nice to remove some of the duplication with Update()
195  // (This is similar but doesn't call any Notify functions or update DeltaTime,
196  // it just updates the simulation state)
197 
198  m_CurrentTurn += 1;
199 
201 
202  // Put all the client commands into a single list, in a globally consistent order
203  std::vector<SimulationCommand> commands;
204  for (std::map<u32, std::vector<SimulationCommand> >::iterator it = m_QueuedCommands[0].begin(); it != m_QueuedCommands[0].end(); ++it)
205  {
206  commands.insert(commands.end(), it->second.begin(), it->second.end());
207  }
208  m_QueuedCommands.pop_front();
209  m_QueuedCommands.resize(m_QueuedCommands.size() + 1);
210 
211  m_Replay.Turn(m_CurrentTurn-1, m_TurnLength, commands);
212 
213  NETTURN_LOG((L"Running %d cmds\n", commands.size()));
214 
215  m_Simulation2.Update(m_TurnLength, commands);
216  }
217 
218  return true;
219 }
220 
221 void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash)
222 {
223  NETTURN_LOG((L"OnSyncError(%d, %ls)\n", turn, Hexify(expectedHash).c_str()));
224 
225  // Only complain the first time
226  if (m_HasSyncError)
227  return;
228  m_HasSyncError = true;
229 
230  bool quick = !TurnNeedsFullHash(turn);
231  std::string hash;
232  bool ok = m_Simulation2.ComputeStateHash(hash, quick);
233  ENSURE(ok);
234 
235  OsPath path = psLogDir()/"oos_dump.txt";
236  std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc);
238  file.close();
239 
240  std::wstringstream msg;
241  msg << L"Out of sync on turn " << turn << L": expected hash " << Hexify(expectedHash) << L"\n\n";
242  msg << L"Current state: turn " << m_CurrentTurn << L", hash " << Hexify(hash) << L"\n\n";
243  msg << L"Dumping current state to " << path;
244  if (g_GUI)
245  g_GUI->DisplayMessageBox(600, 350, L"Sync error", msg.str());
246  else
247  LOGERROR(L"%ls", msg.str().c_str());
248 }
249 
250 void CNetTurnManager::Interpolate(float simFrameLength, float realFrameLength)
251 {
252  // TODO: using m_TurnLength might be a bit dodgy when length changes - maybe
253  // we need to save the previous turn length?
254 
255  float offset = clamp(m_DeltaSimTime / (m_TurnLength / 1000.f) + 1.0, 0.0, 1.0);
256  m_Simulation2.Interpolate(simFrameLength, offset, realFrameLength);
257 }
258 
259 void CNetTurnManager::AddCommand(int client, int player, CScriptValRooted data, u32 turn)
260 {
261  NETTURN_LOG((L"AddCommand(client=%d player=%d turn=%d)\n", client, player, turn));
262 
263  if (!(m_CurrentTurn < turn && turn <= m_CurrentTurn + COMMAND_DELAY + 1))
264  {
265  debug_warn(L"Received command for invalid turn");
266  return;
267  }
268 
269  SimulationCommand cmd;
270  cmd.player = player;
271  cmd.data = data;
272  m_QueuedCommands[turn - (m_CurrentTurn+1)][client].push_back(cmd);
273 }
274 
276 {
277  NETTURN_LOG((L"FinishedAllCommands(%d, %d)\n", turn, turnLength));
278 
279  ENSURE(turn == m_ReadyTurn + 1);
280  m_ReadyTurn = turn;
281  m_TurnLength = turnLength;
282 }
283 
285 {
286  // Check immediately for errors caused by e.g. inconsistent game versions
287  // (The hash is computed after the first sim update, so we start at turn == 1)
288  if (turn == 1)
289  return true;
290 
291  // Otherwise check the full state every ~10 seconds in multiplayer games
292  // (TODO: should probably remove this when we're reasonably sure the game
293  // isn't too buggy, since the full hash is still pretty slow)
294  if (turn % 20 == 0)
295  return true;
296 
297  return false;
298 }
299 
301 {
302  m_TimeWarpStates.clear();
303  m_TimeWarpNumTurns = numTurns;
304 }
305 
307 {
308  if (m_TimeWarpStates.empty())
309  return;
310 
311  std::stringstream stream(m_TimeWarpStates.back());
313  m_TimeWarpStates.pop_back();
314 
315  // Reset the turn manager state, so we won't execute stray commands and
316  // won't do the next snapshot until the appropriate time.
317  // (Ideally we ought to serialise the turn manager state and restore it
318  // here, but this is simpler for now.)
319  ResetState(0, 1);
320 }
321 
323 {
324  TIMER(L"QuickSave");
325 
326  std::stringstream stream;
327  bool ok = m_Simulation2.SerializeState(stream);
328  if (!ok)
329  {
330  LOGERROR(L"Failed to quicksave game");
331  return;
332  }
333 
334  m_QuickSaveState = stream.str();
335  if (g_GUI)
337  else
338  m_QuickSaveMetadata = std::string();
339 
340  LOGMESSAGERENDER(L"Quicksaved game");
341 
342 }
343 
345 {
346  TIMER(L"QuickLoad");
347 
348  if (m_QuickSaveState.empty())
349  {
350  LOGERROR(L"Cannot quickload game - no game was quicksaved");
351  return;
352  }
353 
354  std::stringstream stream(m_QuickSaveState);
355  bool ok = m_Simulation2.DeserializeState(stream);
356  if (!ok)
357  {
358  LOGERROR(L"Failed to quickload game");
359  return;
360  }
361 
362  if (g_GUI && !m_QuickSaveMetadata.empty())
364  "restoreSavedGameData", g_GUI->GetScriptInterface().ParseJSON(m_QuickSaveMetadata));
365 
366  LOGMESSAGERENDER(L"Quickloaded game");
367 
368  // See RewindTimeWarp
369  ResetState(0, 1);
370 }
371 
372 
374  CNetTurnManager(simulation, DEFAULT_TURN_LENGTH_MP, clientId, replay), m_NetClient(client)
375 {
376 }
377 
379 {
380  NETTURN_LOG((L"PostCommand()\n"));
381 
382  // Transmit command to server
384  m_NetClient.SendMessage(&msg);
385 
386  // Add to our local queue
387  //AddCommand(m_ClientId, m_PlayerId, data, m_CurrentTurn + COMMAND_DELAY);
388  // TODO: we should do this when the server stops sending our commands back to us
389 }
390 
392 {
393  NETTURN_LOG((L"NotifyFinishedOwnCommands(%d)\n", turn));
394 
395  // Send message to the server
396  CEndCommandBatchMessage msg;
397  msg.m_TurnLength = DEFAULT_TURN_LENGTH_MP; // TODO: why do we send this?
398  msg.m_Turn = turn;
399  m_NetClient.SendMessage(&msg);
400 }
401 
403 {
404  bool quick = !TurnNeedsFullHash(turn);
405  std::string hash;
406  {
407  PROFILE3("state hash check");
408  bool ok = m_Simulation2.ComputeStateHash(hash, quick);
409  ENSURE(ok);
410  }
411 
412  NETTURN_LOG((L"NotifyFinishedUpdate(%d, %ls)\n", turn, Hexify(hash).c_str()));
413 
414  m_Replay.Hash(hash, quick);
415 
416  // Send message to the server
417  CSyncCheckMessage msg;
418  msg.m_Turn = turn;
419  msg.m_Hash = hash;
420  m_NetClient.SendMessage(&msg);
421 }
422 
424 {
425  // Command received from the server - store it for later execution
426  AddCommand(msg->m_Client, msg->m_Player, msg->m_Data, msg->m_Turn);
427 }
428 
429 
431  CNetTurnManager(simulation, DEFAULT_TURN_LENGTH_SP, 0, replay)
432 {
433 }
434 
436 {
437  // Add directly to the next turn, ignoring COMMAND_DELAY,
438  // because we don't need to compensate for network latency
440 }
441 
443 {
445 }
446 
448 {
449 #if 0 // this hurts performance and is only useful for verifying log replays
450  std::string hash;
451  {
452  PROFILE3("state hash check");
453  bool ok = m_Simulation2.ComputeStateHash(hash);
454  ENSURE(ok);
455  }
456  m_Replay.Hash(hash);
457 #endif
458 }
459 
461 {
462  debug_warn(L"This should never be called");
463 }
464 
465 
466 
467 
469  m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP)
470 {
471  // The first turn we will actually execute is number 2,
472  // so store dummy values into the saved lengths list
473  m_SavedTurnLengths.push_back(0);
474  m_SavedTurnLengths.push_back(0);
475 }
476 
478 {
479  NETTURN_LOG((L"NotifyFinishedClientCommands(client=%d, turn=%d)\n", client, turn));
480 
481  // Must be a client we've already heard of
482  ENSURE(m_ClientsReady.find(client) != m_ClientsReady.end());
483 
484  // Clients must advance one turn at a time
485  ENSURE(turn == m_ClientsReady[client] + 1);
486  m_ClientsReady[client] = turn;
487 
488  // Check whether this was the final client to become ready
490 }
491 
493 {
494  // See if all clients (including self) are ready for a new turn
495  for (std::map<int, u32>::iterator it = m_ClientsReady.begin(); it != m_ClientsReady.end(); ++it)
496  {
497  NETTURN_LOG((L" %d: %d <=? %d\n", it->first, it->second, m_ReadyTurn));
498  if (it->second <= m_ReadyTurn)
499  return; // wasn't ready for m_ReadyTurn+1
500  }
501 
502  // Advance the turn
503  ++m_ReadyTurn;
504 
505  NETTURN_LOG((L"CheckClientsReady: ready for turn %d\n", m_ReadyTurn));
506 
507  // Tell all clients that the next turn is ready
508  CEndCommandBatchMessage msg;
509  msg.m_TurnLength = m_TurnLength;
510  msg.m_Turn = m_ReadyTurn;
511  m_NetServer.Broadcast(&msg);
512 
513  // Save the turn length in case it's needed later
515  m_SavedTurnLengths.push_back(m_TurnLength);
516 }
517 
518 void CNetServerTurnManager::NotifyFinishedClientUpdate(int client, u32 turn, const std::string& hash)
519 {
520  // Clients must advance one turn at a time
521  ENSURE(turn == m_ClientsSimulated[client] + 1);
522  m_ClientsSimulated[client] = turn;
523 
524  m_ClientStateHashes[turn][client] = hash;
525 
526  // Find the newest turn which we know all clients have simulated
527  u32 newest = std::numeric_limits<u32>::max();
528  for (std::map<int, u32>::iterator it = m_ClientsSimulated.begin(); it != m_ClientsSimulated.end(); ++it)
529  {
530  if (it->second < newest)
531  newest = it->second;
532  }
533 
534  // For every set of state hashes that all clients have simulated, check for OOS
535  for (std::map<u32, std::map<int, std::string> >::iterator it = m_ClientStateHashes.begin(); it != m_ClientStateHashes.end(); ++it)
536  {
537  if (it->first > newest)
538  break;
539 
540  // Assume the host is correct (maybe we should choose the most common instead to help debugging)
541  std::string expected = it->second.begin()->second;
542 
543  for (std::map<int, std::string>::iterator cit = it->second.begin(); cit != it->second.end(); ++cit)
544  {
545  NETTURN_LOG((L"sync check %d: %d = %ls\n", it->first, cit->first, Hexify(cit->second).c_str()));
546  if (cit->second != expected)
547  {
548  // Oh no, out of sync
549 
550  // Tell everyone about it
551  CSyncErrorMessage msg;
552  msg.m_Turn = it->first;
553  msg.m_HashExpected = expected;
554  m_NetServer.Broadcast(&msg);
555 
556  break;
557  }
558  }
559  }
560 
561  // Delete the saved hashes for all turns that we've already verified
562  m_ClientStateHashes.erase(m_ClientStateHashes.begin(), m_ClientStateHashes.lower_bound(newest+1));
563 }
564 
566 {
567  NETTURN_LOG((L"InitialiseClient(client=%d, turn=%d)\n", client, turn));
568 
569  ENSURE(m_ClientsReady.find(client) == m_ClientsReady.end());
570  m_ClientsReady[client] = turn + 1;
571  m_ClientsSimulated[client] = turn;
572 }
573 
575 {
576  NETTURN_LOG((L"UninitialiseClient(client=%d)\n", client));
577 
578  ENSURE(m_ClientsReady.find(client) != m_ClientsReady.end());
579  m_ClientsReady.erase(client);
580  m_ClientsSimulated.erase(client);
581 
582  // Check whether we're ready for the next turn now that we're not
583  // waiting for this client any more
585 }
586 
588 {
589  m_TurnLength = msecs;
590 }
591 
593 {
594  ENSURE(turn <= m_ReadyTurn);
595  return m_SavedTurnLengths.at(turn);
596 }
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)
void UninitialiseClient(int client)
Inform the turn manager that a previously-initialised client has left the game and will no longer be ...
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
CNetLocalTurnManager(CSimulation2 &simulation, IReplayLogger &replay)
virtual void Turn(u32 n, u32 turnLength, const std::vector< SimulationCommand > &commands)=0
Run the given turn with the given collection of player commands.
const OsPath & psLogDir()
Definition: Pyrogenesis.cpp:96
#define LOGERROR
Definition: CLogger.h:35
virtual void NotifyFinishedOwnCommands(u32 turn)
Called when this client has finished sending all its commands scheduled for the given turn...
CScriptValRooted data
bool DeserializeState(std::istream &stream)
std::list< std::string > m_TimeWarpStates
static void out(const wchar_t *fmt,...)
Definition: wdbg_sym.cpp:419
bool CallFunctionVoid(jsval val, const char *name)
Call the named property on the given object, with void return type and 0 arguments.
void EnableTimeWarpRecording(size_t numTurns)
Enables the recording of state snapshots every numTurns, which can be jumped back to via RewindTimeWa...
void Interpolate(float simFrameLength, float frameOffset, float realFrameLength)
const jsval & get() const
Returns the current value.
Definition: ScriptVal.h:38
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
std::string StringifyJSON(jsval obj, bool indent=true)
Stringify to a JSON string, UTF-8 encoded.
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.
CScriptValRooted ParseJSON(const std::string &string_utf8)
Parse a UTF-8-encoded JSON string.
CGUIManager * g_GUI
Definition: GUIManager.cpp:32
void Update(int turnLength)
IReplayLogger & m_Replay
Public API for simulation system.
Definition: Simulation2.h:46
CScriptVal GetSavedGameData()
Calls the current page&#39;s script function getSavedGameData() and returns the result.
Definition: GUIManager.cpp:187
bool WillUpdate(float simFrameLength)
Returns whether Update(simFrameLength, ...) will process at least one new turn.
bool SendMessage(const CNetMessage *message)
Send a message to the server.
Definition: NetClient.cpp:216
virtual void NotifyFinishedUpdate(u32 turn)
Called when this client has finished a simulation update.
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
void SetTurnLength(u32 msecs)
size_t m_TimeWarpNumTurns
u32 m_ReadyTurn
The latest turn for which we have received all commands from all clients.
Definition: path.h:75
#define NETTURN_LOG(args)
void InitialiseClient(int client, u32 turn)
Inform the turn manager of a new client who will be sending commands.
static const int DEFAULT_TURN_LENGTH_MP
Contains functions for managing saved game archives.
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)
Simulation command, typically received over the network in multiplayer games.
virtual void Hash(const std::string &hash, bool quick)=0
Optional hash of simulation state (for sync checking).
JSObject * GetScriptObject()
See CGUI::GetScriptObject; applies to the currently active page.
Definition: GUIManager.cpp:290
ScriptInterface & GetScriptInterface() const
static const int COMMAND_DELAY
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...
bool ComputeStateHash(std::string &outHash, bool quick)
virtual void PostCommand(CScriptValRooted data)
Called by simulation code, to add a new command to be distributed to all clients and executed soon...
void DisplayMessageBox(int width, int height, const CStrW &title, const CStrW &message)
Display a modal message box with an &quot;OK&quot; button.
Definition: GUIManager.cpp:94
std::deque< std::map< u32, std::vector< SimulationCommand > > > m_QueuedCommands
Commands queued at each turn (index 0 is for m_CurrentTurn+1)
bool SerializeState(std::ostream &stream)
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.
ScriptInterface & GetScriptInterface()
Definition: GUIManager.h:52
CScriptValRooted m_Data
Definition: NetMessage.h:126
void NotifyFinishedClientCommands(int client, u32 turn)
#define TIMER(description)
Measures the time taken to execute code up until end of the current scope; displays it via debug_prin...
Definition: timer.h:108
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.
static const int DEFAULT_TURN_LENGTH_SP
std::map< int, u32 > m_ClientsReady
CNetServerTurnManager(CNetServerWorker &server)
#define PROFILE3(name)
Definition: Profile.h:201
#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.
void FlushDestroyedEntities()
Does the actual destruction of entities from DestroyEntity.
bool Broadcast(const CNetMessage *message)
Send a message to all clients who have completed the full connection process (i.e.
Definition: NetServer.cpp:197
#define LOGMESSAGERENDER
Definition: CLogger.h:33
jsval get() const
Returns the current value (or JSVAL_VOID if uninitialised).
Definition: ScriptVal.cpp:45
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...
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
std::map< int, u32 > m_ClientsSimulated
CNetClient & m_NetClient
virtual void OnSimulationMessage(CSimulationMessage *msg)
Called by networking code when a simulation message is received.
static std::wstring Hexify(const std::string &s)
void RewindTimeWarp()
Jumps back to the latest recorded state snapshot (if any).
bool DumpDebugState(std::ostream &stream)
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...
T clamp(T value, T min, T max)
Definition: MathUtil.h:32
CSimulation2 & m_Simulation2
static std::string OsString(const OsPath &path)
Definition: os_path.h:42
Special message type for simulation commands.
Definition: NetMessage.h:113