mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-08-15 14:43:32 -07:00
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
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:
parent
9ab89b01c2
commit
71be79791f
17 changed files with 105 additions and 95 deletions
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue