// B4 adapter: the ServerSystem state `ServerSystem::ProcessTurn` reads and writes <-> our // game::sim colony call. // // The hook (src/shim/hooks/colony_turn.cpp) snapshots a ServerSystem into a ColonySnapshot // using only the field offsets in the generated header. This file is the pure half: it turns // a snapshot into sim::ColonyTurnState + sim::ColonyTurnInputs and describes both for the // trace. It has no OS or game dependencies, so it builds and is unit-tested on the host. // // INPUT BOUNDARY. `ServerSystem::ProcessTurn` is a dispatcher: most of a colony turn happens // in callees this milestone does not model. What our side reproduces is the set of words the // dispatcher writes *itself*, plus the two bonus-pool helpers and the system-bonus accrual // whose arithmetic game/sim already carries. Everything else -- the plague pass, imperial and // civilian growth, the resource debit, the in-orbit refuel, slaves, rebellion, and the morale // events the addiction sweep raises -- is an input: those fields are not declared regions, so // the harness never compares them, and the trace records them as arguments instead. // // The one live value our side asks the game for is the imperial carrying capacity, which the // accrual reads. `ServerSystem::MaxPop` is read-only, so the hook calls the game's own copy on // the live system rather than re-deriving a capacity from species and group tables that this // milestone does not model -- the same delegation B3 makes to `TechTree::Cost`. #pragma once #include #include "game/sim/colony.h" #include "shim/trace/emitter.h" namespace shim::hooks { constexpr int kColonySpeciesSlots = 7; // Everything the adapter needs out of a ServerSystem, its owner and the server. struct ColonySnapshot { // identity std::int32_t systemIndex = 0; std::int32_t ownerIndex = -1; // -1 when unowned std::int32_t ownerSpecies = -1; bool owned = false; bool independent = false; bool homeSystem = false; bool stable = false; // the game's own IsStable verdict std::int32_t playerCount = 0; std::int32_t currentTurn = 0; // ModCount std::int32_t turnAcquired = 0; // TAcq // the mutable colony words the pass owns float infra = 0; float infraBonus = 0; std::int32_t pop = 0; std::int32_t popBonus = 0; std::int32_t turnsDeveloping = 0; std::int32_t totalResources = 0; std::uint8_t growthHalted[3] = {0, 0, 0}; std::uint64_t battles = 0; std::uint32_t battlesMask = 0; std::uint64_t recon = 0; std::uint32_t reconMask = 0; // the addiction sweep's inputs std::int32_t addictionStart[kColonySpeciesSlots] = {}; std::uint8_t civilianPresent[kColonySpeciesSlots] = {}; std::uint8_t temperance[kColonySpeciesSlots] = {}; std::int32_t addictionPhase2Start = 0; std::int32_t addictionPhase3Start = 0; // measured live rather than re-derived (see the header comment) std::int64_t imperialCapacity = 0; bool ownerSpeciesEligible = true; // context that is recorded but never compared std::int32_t planetSize = 0; float suitability = 0; std::int32_t resources = 0; std::int32_t rebelMask = 0; std::int32_t rngLeftIn = 0; std::uint32_t fpuControlWord = 0; std::int32_t buildQueueDepth = -1; }; // Pinned: the snapshot is memcpy'd into a declared region, so a padding surprise would shift // every field the describer reports (M2's +0x14 lesson). static_assert(sizeof(ColonySnapshot) % 8 == 0, "ColonySnapshot has no tail padding surprise"); // The tuning keys the modelled steps read. The shim fills these from the loaded globals; a // host test fills them directly. struct ColonyTuning { int SYSTEMBONUS_MINTURNS = 0; double SYSTEMBONUS_POPBONUS = 0; double SYSTEMBONUS_POPBONUS_INC = 0; double SYSTEMBONUS_INFRABONUS = 0; double SYSTEMBONUS_INFRABONUS_INC = 0; }; sots::sim::TuningTable ToTuningTable(const ColonyTuning& t); sots::sim::ColonyTurnState ToColonyTurnState(const ColonySnapshot& s); sots::sim::ColonyTurnInputs ToColonyTurnInputs(const ColonySnapshot& s); // Write a finished state back over a snapshot, so the hook can lay the result out into the // scratch regions field by field. void ApplyColonyTurnState(const sots::sim::ColonyTurnState& st, ColonySnapshot& s); // Trace describers. trace::Tv DescribeColonySnapshot(const void* data, std::size_t size, unsigned inline_max); trace::Tv DescribeMoraleEvents(const sots::sim::ColonyTurnResult& r); } // namespace shim::hooks