// Phase 11 helpers for forging FlatBuffers report payloads in e2e // tests. Mirrors the engine's `report.Report` shape so the mocked // gateway can return realistic data without standing up the real // engine container. // // Phase 11 only renders planets, so the helpers keep the report shape // minimal (turn / dimensions / planet vectors). Phase 13 extended the // fixture with the optional rich planet fields (size, resources, // stockpiles, population, industry, colonists, production, free // industry) so the inspector e2e can drive the read-only display // against realistic values. Phase 15 adds a minimal `LocalShipClass` // projection so the planet inspector's Build-Ship sub-picker has data // in e2e specs (`name` only — Phase 17 widens this when ship-class // CRUD lands). Phase 21 adds a `LocalScience` projection so the // sciences table and the planet production picker's Research sub-row // have data in e2e specs. import { Builder } from "flatbuffers"; import { LocalPlanet, OtherPlanet, Player, Report, Route, RouteEntry, Science, ShipClass, UnidentifiedPlanet, UninhabitedPlanet, } from "../../../src/proto/galaxy/fbs/report"; export interface PlanetFixture { number: number; name: string; x: number; y: number; size?: number; resources?: number; capital?: number; material?: number; } export interface InhabitedFixture extends PlanetFixture { population?: number; colonists?: number; industry?: number; production?: string; freeIndustry?: number; } export interface OtherPlanetFixture extends InhabitedFixture { owner: string; } export interface ShipClassFixture { name: string; drive?: number; armament?: number; weapons?: number; shields?: number; cargo?: number; } export interface ScienceFixture { name: string; drive?: number; weapons?: number; shields?: number; cargo?: number; } export interface PlayerFixture { name: string; drive?: number; } export interface RouteEntryFixture { loadType: "COL" | "CAP" | "MAT" | "EMP"; destinationPlanetNumber: number; } export interface RouteFixture { sourcePlanetNumber: number; entries: RouteEntryFixture[]; } export interface ReportFixture { turn: number; mapWidth?: number; mapHeight?: number; localPlanets?: InhabitedFixture[]; otherPlanets?: OtherPlanetFixture[]; uninhabitedPlanets?: PlanetFixture[]; unidentifiedPlanets?: { number: number; x: number; y: number }[]; localShipClass?: ShipClassFixture[]; localScience?: ScienceFixture[]; race?: string; players?: PlayerFixture[]; routes?: RouteFixture[]; } export function buildReportPayload(fixture: ReportFixture): Uint8Array { const builder = new Builder(512); const localOffsets = (fixture.localPlanets ?? []).map((planet) => { const name = builder.createString(planet.name); const production = planet.production !== undefined ? builder.createString(planet.production) : null; LocalPlanet.startLocalPlanet(builder); LocalPlanet.addNumber(builder, BigInt(planet.number)); LocalPlanet.addX(builder, planet.x); LocalPlanet.addY(builder, planet.y); LocalPlanet.addName(builder, name); LocalPlanet.addSize(builder, planet.size ?? 10); LocalPlanet.addResources(builder, planet.resources ?? 0.5); LocalPlanet.addCapital(builder, planet.capital ?? 0); LocalPlanet.addMaterial(builder, planet.material ?? 0); LocalPlanet.addPopulation(builder, planet.population ?? 0); LocalPlanet.addIndustry(builder, planet.industry ?? 0); LocalPlanet.addColonists(builder, planet.colonists ?? 0); if (production !== null) LocalPlanet.addProduction(builder, production); LocalPlanet.addFreeIndustry(builder, planet.freeIndustry ?? 0); return LocalPlanet.endLocalPlanet(builder); }); const otherOffsets = (fixture.otherPlanets ?? []).map((planet) => { const name = builder.createString(planet.name); const owner = builder.createString(planet.owner); const production = planet.production !== undefined ? builder.createString(planet.production) : null; OtherPlanet.startOtherPlanet(builder); OtherPlanet.addNumber(builder, BigInt(planet.number)); OtherPlanet.addX(builder, planet.x); OtherPlanet.addY(builder, planet.y); OtherPlanet.addName(builder, name); OtherPlanet.addOwner(builder, owner); OtherPlanet.addSize(builder, planet.size ?? 9); OtherPlanet.addResources(builder, planet.resources ?? 0.5); OtherPlanet.addCapital(builder, planet.capital ?? 0); OtherPlanet.addMaterial(builder, planet.material ?? 0); OtherPlanet.addPopulation(builder, planet.population ?? 0); OtherPlanet.addIndustry(builder, planet.industry ?? 0); OtherPlanet.addColonists(builder, planet.colonists ?? 0); if (production !== null) OtherPlanet.addProduction(builder, production); OtherPlanet.addFreeIndustry(builder, planet.freeIndustry ?? 0); return OtherPlanet.endOtherPlanet(builder); }); const uninhabitedOffsets = (fixture.uninhabitedPlanets ?? []).map( (planet) => { const name = builder.createString(planet.name); UninhabitedPlanet.startUninhabitedPlanet(builder); UninhabitedPlanet.addNumber(builder, BigInt(planet.number)); UninhabitedPlanet.addX(builder, planet.x); UninhabitedPlanet.addY(builder, planet.y); UninhabitedPlanet.addName(builder, name); UninhabitedPlanet.addSize(builder, planet.size ?? 6); UninhabitedPlanet.addResources(builder, planet.resources ?? 0.5); UninhabitedPlanet.addCapital(builder, planet.capital ?? 0); UninhabitedPlanet.addMaterial(builder, planet.material ?? 0); return UninhabitedPlanet.endUninhabitedPlanet(builder); }, ); const unidentifiedOffsets = (fixture.unidentifiedPlanets ?? []).map( (planet) => { UnidentifiedPlanet.startUnidentifiedPlanet(builder); UnidentifiedPlanet.addNumber(builder, BigInt(planet.number)); UnidentifiedPlanet.addX(builder, planet.x); UnidentifiedPlanet.addY(builder, planet.y); return UnidentifiedPlanet.endUnidentifiedPlanet(builder); }, ); const localShipClassOffsets = (fixture.localShipClass ?? []).map((cls) => { const name = builder.createString(cls.name); ShipClass.startShipClass(builder); ShipClass.addName(builder, name); ShipClass.addDrive(builder, cls.drive ?? 0); ShipClass.addArmament(builder, BigInt(cls.armament ?? 0)); ShipClass.addWeapons(builder, cls.weapons ?? 0); ShipClass.addShields(builder, cls.shields ?? 0); ShipClass.addCargo(builder, cls.cargo ?? 0); return ShipClass.endShipClass(builder); }); const localScienceOffsets = (fixture.localScience ?? []).map((sci) => { const name = builder.createString(sci.name); Science.startScience(builder); Science.addName(builder, name); Science.addDrive(builder, sci.drive ?? 0); Science.addWeapons(builder, sci.weapons ?? 0); Science.addShields(builder, sci.shields ?? 0); Science.addCargo(builder, sci.cargo ?? 0); return Science.endScience(builder); }); const playerOffsets = (fixture.players ?? []).map((p) => { const name = builder.createString(p.name); Player.startPlayer(builder); Player.addName(builder, name); Player.addDrive(builder, p.drive ?? 1); return Player.endPlayer(builder); }); const routeOffsets = (fixture.routes ?? []).map((route) => { const entryOffsets = route.entries.map((entry) => { const valueOffset = builder.createString(entry.loadType); RouteEntry.startRouteEntry(builder); RouteEntry.addKey(builder, BigInt(entry.destinationPlanetNumber)); RouteEntry.addValue(builder, valueOffset); return RouteEntry.endRouteEntry(builder); }); const entriesVec = Route.createRouteVector(builder, entryOffsets); Route.startRoute(builder); Route.addPlanet(builder, BigInt(route.sourcePlanetNumber)); Route.addRoute(builder, entriesVec); return Route.endRoute(builder); }); const localVec = localOffsets.length === 0 ? null : Report.createLocalPlanetVector(builder, localOffsets); const otherVec = otherOffsets.length === 0 ? null : Report.createOtherPlanetVector(builder, otherOffsets); const uninhabitedVec = uninhabitedOffsets.length === 0 ? null : Report.createUninhabitedPlanetVector(builder, uninhabitedOffsets); const unidentifiedVec = unidentifiedOffsets.length === 0 ? null : Report.createUnidentifiedPlanetVector(builder, unidentifiedOffsets); const localShipClassVec = localShipClassOffsets.length === 0 ? null : Report.createLocalShipClassVector(builder, localShipClassOffsets); const localScienceVec = localScienceOffsets.length === 0 ? null : Report.createLocalScienceVector(builder, localScienceOffsets); const playerVec = playerOffsets.length === 0 ? null : Report.createPlayerVector(builder, playerOffsets); const routeVec = routeOffsets.length === 0 ? null : Report.createRouteVector(builder, routeOffsets); const raceOffset = fixture.race === undefined ? null : builder.createString(fixture.race); const totalPlanets = (fixture.localPlanets ?? []).length + (fixture.otherPlanets ?? []).length + (fixture.uninhabitedPlanets ?? []).length + (fixture.unidentifiedPlanets ?? []).length; Report.startReport(builder); Report.addTurn(builder, BigInt(fixture.turn)); Report.addWidth(builder, fixture.mapWidth ?? 4000); Report.addHeight(builder, fixture.mapHeight ?? 4000); Report.addPlanetCount(builder, totalPlanets); if (raceOffset !== null) Report.addRace(builder, raceOffset); if (playerVec !== null) Report.addPlayer(builder, playerVec); if (localVec !== null) Report.addLocalPlanet(builder, localVec); if (otherVec !== null) Report.addOtherPlanet(builder, otherVec); if (uninhabitedVec !== null) Report.addUninhabitedPlanet(builder, uninhabitedVec); if (unidentifiedVec !== null) Report.addUnidentifiedPlanet(builder, unidentifiedVec); if (localShipClassVec !== null) Report.addLocalShipClass(builder, localShipClassVec); if (localScienceVec !== null) Report.addLocalScience(builder, localScienceVec); if (routeVec !== null) Report.addRoute(builder, routeVec); const reportOff = Report.endReport(builder); builder.finish(reportOff); return builder.asUint8Array(); }