feat: v0.10.0 — right Jobs & Market pane (contracts accept/dispatch, market buy/sell/refuel with live previews); catalog + economy constants exposed in /api/state; shared applySnapshot for instant action feedback

This commit is contained in:
2026-09-17 19:18:42 +00:00
parent 03653fc50e
commit cf811dcf4d
15 changed files with 894 additions and 14 deletions
+25
View File
@@ -36,3 +36,28 @@ export const FUEL_PRICE_PER_L = 0.8;
// Fraction of the catalog price paid out when selling a plane (v0.8.0).
export const SELL_FRACTION = 0.5;
// Snapshot shape of one catalog entry in GET /api/state (v0.10.0): `model` is the
// id used by buy/dispatch, `label` the display name — clients compute all market
// previews (buy price, sell payout, refuel cost) from these + the economy constants.
export interface CatalogEntry {
model: string;
label: string;
price: number;
maxFuel: number;
burnPerKm: number;
speedKmh: number;
}
// The catalog as a flat array, one entry per plane type — the single source of
// truth for both the sim (PLANE_TYPES) and the client snapshot.
export function catalogEntries(): CatalogEntry[] {
return Object.values(PLANE_TYPES).map((t) => ({
model: t.id,
label: t.name,
price: t.price,
maxFuel: t.maxFuel,
burnPerKm: t.burnPerKm,
speedKmh: t.speedKmh,
}));
}
+9 -1
View File
@@ -2,7 +2,7 @@ import { loadAirportsGeoJson } from '@/lib/airports';
import { haversineKm } from '@/lib/geo';
import { getGameDb } from '@/lib/db/client';
import * as schema from '@/lib/db/schema';
import { PLANE_TYPES } from './catalog';
import { catalogEntries, FUEL_PRICE_PER_L, PLANE_TYPES, SELL_FRACTION, type CatalogEntry } from './catalog';
import { fuelAt, progressAt, positionAt } from '@/lib/sim/movement';
// Read-only game-state snapshot for client polling (GET /api/state).
@@ -43,6 +43,11 @@ export interface StateSnapshot {
simState: { clockMs: number; timeScale: number; paused: boolean };
planes: PlaneState[];
contracts: ContractState[];
// Market reference data (v0.10.0) — static per build, sent with every snapshot so
// the client can compute buy/sell/refuel previews without a separate endpoint.
catalog: CatalogEntry[];
fuelPricePerL: number;
sellFraction: number;
}
export async function getStateSnapshot(): Promise<StateSnapshot> {
@@ -84,6 +89,9 @@ export async function getStateSnapshot(): Promise<StateSnapshot> {
return {
account: { cash: accountRow.cash, reputation: accountRow.reputation },
simState: { clockMs: simRow.clockMs, timeScale: simRow.timeScale, paused: simRow.paused },
catalog: catalogEntries(),
fuelPricePerL: FUEL_PRICE_PER_L,
sellFraction: SELL_FRACTION,
planes: planeRows.map((p) => {
const live = livePlane(p);
return {