Files
Flight-Ops/lib/game/state.ts
T

92 lines
2.8 KiB
TypeScript

import { loadAirportsGeoJson } from '@/lib/airports';
import { getGameDb } from '@/lib/db/client';
import * as schema from '@/lib/db/schema';
// Read-only game-state snapshot for client polling (GET /api/state).
export interface PlaneState {
id: string;
model: string;
status: 'available' | 'flying';
fuel: number;
maxFuel: number;
locationIcao: string;
locationName: string;
contractId: string | null;
lat: number;
lon: number;
}
export interface ContractState {
id: string;
originIcao: string;
originName: string;
destIcao: string;
destName: string;
reward: number;
cargoType: string;
cargoCount: number;
deadlineSimTime: number;
status: 'open' | 'accepted' | 'completed';
planeId: string | null;
createdSimTime: number;
}
export interface StateSnapshot {
account: { cash: number; reputation: number };
simState: { clockMs: number; timeScale: number; paused: boolean };
planes: PlaneState[];
contracts: ContractState[];
}
export async function getStateSnapshot(): Promise<StateSnapshot> {
const { db } = await getGameDb();
// NOTE: use plain select(), not the relational db.query.* API — in drizzle-orm
// 0.45.x the sql-js driver drops the result mapper for relational queries and
// returns raw rows keyed by SQL column names (snake_case, no type decoding).
const [accountRows, simRows, planeRows, contractRows] = await Promise.all([
db.select().from(schema.account),
db.select().from(schema.simState),
db.select().from(schema.planes),
db.select().from(schema.contracts),
]);
const accountRow = accountRows[0];
const simRow = simRows[0];
if (!accountRow || !simRow) throw new Error('game state missing account/sim_state row');
const fc = await loadAirportsGeoJson();
const nameByIcao = new Map(fc.features.map((f) => [f.properties.icao, f.properties.name]));
const nameOf = (icao: string) => nameByIcao.get(icao) ?? icao;
return {
account: { cash: accountRow.cash, reputation: accountRow.reputation },
simState: { clockMs: simRow.clockMs, timeScale: simRow.timeScale, paused: simRow.paused },
planes: planeRows.map((p) => ({
id: p.id,
model: p.model,
status: p.status,
fuel: p.fuel,
maxFuel: p.maxFuel,
locationIcao: p.locationIcao,
locationName: nameOf(p.locationIcao),
contractId: p.contractId,
lat: p.lat,
lon: p.lon,
})),
contracts: contractRows.map((c) => ({
id: c.id,
originIcao: c.originIcao,
originName: nameOf(c.originIcao),
destIcao: c.destIcao,
destName: nameOf(c.destIcao),
reward: c.reward,
cargoType: c.cargoType,
cargoCount: c.cargoCount,
deadlineSimTime: c.deadlineSimTime,
status: c.status,
planeId: c.planeId,
createdSimTime: c.createdSimTime,
})),
};
}