sots-engine/src/shim/hooks/colony_inputs.h

106 lines
4.4 KiB
C++

// 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 <cstdint>
#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