feat: complete actor handoff and piloted aircraft presence
This commit is contained in:
@@ -40,3 +40,7 @@ export {
|
||||
type SceneAircraftOptions,
|
||||
type SceneAircraftView,
|
||||
} from "./sceneAircraft.ts";
|
||||
export {
|
||||
createAircraftPoseSnapshot,
|
||||
type AircraftRealtimeIdentity,
|
||||
} from "./realtime.ts";
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/** Renderer-independent bridge from deterministic flight state to realtime protocol state. */
|
||||
|
||||
import type { AircraftPoseSnapshot } from "../realtime/types.ts";
|
||||
import type { AircraftControllerSnapshot } from "./controller.ts";
|
||||
|
||||
export interface AircraftRealtimeIdentity {
|
||||
aircraftId: string;
|
||||
pilotActorId: string;
|
||||
}
|
||||
|
||||
function identity(value: string, name: string): string {
|
||||
if (typeof value !== "string" || value.length === 0 || value.length > 256) {
|
||||
throw new RangeError(`${name} must be a non-empty string of at most 256 characters`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts one controller snapshot into the exact geographic wire contract.
|
||||
* Geographic velocity axes are east/up/north; heading zero therefore travels
|
||||
* north even though the Three.js presentation model faces local -Z.
|
||||
*/
|
||||
export function createAircraftPoseSnapshot(
|
||||
identityValue: AircraftRealtimeIdentity,
|
||||
state: AircraftControllerSnapshot,
|
||||
sequence: number,
|
||||
timestampMs: number,
|
||||
): AircraftPoseSnapshot {
|
||||
const heading = state.headingDeg * Math.PI / 180;
|
||||
const pitch = state.pitchDeg * Math.PI / 180;
|
||||
const horizontalSpeedMps = state.speedMps * Math.cos(pitch);
|
||||
return {
|
||||
entity: "aircraft",
|
||||
aircraftId: identity(identityValue.aircraftId, "aircraftId"),
|
||||
kind: "electric-vtail",
|
||||
pilotActorId: identity(identityValue.pilotActorId, "pilotActorId"),
|
||||
sequence,
|
||||
timestampMs,
|
||||
pose: {
|
||||
space: "geographic",
|
||||
lat: state.lat,
|
||||
lng: state.lng,
|
||||
altitudeM: state.altitudeM,
|
||||
headingDeg: state.headingDeg,
|
||||
pitchDeg: state.pitchDeg,
|
||||
},
|
||||
velocity: {
|
||||
xMps: Math.sin(heading) * horizontalSpeedMps,
|
||||
yMps: state.verticalSpeedMps,
|
||||
zMps: Math.cos(heading) * horizontalSpeedMps,
|
||||
yawDegPerSec: 0,
|
||||
},
|
||||
rollDeg: state.rollDeg,
|
||||
throttle: state.throttle,
|
||||
rollInput: state.rollInput,
|
||||
pitchInput: state.pitchInput,
|
||||
yawInput: state.yawInput,
|
||||
fanRadians: state.fanRadians,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user