ui/phase-18: ship-class calc bridge with live designer preview
Wires pkg/calc/ship.go into the WASM Core boundary as seven thin
wrappers (DriveEffective, EmptyMass, WeaponsBlockMass, FullMass,
Speed, CargoCapacity, CarryingMass). The ship-class designer reads
Core through a new CORE_CONTEXT_KEY populated by the in-game layout
and renders a five-row preview pane (mass, full-load mass, max
speed, range at full load, cargo capacity) that updates reactively
on every form edit and on the player's localPlayer{Drive,Weapons,
Shields,Cargo} tech levels — three of which are now decoded from
the report's Player block alongside the existing localPlayerDrive.
CarryingMass is the seventh wrapper added to the original six-function
list so that "full-load mass" composes through pkg/calc/ functions
without putting math in TypeScript.
This commit is contained in:
@@ -35,6 +35,44 @@ export interface EventSigningFields {
|
||||
payloadHash: Uint8Array;
|
||||
}
|
||||
|
||||
export interface DriveEffectiveInput {
|
||||
drive: number;
|
||||
driveTech: number;
|
||||
}
|
||||
|
||||
export interface ShipBlocksInput {
|
||||
drive: number;
|
||||
weapons: number;
|
||||
armament: number;
|
||||
shields: number;
|
||||
cargo: number;
|
||||
}
|
||||
|
||||
export interface WeaponsBlockInput {
|
||||
weapons: number;
|
||||
armament: number;
|
||||
}
|
||||
|
||||
export interface FullMassInput {
|
||||
emptyMass: number;
|
||||
carryingMass: number;
|
||||
}
|
||||
|
||||
export interface SpeedInput {
|
||||
driveEffective: number;
|
||||
fullMass: number;
|
||||
}
|
||||
|
||||
export interface CargoCapacityInput {
|
||||
cargo: number;
|
||||
cargoTech: number;
|
||||
}
|
||||
|
||||
export interface CarryingMassInput {
|
||||
load: number;
|
||||
cargoTech: number;
|
||||
}
|
||||
|
||||
export interface Core {
|
||||
/**
|
||||
* signRequest returns the canonical signing input bytes for a v1
|
||||
@@ -71,6 +109,54 @@ export interface Core {
|
||||
payloadBytes: Uint8Array,
|
||||
payloadHash: Uint8Array,
|
||||
): boolean;
|
||||
|
||||
/**
|
||||
* driveEffective wraps `pkg/calc/ship.go.DriveEffective`: effective
|
||||
* drive power = ship drive block × player drive tech.
|
||||
*/
|
||||
driveEffective(input: DriveEffectiveInput): number;
|
||||
|
||||
/**
|
||||
* emptyMass wraps `pkg/calc/ship.go.EmptyMass`: mass of the ship
|
||||
* with empty holds. Returns null when the upstream validator
|
||||
* rejects the weapons/armament pair (one zero and the other
|
||||
* non-zero).
|
||||
*/
|
||||
emptyMass(input: ShipBlocksInput): number | null;
|
||||
|
||||
/**
|
||||
* weaponsBlockMass wraps `pkg/calc/ship.go.WeaponsBlockMass`: mass
|
||||
* of the weapons sub-block. Returns null on the same invalid
|
||||
* pairing as emptyMass.
|
||||
*/
|
||||
weaponsBlockMass(input: WeaponsBlockInput): number | null;
|
||||
|
||||
/**
|
||||
* fullMass wraps `pkg/calc/ship.go.FullMass`: empty mass plus the
|
||||
* mass of the carried cargo.
|
||||
*/
|
||||
fullMass(input: FullMassInput): number;
|
||||
|
||||
/**
|
||||
* speed wraps `pkg/calc/ship.go.Speed`: light-years per turn,
|
||||
* driveEffective × 20 / fullMass; zero when fullMass ≤ 0.
|
||||
*/
|
||||
speed(input: SpeedInput): number;
|
||||
|
||||
/**
|
||||
* cargoCapacity wraps `pkg/calc/ship.go.CargoCapacity`: hold
|
||||
* capacity of one ship in cargo units, scaled by the player's
|
||||
* cargo tech.
|
||||
*/
|
||||
cargoCapacity(input: CargoCapacityInput): number;
|
||||
|
||||
/**
|
||||
* carryingMass wraps `pkg/calc/ship.go.CarryingMass`: mass of a
|
||||
* payload of `load` cargo units at the player's cargo tech. Used
|
||||
* by the ship-class designer to derive full-load mass from
|
||||
* cargoCapacity.
|
||||
*/
|
||||
carryingMass(input: CarryingMassInput): number;
|
||||
}
|
||||
|
||||
export type CoreLoader = () => Promise<Core>;
|
||||
|
||||
@@ -9,10 +9,17 @@
|
||||
// served from `static/core.wasm`.
|
||||
|
||||
import type {
|
||||
CargoCapacityInput,
|
||||
CarryingMassInput,
|
||||
Core,
|
||||
DriveEffectiveInput,
|
||||
EventSigningFields,
|
||||
FullMassInput,
|
||||
RequestSigningFields,
|
||||
ResponseSigningFields,
|
||||
ShipBlocksInput,
|
||||
SpeedInput,
|
||||
WeaponsBlockInput,
|
||||
} from "./index";
|
||||
|
||||
/**
|
||||
@@ -36,6 +43,13 @@ interface GalaxyCoreBridge {
|
||||
payloadBytes: Uint8Array,
|
||||
payloadHash: Uint8Array,
|
||||
): boolean;
|
||||
driveEffective(input: DriveEffectiveInput): number;
|
||||
emptyMass(input: ShipBlocksInput): number | null;
|
||||
weaponsBlockMass(input: WeaponsBlockInput): number | null;
|
||||
fullMass(input: FullMassInput): number;
|
||||
speed(input: SpeedInput): number;
|
||||
cargoCapacity(input: CargoCapacityInput): number;
|
||||
carryingMass(input: CarryingMassInput): number;
|
||||
}
|
||||
|
||||
interface BridgeRequestFields {
|
||||
@@ -175,6 +189,27 @@ export function adaptBridge(bridge: GalaxyCoreBridge): Core {
|
||||
): boolean {
|
||||
return bridge.verifyPayloadHash(payloadBytes, payloadHash);
|
||||
},
|
||||
driveEffective(input: DriveEffectiveInput): number {
|
||||
return bridge.driveEffective(input);
|
||||
},
|
||||
emptyMass(input: ShipBlocksInput): number | null {
|
||||
return bridge.emptyMass(input);
|
||||
},
|
||||
weaponsBlockMass(input: WeaponsBlockInput): number | null {
|
||||
return bridge.weaponsBlockMass(input);
|
||||
},
|
||||
fullMass(input: FullMassInput): number {
|
||||
return bridge.fullMass(input);
|
||||
},
|
||||
speed(input: SpeedInput): number {
|
||||
return bridge.speed(input);
|
||||
},
|
||||
cargoCapacity(input: CargoCapacityInput): number {
|
||||
return bridge.cargoCapacity(input);
|
||||
},
|
||||
carryingMass(input: CarryingMassInput): number {
|
||||
return bridge.carryingMass(input);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user