Use turn_id_t (int32_t) for turn-count across simulation, network and replay
Some checks failed
checkrefs / lfscheck (push) Has been cancelled
checkrefs / checkrefs (push) Has been cancelled
lint / cppcheck (push) Has been cancelled
lint / copyright (push) Has been cancelled
lint / jenkinsfiles (push) Has been cancelled
pre-commit / build (push) Has been cancelled

CSimulation2 used , CSimulation2Impl mixed /, and
CTurnManager used  for the same turn-count concept, forcing a
static_cast<int64_t> at the one place these types already met
(rejoin-test comparison).

Add  (alias for std::int32_t) in SimulationCommand.h and use
it consistently for every turn counter in CSimulation2/Impl,
CTurnManager and its subclasses (CLocalTurnManager,
CReplayTurnManager), CNetServerTurnManager/CNetClientTurnManager, and
the network wire format (m_Turn in CEndCommandBatchMessage,
CSimulationMessage, CSyncCheckMessage, CSyncErrorMessage, and
m_CurrentTurn in CLoadedGameMessage).

Turn *duration* fields (m_TurnLength, m_CommandDelay,
DEFAULT_TURN_LENGTH, COMMAND_DELAY_SP/MP, SetTurnLength,
GetSavedTurnLength return type) are left as u32 — they're milliseconds,
not a counter, and out of scope here.

Remaining turn_id_t vs size_t comparisons use std::cmp_equal or
explicit casts, matching the existing pattern in Simulation2.cpp.

Fixes #8718
This commit is contained in:
vyordan 2026-06-26 22:04:27 -06:00 committed by Phosit
parent 9ab89b01c2
commit 71be79791f
17 changed files with 105 additions and 95 deletions

View file

@ -63,7 +63,7 @@ void CNetClientTurnManager::PostCommand(JS::HandleValue data)
// TODO: we should do this when the server stops sending our commands back to us
}
void CNetClientTurnManager::NotifyFinishedOwnCommands(u32 turn)
void CNetClientTurnManager::NotifyFinishedOwnCommands(turn_id_t turn)
{
NETCLIENTTURN_LOG("NotifyFinishedOwnCommands(%d)\n", turn);
@ -79,7 +79,7 @@ void CNetClientTurnManager::NotifyFinishedOwnCommands(u32 turn)
m_NetClient.SendMessage(&msg);
}
void CNetClientTurnManager::NotifyFinishedUpdate(u32 turn, const UpdateCallback&)
void CNetClientTurnManager::NotifyFinishedUpdate(turn_id_t turn, const UpdateCallback&)
{
bool quick = !TurnNeedsFullHash(turn);
std::string hash;
@ -110,10 +110,10 @@ void CNetClientTurnManager::OnDestroyConnection()
void CNetClientTurnManager::OnSimulationMessage(CSimulationMessage* msg)
{
// Command received from the server - store it for later execution
AddCommand(msg->m_Client, msg->m_Player, msg->m_Data, msg->m_Turn);
AddCommand(msg->m_Client, msg->m_Player, msg->m_Data, static_cast<turn_id_t>(msg->m_Turn));
}
void CNetClientTurnManager::OnSyncError(u32 turn, const CStr& expectedHash, const std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames)
void CNetClientTurnManager::OnSyncError(turn_id_t turn, const CStr& expectedHash, const std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames)
{
CStr expectedHashHex(Hexify(expectedHash));
NETCLIENTTURN_LOG("OnSyncError(%d, %hs)\n", turn, expectedHashHex.c_str());

View file

@ -49,12 +49,12 @@ public:
*/
void OnDestroyConnection();
void OnSyncError(u32 turn, const CStr& expectedHash, const std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames);
void OnSyncError(turn_id_t turn, const CStr& expectedHash, const std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames);
private:
void NotifyFinishedOwnCommands(u32 turn) override;
void NotifyFinishedOwnCommands(turn_id_t turn) override;
void NotifyFinishedUpdate(u32 turn, const UpdateCallback& sendEventToAll) override;
void NotifyFinishedUpdate(turn_id_t turn, const UpdateCallback& sendEventToAll) override;
CNetClient& m_NetClient;
};

View file

@ -139,7 +139,7 @@ public:
u32 m_Client;
i32 m_Player;
u32 m_Turn;
i32 m_Turn;
JS::PersistentRooted<JS::Value> m_Data;
private:
const Script::Interface& m_ScriptInterface;

View file

@ -150,7 +150,7 @@ u8* CSimulationMessage::Serialize(u8* pBuffer) const
CBufferBinarySerializer serializer(m_ScriptInterface, pos);
serializer.NumberU32_Unbounded("client", m_Client);
serializer.NumberI32_Unbounded("player", m_Player);
serializer.NumberU32_Unbounded("turn", m_Turn);
serializer.NumberI32_Unbounded("turn", m_Turn);
serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
return serializer.GetBuffer();
@ -165,7 +165,7 @@ const u8* CSimulationMessage::Deserialize(const u8* pStart, const u8* pEnd)
CStdDeserializer deserializer(m_ScriptInterface, stream);
deserializer.NumberU32_Unbounded("client", m_Client);
deserializer.NumberI32_Unbounded("player", m_Player);
deserializer.NumberU32_Unbounded("turn", m_Turn);
deserializer.NumberI32_Unbounded("turn", m_Turn);
deserializer.ScriptVal("command", &m_Data);
return pEnd;
}
@ -177,7 +177,7 @@ size_t CSimulationMessage::GetSerializedLength() const
CLengthBinarySerializer serializer(m_ScriptInterface);
serializer.NumberU32_Unbounded("client", m_Client);
serializer.NumberI32_Unbounded("player", m_Player);
serializer.NumberU32_Unbounded("turn", m_Turn);
serializer.NumberI32_Unbounded("turn", m_Turn);
// TODO: The cast can probably be removed if and when ScriptVal can take a JS::HandleValue instead of
// a JS::MutableHandleValue (relies on JSAPI change). Also search for other casts like this one in that case.

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -27,7 +27,7 @@
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
#define PS_PROTOCOL_VERSION 0x01010019 // Arbitrary protocol
#define PS_PROTOCOL_VERSION 0x0101001A // Arbitrary protocol
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
// Set when lobby authentication is required. Used in the SrvHandshakeResponseMessage.
@ -231,7 +231,7 @@ START_NMT_CLASS_(ClientPaused, NMT_CLIENT_PAUSED)
END_NMT_CLASS()
START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME)
NMT_FIELD_INT(m_CurrentTurn, u32, 4)
NMT_FIELD_INT(m_CurrentTurn, i32, 4)
END_NMT_CLASS()
START_NMT_CLASS_(GameStart, NMT_GAME_START)
@ -243,17 +243,17 @@ START_NMT_CLASS_(GameSavedStart, NMT_SAVED_GAME_START)
END_NMT_CLASS()
START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH)
NMT_FIELD_INT(m_Turn, u32, 4)
NMT_FIELD_INT(m_Turn, i32, 4)
NMT_FIELD_INT(m_TurnLength, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(SyncCheck, NMT_SYNC_CHECK)
NMT_FIELD_INT(m_Turn, u32, 4)
NMT_FIELD_INT(m_Turn, i32, 4)
NMT_FIELD(CStr, m_Hash)
END_NMT_CLASS()
START_NMT_CLASS_(SyncError, NMT_SYNC_ERROR)
NMT_FIELD_INT(m_Turn, u32, 4)
NMT_FIELD_INT(m_Turn, i32, 4)
NMT_FIELD(CStr, m_HashExpected)
NMT_START_ARRAY(m_PlayerNames)
NMT_FIELD(CStrW, m_Name)

View file

@ -49,6 +49,7 @@
#include "scriptinterface/Context.h"
#include "scriptinterface/Interface.h"
#include "scriptinterface/Request.h"
#include "simulation2/helpers/SimulationCommand.h"
#include "simulation2/system/TurnManager.h"
#include <algorithm>
@ -1172,9 +1173,9 @@ bool CNetServerWorker::OnSimulationCommand(CNetServerSession* session, CFsmEvent
server.Multicast(message, { NSS_INGAME });
// Save all the received commands
if (server.m_SavedCommands.size() < message->m_Turn + 1)
server.m_SavedCommands.resize(message->m_Turn + 1);
server.m_SavedCommands[message->m_Turn].push_back(*message);
if (server.m_SavedCommands.size() < static_cast<size_t>(message->m_Turn) + 1)
server.m_SavedCommands.resize(static_cast<size_t>(message->m_Turn) + 1);
server.m_SavedCommands[static_cast<size_t>(message->m_Turn)].push_back(*message);
// TODO: we shouldn't send the message back to the client that first sent it
return true;
@ -1396,14 +1397,14 @@ bool CNetServerWorker::OnJoinSyncingLoadedGame(CNetServerSession* session, CFsmE
CLoadedGameMessage* message = (CLoadedGameMessage*)event->GetParamRef();
u32 turn = message->m_CurrentTurn;
u32 readyTurn = server.m_ServerTurnManager->GetReadyTurn();
turn_id_t turn = message->m_CurrentTurn;
turn_id_t readyTurn = server.m_ServerTurnManager->GetReadyTurn();
// Send them all commands received since their saved state,
// and turn-ended messages for any turns that have already been processed
for (size_t i = turn + 1; i < std::max(readyTurn+1, (u32)server.m_SavedCommands.size()); ++i)
for (turn_id_t i = turn + 1; i < std::max(readyTurn + 1, static_cast<turn_id_t>(server.m_SavedCommands.size())); ++i)
{
if (i < server.m_SavedCommands.size())
if (static_cast<size_t>(i) < server.m_SavedCommands.size())
for (size_t j = 0; j < server.m_SavedCommands[i].size(); ++j)
session->SendMessage(&server.m_SavedCommands[i][j]);

View file

@ -27,6 +27,7 @@
#include "network/NetServerSession.h"
#include "ps/CLogger.h"
#include "ps/ConfigDB.h"
#include "simulation2/helpers/SimulationCommand.h"
#include "simulation2/system/TurnManager.h"
#include <limits>
@ -50,7 +51,7 @@ CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server)
m_SavedTurnLengths.push_back(m_TurnLength);
}
void CNetServerTurnManager::NotifyFinishedClientCommands(CNetServerSession& session, u32 turn)
void CNetServerTurnManager::NotifyFinishedClientCommands(CNetServerSession& session, turn_id_t turn)
{
int client = session.GetHostID();
@ -105,11 +106,11 @@ void CNetServerTurnManager::CheckClientsReady()
msg.m_Turn = m_ReadyTurn;
m_NetServer.Multicast(&msg, { NSS_INGAME });
ENSURE(m_SavedTurnLengths.size() == m_ReadyTurn);
ENSURE(std::cmp_equal(m_SavedTurnLengths.size(), m_ReadyTurn));
m_SavedTurnLengths.push_back(m_TurnLength);
}
void CNetServerTurnManager::NotifyFinishedClientUpdate(CNetServerSession& session, u32 turn, const CStr& hash)
void CNetServerTurnManager::NotifyFinishedClientUpdate(CNetServerSession& session, turn_id_t turn, const CStr& hash)
{
int client = session.GetHostID();
@ -138,13 +139,13 @@ void CNetServerTurnManager::NotifyFinishedClientUpdate(CNetServerSession& sessio
m_ClientStateHashes[turn][client] = hash;
// Find the newest turn which we know all clients have simulated
u32 newest = std::numeric_limits<u32>::max();
turn_id_t newest = std::numeric_limits<turn_id_t>::max();
for (const std::pair<const int, Client>& clientData : m_ClientsData)
if (clientData.second.simulatedTurn < newest)
newest = clientData.second.simulatedTurn;
// For every set of state hashes that all clients have simulated, check for OOS
for (const std::pair<const u32, std::map<int, std::string>>& clientStateHash : m_ClientStateHashes)
for (const std::pair<const turn_id_t, std::map<int, std::string>>& clientStateHash : m_ClientStateHashes)
{
if (clientStateHash.first > newest)
break;
@ -187,7 +188,7 @@ void CNetServerTurnManager::NotifyFinishedClientUpdate(CNetServerSession& sessio
m_ClientStateHashes.erase(m_ClientStateHashes.begin(), m_ClientStateHashes.lower_bound(newest+1));
}
void CNetServerTurnManager::InitialiseClient(int client, u32 turn, bool observer)
void CNetServerTurnManager::InitialiseClient(int client, turn_id_t turn, bool observer)
{
NETSERVERTURN_LOG("InitialiseClient(client=%d, turn=%d)\n", client, turn);
@ -206,7 +207,7 @@ void CNetServerTurnManager::UninitialiseClient(int client)
bool checkOOS = m_ClientsData[client].isOOS;
m_ClientsData.erase(client);
for (std::pair<const u32, std::map<int, std::string>>& clientStateHash : m_ClientStateHashes)
for (std::pair<const turn_id_t, std::map<int, std::string>>& clientStateHash : m_ClientStateHashes)
clientStateHash.second.erase(client);
// Check whether we're ready for the next turn now that we're not
@ -228,8 +229,8 @@ void CNetServerTurnManager::SetTurnLength(u32 msecs)
m_TurnLength = msecs;
}
u32 CNetServerTurnManager::GetSavedTurnLength(u32 turn)
u32 CNetServerTurnManager::GetSavedTurnLength(turn_id_t turn)
{
ENSURE(turn <= m_ReadyTurn);
return m_SavedTurnLengths.at(turn);
return m_SavedTurnLengths.at(static_cast<size_t>(turn));
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -21,6 +21,7 @@
#include "lib/code_annotation.h"
#include "lib/types.h"
#include "ps/CStr.h"
#include "simulation2/helpers/SimulationCommand.h"
#include <map>
#include <string>
@ -44,15 +45,15 @@ class CNetServerTurnManager
public:
CNetServerTurnManager(CNetServerWorker& server);
void NotifyFinishedClientCommands(CNetServerSession& session, u32 turn);
void NotifyFinishedClientCommands(CNetServerSession& session, turn_id_t turn);
void NotifyFinishedClientUpdate(CNetServerSession& session, u32 turn, const CStr& hash);
void NotifyFinishedClientUpdate(CNetServerSession& session, turn_id_t turn, const CStr& hash);
/**
* Inform the turn manager of a new client
* @param observer - whether this client is an observer.
*/
void InitialiseClient(int client, u32 turn, bool observer);
void InitialiseClient(int client, turn_id_t turn, bool observer);
/**
* Inform the turn manager that a previously-initialised client has left the game.
@ -65,13 +66,13 @@ public:
* Returns the latest turn for which all clients are ready;
* they will have already been told to execute this turn.
*/
u32 GetReadyTurn() { return m_ReadyTurn; }
turn_id_t GetReadyTurn() { return m_ReadyTurn; }
/**
* Returns the turn length that was used for the given turn.
* Requires turn <= GetReadyTurn().
*/
u32 GetSavedTurnLength(u32 turn);
u32 GetSavedTurnLength(turn_id_t turn);
private:
void CheckClientsReady();
@ -80,9 +81,9 @@ private:
{
CStrW playerName;
// Latest turn for which all commands have been received.
u32 readyTurn;
turn_id_t readyTurn;
// Last known simulated turn.
u32 simulatedTurn;
turn_id_t simulatedTurn;
bool isObserver;
bool isOOS = false;
};
@ -93,10 +94,10 @@ private:
bool m_HasSyncError = false;
// Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted
std::map<u32, std::map<int, std::string>> m_ClientStateHashes;
std::map<turn_id_t, std::map<int, std::string>> m_ClientStateHashes;
/// The latest turn for which we have received all commands from all clients
u32 m_ReadyTurn;
turn_id_t m_ReadyTurn;
// Current turn length
u32 m_TurnLength;

View file

@ -92,13 +92,13 @@ public:
return serializationTestOption ? serializationTestOption->turn :
std::max(CConfigDB::GetIfInitialised("serializationtest", -1), -1);
}()},
m_RejoinTestTurn{[&]() -> std::optional<int>
m_RejoinTestTurn{[&]() -> std::optional<turn_id_t>
{
const auto* rejoinTestOption{
std::get_if<SimulationDebugOptions::RejoinTest>(&debugOptions.test)};
if (rejoinTestOption)
return rejoinTestOption->turn;
const int configVal{CConfigDB::GetIfInitialised("rejointest", -1)};
const turn_id_t configVal{CConfigDB::GetIfInitialised("rejointest", -1)};
if (configVal >= 0)
return configVal;
return std::nullopt;
@ -163,17 +163,17 @@ public:
std::set<VfsPath> m_LoadedScripts;
uint32_t m_TurnNumber;
turn_id_t m_TurnNumber;
bool m_EnableOOSLog{false};
OsPath m_OOSLogPath;
// Functions and data for the serialization test mode: (see Update() for relevant comments)
std::optional<int> m_SerializationTestTurn;
std::optional<turn_id_t> m_SerializationTestTurn;
bool m_TestingSerialization{false};
bool m_EnableSerializationTest{false};
std::optional<int> m_RejoinTestTurn;
std::optional<turn_id_t> m_RejoinTestTurn;
bool m_TestingRejoin{false};
// Secondary simulation (NB: order matters for destruction).
@ -383,7 +383,7 @@ void CSimulation2Impl::InitRNGSeedAI()
void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationCommand>& commands)
{
PROFILE3("sim update");
PROFILE2_ATTR("turn %d", (int)m_TurnNumber);
PROFILE2_ATTR("turn %d", m_TurnNumber);
fixed turnLengthFixed = fixed::FromInt(turnLength) / 1000;
@ -408,11 +408,11 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
const Script::Interface& scriptInterface = m_ComponentManager.GetScriptInterface();
const bool startSerializationTest = m_SerializationTestTurn.has_value() &&
std::cmp_equal(m_SerializationTestTurn.value(), m_TurnNumber);
m_SerializationTestTurn.value() == m_TurnNumber;
if (startSerializationTest)
m_TestingSerialization = true;
const bool startRejoinTest = m_RejoinTestTurn.has_value() &&
static_cast<int64_t>(m_RejoinTestTurn.value()) == m_TurnNumber;
m_RejoinTestTurn.value() == m_TurnNumber;
if (startRejoinTest)
m_TestingRejoin = true;
@ -891,11 +891,11 @@ bool CSimulation2::DeserializeState(std::istream& stream)
return m->m_ComponentManager.DeserializeState(stream);
}
void CSimulation2::ActivateRejoinTest(int turn)
void CSimulation2::ActivateRejoinTest(turn_id_t turn)
{
if (m->m_RejoinTestTurn.has_value())
return;
LOGMESSAGERENDER("Rejoin test will activate in %i turns", turn - m->m_TurnNumber);
LOGMESSAGERENDER("Rejoin test will activate in %d turns", turn - m->m_TurnNumber);
m->m_RejoinTestTurn = turn;
}

View file

@ -22,6 +22,7 @@
#include "lib/file/vfs/vfs_path.h"
#include "lib/status.h"
#include "ps/Loader.h"
#include "simulation2/helpers/SimulationCommand.h"
#include "simulation2/system/DebugOptions.h"
#include "simulation2/system/Entity.h"
@ -240,7 +241,7 @@ public:
/**
* Activate the rejoin-test feature for turn @param turn.
*/
void ActivateRejoinTest(int turn);
void ActivateRejoinTest(turn_id_t turn);
std::string GenerateSchema();

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -24,6 +24,12 @@
#include <js/TypeDecls.h>
#include <js/Value.h>
/**
* At 1000 turns/second, a 32-bit counter would overflow in ~49 days.
* No overflow checks are needed.
*/
using turn_id_t = std::int32_t;
struct JSContext;
/**

View file

@ -42,12 +42,12 @@ void CLocalTurnManager::PostCommand(JS::HandleValue data)
AddCommand(m_ClientId, m_PlayerId, data, m_CurrentTurn + m_CommandDelay);
}
void CLocalTurnManager::NotifyFinishedOwnCommands(u32 turn)
void CLocalTurnManager::NotifyFinishedOwnCommands(turn_id_t turn)
{
FinishedAllCommands(turn, m_TurnLength);
}
void CLocalTurnManager::NotifyFinishedUpdate(u32 /*turn*/, const UpdateCallback&)
void CLocalTurnManager::NotifyFinishedUpdate(turn_id_t /*turn*/, const UpdateCallback&)
{
#if 0 // this hurts performance and is only useful for verifying log replays
std::string hash;

View file

@ -41,9 +41,9 @@ public:
void PostCommand(player_id_t playerid, JS::HandleValue data);
protected:
void NotifyFinishedOwnCommands(u32 turn) override;
void NotifyFinishedOwnCommands(turn_id_t turn) override;
void NotifyFinishedUpdate(u32 turn, const UpdateCallback& sendEventToAll) override;
void NotifyFinishedUpdate(turn_id_t turn, const UpdateCallback& sendEventToAll) override;
};
#endif // INCLUDED_LOCALTURNMANAGER

View file

@ -47,18 +47,18 @@ CReplayTurnManager::CReplayTurnManager(CSimulation2& simulation, IReplayLogger&
{
}
void CReplayTurnManager::StoreReplayCommand(u32 turn, int player, const std::string& command)
void CReplayTurnManager::StoreReplayCommand(turn_id_t turn, int player, const std::string& command)
{
// Using the pair we make sure that commands per turn will be processed in the correct order
m_ReplayCommands[turn].emplace_back(player, command);
}
void CReplayTurnManager::StoreReplayHash(u32 turn, const std::string& hash, bool quick)
void CReplayTurnManager::StoreReplayHash(turn_id_t turn, const std::string& hash, bool quick)
{
m_ReplayHash[turn] = std::make_pair(hash, quick);
}
void CReplayTurnManager::StoreReplayTurnLength(u32 turn, u32 turnLength)
void CReplayTurnManager::StoreReplayTurnLength(turn_id_t turn, u32 turnLength)
{
m_ReplayTurnLengths[turn] = turnLength;
@ -67,12 +67,12 @@ void CReplayTurnManager::StoreReplayTurnLength(u32 turn, u32 turnLength)
m_TurnLength = m_ReplayTurnLengths[0];
}
void CReplayTurnManager::StoreFinalReplayTurn(u32 turn)
void CReplayTurnManager::StoreFinalReplayTurn(turn_id_t turn)
{
m_FinalTurn = turn;
}
void CReplayTurnManager::NotifyFinishedUpdate(u32 turn, const UpdateCallback& sendEventToAll)
void CReplayTurnManager::NotifyFinishedUpdate(turn_id_t turn, const UpdateCallback& sendEventToAll)
{
if (turn == 1 && m_FinalTurn == 0)
sendEventToAll(EventNameReplayFinished, std::nullopt);
@ -83,7 +83,7 @@ void CReplayTurnManager::NotifyFinishedUpdate(u32 turn, const UpdateCallback& se
DoTurn(turn, sendEventToAll);
// Compare hash if it exists in the replay and if we didn't have an OOS already
std::map<u32, std::pair<std::string, bool>>::iterator turnHashIt = m_ReplayHash.find(turn);
std::map<turn_id_t, std::pair<std::string, bool>>::iterator turnHashIt = m_ReplayHash.find(turn);
if (m_HasSyncError || turnHashIt == m_ReplayHash.end())
return;
@ -119,9 +119,9 @@ void CReplayTurnManager::NotifyFinishedUpdate(u32 turn, const UpdateCallback& se
sendEventToAll(EventNameReplayOutOfSync, paramData);
}
void CReplayTurnManager::DoTurn(u32 turn, const UpdateCallback& sendEventToAll)
void CReplayTurnManager::DoTurn(turn_id_t turn, const UpdateCallback& sendEventToAll)
{
debug_printf("Executing turn %u of %u\n", turn, m_FinalTurn);
debug_printf("Executing turn %d of %d\n", turn, m_FinalTurn);
m_TurnLength = m_ReplayTurnLengths[turn];

View file

@ -40,18 +40,18 @@ class CReplayTurnManager : public CLocalTurnManager
public:
CReplayTurnManager(CSimulation2& simulation, IReplayLogger& replay);
void StoreReplayCommand(u32 turn, int player, const std::string& command);
void StoreReplayCommand(turn_id_t turn, int player, const std::string& command);
void StoreReplayTurnLength(u32 turn, u32 turnLength);
void StoreReplayTurnLength(turn_id_t turn, u32 turnLength);
void StoreReplayHash(u32 turn, const std::string& hash, bool quick);
void StoreReplayHash(turn_id_t turn, const std::string& hash, bool quick);
void StoreFinalReplayTurn(u32 turn);
void StoreFinalReplayTurn(turn_id_t turn);
private:
void NotifyFinishedUpdate(u32 turn, const UpdateCallback& sendEventToAll) override;
void NotifyFinishedUpdate(turn_id_t turn, const UpdateCallback& sendEventToAll) override;
void DoTurn(u32 turn, const UpdateCallback& sendEventToAll);
void DoTurn(turn_id_t turn, const UpdateCallback& sendEventToAll);
static const CStr EventNameReplayFinished;
static const CStr EventNameReplayOutOfSync;
@ -59,13 +59,13 @@ private:
bool m_HasSyncError = false;
// Contains the commands of every player on each turn
std::map<u32, std::vector<std::pair<player_id_t, std::string>>> m_ReplayCommands;
std::map<turn_id_t, std::vector<std::pair<player_id_t, std::string>>> m_ReplayCommands;
// Contains the length of every turn
std::map<u32, u32> m_ReplayTurnLengths;
std::map<turn_id_t, u32> m_ReplayTurnLengths;
// Contains all replay hash values and weather or not the quick hash method was used
std::map<u32, std::pair<std::string, bool>> m_ReplayHash;
std::map<turn_id_t, std::pair<std::string, bool>> m_ReplayHash;
};
#endif // INCLUDED_REPLAYTURNMANAGER

View file

@ -48,14 +48,14 @@ const CStr CTurnManager::EventNameSavegameLoaded = "SavegameLoaded";
CTurnManager::CTurnManager(CSimulation2& simulation, u32 defaultTurnLength, u32 commandDelay, int clientId, IReplayLogger& replay)
: m_Simulation2(simulation), m_CurrentTurn(0), m_CommandDelay(commandDelay), m_ReadyTurn(commandDelay - 1), m_TurnLength(defaultTurnLength),
m_PlayerId(-1), m_ClientId(clientId), m_DeltaSimTime(0), m_Replay(replay),
m_FinalTurn(std::numeric_limits<u32>::max()), m_TimeWarpNumTurns(0)
m_FinalTurn(std::numeric_limits<turn_id_t>::max()), m_TimeWarpNumTurns(0)
{
Script::Request rq(m_Simulation2.GetScriptInterface());
m_QuickSaveMetadata.init(rq.cx);
m_QueuedCommands.resize(1);
}
void CTurnManager::ResetState(u32 newCurrentTurn, u32 newReadyTurn)
void CTurnManager::ResetState(turn_id_t newCurrentTurn, turn_id_t newReadyTurn)
{
m_CurrentTurn = newCurrentTurn;
m_ReadyTurn = newReadyTurn;
@ -141,7 +141,7 @@ bool CTurnManager::Update(float simFrameLength, size_t maxTurns, const UpdateCal
// Put all the client commands into a single list, in a globally consistent order
std::vector<SimulationCommand> commands;
for (std::pair<const u32, std::vector<SimulationCommand>>& p : m_QueuedCommands[0])
for (std::pair<const turn_id_t, std::vector<SimulationCommand>>& p : m_QueuedCommands[0])
commands.insert(commands.end(), std::make_move_iterator(p.second.begin()), std::make_move_iterator(p.second.end()));
m_QueuedCommands.pop_front();
@ -184,7 +184,7 @@ bool CTurnManager::UpdateFastForward()
// Put all the client commands into a single list, in a globally consistent order
std::vector<SimulationCommand> commands;
for (std::pair<const u32, std::vector<SimulationCommand>>& p : m_QueuedCommands[0])
for (std::pair<const turn_id_t, std::vector<SimulationCommand>>& p : m_QueuedCommands[0])
commands.insert(commands.end(), std::make_move_iterator(p.second.begin()), std::make_move_iterator(p.second.end()));
m_QueuedCommands.pop_front();
@ -214,7 +214,7 @@ void CTurnManager::Interpolate(float simFrameLength, float realFrameLength)
m_Simulation2.Interpolate(simFrameLength, offset, realFrameLength);
}
void CTurnManager::AddCommand(int client, int player, JS::HandleValue data, u32 turn)
void CTurnManager::AddCommand(int client, int player, JS::HandleValue data, turn_id_t turn)
{
NETTURN_LOG("AddCommand(client=%d player=%d turn=%d current=%d, ready=%d)\n", client, player, turn, m_CurrentTurn, m_ReadyTurn);
@ -239,7 +239,7 @@ void CTurnManager::AddCommand(int client, int player, JS::HandleValue data, u32
m_QueuedCommands[turn - (m_CurrentTurn+1)][client].emplace_back(player, rq.cx, data);
}
void CTurnManager::FinishedAllCommands(u32 turn, u32 turnLength)
void CTurnManager::FinishedAllCommands(turn_id_t turn, u32 turnLength)
{
NETTURN_LOG("FinishedAllCommands(%d, %d)\n", turn, turnLength);
@ -248,7 +248,7 @@ void CTurnManager::FinishedAllCommands(u32 turn, u32 turnLength)
m_TurnLength = turnLength;
}
bool CTurnManager::TurnNeedsFullHash(u32 turn) const
bool CTurnManager::TurnNeedsFullHash(turn_id_t turn) const
{
// Check immediately for errors caused by e.g. inconsistent game versions
// (The hash is computed after the first sim update, so we start at turn == 1)

View file

@ -101,7 +101,7 @@ public:
virtual ~CTurnManager() { }
void ResetState(u32 newCurrentTurn, u32 newReadyTurn);
void ResetState(turn_id_t newCurrentTurn, turn_id_t newReadyTurn);
/**
* Set the current user's player ID, which will be added into command messages.
@ -146,7 +146,7 @@ public:
* Called when all commands for a given turn have been received.
* This allows Update to progress to that turn.
*/
void FinishedAllCommands(u32 turn, u32 turnLength);
void FinishedAllCommands(turn_id_t turn, u32 turnLength);
/**
* Enables the recording of state snapshots every @p numTurns,
@ -163,52 +163,52 @@ public:
void QuickSave(JS::HandleValue GUIMetadata);
std::optional<JS::Value> TryQuickLoad();
u32 GetCurrentTurn() const { return m_CurrentTurn; }
turn_id_t GetCurrentTurn() const { return m_CurrentTurn; }
/**
* @return how many turns are ready to be computed.
* (used to detect players/observers that fall behind the live game.
*/
u32 GetPendingTurns() const { return m_ReadyTurn - m_CurrentTurn; }
turn_id_t GetPendingTurns() const { return m_ReadyTurn - m_CurrentTurn; }
protected:
/**
* Store a command to be executed at a given turn.
*/
void AddCommand(int client, int player, JS::HandleValue data, u32 turn);
void AddCommand(int client, int player, JS::HandleValue data, turn_id_t turn);
/**
* Called when this client has finished sending all its commands scheduled for the given turn.
*/
virtual void NotifyFinishedOwnCommands(u32 turn) = 0;
virtual void NotifyFinishedOwnCommands(turn_id_t turn) = 0;
/**
* Called when this client has finished a simulation update.
*/
virtual void NotifyFinishedUpdate(u32 turn, const UpdateCallback& sendEventToAll) = 0;
virtual void NotifyFinishedUpdate(turn_id_t turn, const UpdateCallback& sendEventToAll) = 0;
/**
* Returns whether we should compute a complete state hash for the given turn,
* instead of a quick less-complete hash.
*/
bool TurnNeedsFullHash(u32 turn) const;
bool TurnNeedsFullHash(turn_id_t turn) const;
CSimulation2& m_Simulation2;
/// The turn that we have most recently executed
u32 m_CurrentTurn;
turn_id_t m_CurrentTurn;
// Current command delay (commands are scheduled for m_CurrentTurn + m_CommandDelay)
u32 m_CommandDelay;
/// The latest turn for which we have received all commands from all clients
u32 m_ReadyTurn;
turn_id_t m_ReadyTurn;
// Current turn length
u32 m_TurnLength;
/// Commands queued at each turn (index 0 is for m_CurrentTurn+1)
std::deque<std::map<u32, std::vector<SimulationCommand>>> m_QueuedCommands;
std::deque<std::map<turn_id_t, std::vector<SimulationCommand>>> m_QueuedCommands;
int m_PlayerId;
uint m_ClientId;
@ -220,7 +220,7 @@ protected:
IReplayLogger& m_Replay;
// The number of the last turn that is allowed to be executed (used for replays)
u32 m_FinalTurn;
turn_id_t m_FinalTurn;
private:
size_t m_TimeWarpNumTurns; // 0 if disabled