mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
Use turn_id_t (int32_t) for turn-count across simulation, network and replay
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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user