diff --git a/binaries/system/readme.txt b/binaries/system/readme.txt index 5b8c2d5700..d8cccd2db5 100644 --- a/binaries/system/readme.txt +++ b/binaries/system/readme.txt @@ -77,7 +77,7 @@ Advanced / diagnostic: -ooslog dumps simulation state in binary and ASCII representations each turn, files created in sim_log within the game's log folder. NOTE: game will run much slower with this option! --serializationtest checks simulation state each turn for serialization errors; on test +-serializationtest=N checks simulation state for serialization errors starting at turn N; on test failure, error is displayed and logs created in oos_log within the game's log folder. NOTE: game will run much slower with this option! -rejointest=N simulates a rejoin and checks simulation state each turn for serialization diff --git a/source/main.cpp b/source/main.cpp index be233ca89e..9590fea8ef 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -659,8 +659,15 @@ static void RunGameOrAtlas(const std::span argv) { CReplayPlayer replay; replay.Load(replayFile); + const int serializationTestTurn{[&] { + if (!args.Has("serializationtest")) + return -1; + + const CStr str{args.Get("serializationtest")}; + return str.empty() ? 0 : str.ToInt(); + }()}; replay.Replay( - args.Has("serializationtest"), + serializationTestTurn, args.Has("rejointest") ? args.Get("rejointest").ToInt() : -1, args.Has("ooslog"), !args.Has("hashtest-full") || args.Get("hashtest-full") == "true", diff --git a/source/ps/GameSetup/Config.cpp b/source/ps/GameSetup/Config.cpp index a1524f8f06..146cc1b647 100644 --- a/source/ps/GameSetup/Config.cpp +++ b/source/ps/GameSetup/Config.cpp @@ -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 @@ -91,7 +91,10 @@ static void ProcessCommandLineArgs(const CmdLineArgs& args) g_ConfigDB.SetValueString(CFG_COMMAND, "ooslog", "true"); if (args.Has("serializationtest")) - g_ConfigDB.SetValueString(CFG_COMMAND, "serializationtest", "true"); + { + const CStr str{args.Get("serializationtest")}; + g_ConfigDB.SetValueString(CFG_COMMAND, "serializationtest", str.empty() ? "0" : str); + } if (args.Has("rejointest")) g_ConfigDB.SetValueString(CFG_COMMAND, "rejointest", args.Get("rejointest")); diff --git a/source/ps/Replay.cpp b/source/ps/Replay.cpp index 9e8815ab74..17a38df592 100644 --- a/source/ps/Replay.cpp +++ b/source/ps/Replay.cpp @@ -191,7 +191,8 @@ void CheckReplayMods(const std::vector& replayMods) } } // anonymous namespace -void CReplayPlayer::Replay(const bool serializationtest, const int rejointestturn, const bool ooslog, const bool testHashFull, const bool testHashQuick) +void CReplayPlayer::Replay(const int serializationtestturn, const int rejointestturn, const bool ooslog, + const bool testHashFull, const bool testHashQuick) { ENSURE(m_Stream); @@ -249,12 +250,15 @@ void CReplayPlayer::Replay(const bool serializationtest, const int rejointesttur MountMods(Paths(g_CmdLineArgs), g_Mods.GetEnabledMods()); } - if (serializationtest && rejointestturn >= 0) + if (serializationtestturn >= 0 && rejointestturn >= 0) LOGERROR("serializationtest and rejointest can't be activ at the same time."); SimulationDebugOptions debugOption{}; - if (serializationtest) - debugOption.test = SimulationDebugOptions::SerializationTest{}; + if (serializationtestturn >= 0) + { + debugOption.test = + SimulationDebugOptions::SerializationTest{serializationtestturn}; + } if (rejointestturn >= 0) debugOption.test = SimulationDebugOptions::RejoinTest{rejointestturn}; if (ooslog) diff --git a/source/ps/Replay.h b/source/ps/Replay.h index cb7034386b..868f09bb54 100644 --- a/source/ps/Replay.h +++ b/source/ps/Replay.h @@ -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 @@ -114,7 +114,8 @@ public: ~CReplayPlayer(); void Load(const OsPath& path); - void Replay(const bool serializationtest, const int rejointestturn, const bool ooslog, const bool testHashFull, const bool testHashQuick); + void Replay(const int serializationtestturn, const int rejointestturn, const bool ooslog, + const bool testHashFull, const bool testHashQuick); private: std::istream* m_Stream; diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index 1a28fb00de..38e1e1630c 100644 --- a/source/simulation2/Simulation2.cpp +++ b/source/simulation2/Simulation2.cpp @@ -82,10 +82,14 @@ public: m_MapSettings{cx.GetGeneralJSContext()}, // Tests won't have config initialised m_EnableOOSLog{debugOptions.oosLog || CConfigDB::GetIfInitialised("ooslog", false)}, - m_EnableSerializationTest{ - std::holds_alternative(debugOptions.test) || - CConfigDB::GetIfInitialised("serializationtest", false)}, // Handle bogus values of the arg + m_SerializationTestTurn{[&] + { + const auto* serializationTestOption{ + std::get_if(&debugOptions.test)}; + return serializationTestOption ? serializationTestOption->turn : + std::max(CConfigDB::GetIfInitialised("serializationtest", -1), -1); + }()}, m_RejoinTestTurn{[&]() -> std::optional { const auto* rejoinTestOption{ @@ -164,6 +168,8 @@ public: // Functions and data for the serialization test mode: (see Update() for relevant comments) + std::optional m_SerializationTestTurn; + bool m_TestingSerialization{false}; bool m_EnableSerializationTest{false}; std::optional m_RejoinTestTurn; bool m_TestingRejoin{false}; @@ -392,12 +398,16 @@ void CSimulation2Impl::Update(int turnLength, const std::vector(m_RejoinTestTurn.value()) == m_TurnNumber; if (startRejoinTest) m_TestingRejoin = true; - if (m_EnableSerializationTest || m_TestingRejoin) + if (m_TestingSerialization || m_TestingRejoin) { ENSURE(m_ComponentManager.SerializeState(primaryStateBefore.state)); if (serializationTestDebugDump) @@ -408,8 +418,10 @@ void CSimulation2Impl::Update(int turnLength, const std::vectorDeserializeState(primaryStateBefore.state)); } - if (m_EnableSerializationTest || m_TestingRejoin) + if (m_TestingSerialization || m_TestingRejoin) { SerializationTestState secondaryStateBefore; ENSURE(m_SecondaryComponentManager->SerializeState(secondaryStateBefore.state)); diff --git a/source/simulation2/system/DebugOptions.h b/source/simulation2/system/DebugOptions.h index 5cbf810870..4f95d08646 100644 --- a/source/simulation2/system/DebugOptions.h +++ b/source/simulation2/system/DebugOptions.h @@ -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 @@ -22,7 +22,10 @@ struct SimulationDebugOptions { - struct SerializationTest {}; + struct SerializationTest + { + int turn; + }; struct RejoinTest { int turn;