235 lines
5.8 KiB
TypeScript
235 lines
5.8 KiB
TypeScript
/** JSON-safe contracts for an eventual server-authoritative Tera session. */
|
|
|
|
export type RealtimeActorKind = "humanoid" | "dog" | "crow";
|
|
export type RealtimeVehicleKind = "model-x";
|
|
export type RealtimeAircraftKind = "electric-vtail";
|
|
export type RealtimeMemberRole = "visitor" | "member" | "admin";
|
|
export type RealtimeRevocationReason =
|
|
| "signed-out"
|
|
| "membership-revoked"
|
|
| "session-replaced"
|
|
| "protocol-violation"
|
|
| "server-shutdown";
|
|
|
|
export interface CaliforniaTileInterest {
|
|
kind: "california-tile";
|
|
/** Discrete authored world grid, not web-map tiles. */
|
|
x: number;
|
|
y: number;
|
|
level: number;
|
|
}
|
|
|
|
export interface CityInterest {
|
|
kind: "city";
|
|
cityId: "bay-area" | "socal";
|
|
}
|
|
|
|
export interface OfficeInterest {
|
|
kind: "office";
|
|
officeId: string;
|
|
}
|
|
|
|
export interface FloorInterest {
|
|
kind: "floor";
|
|
officeId: string;
|
|
floorId: string;
|
|
}
|
|
|
|
export interface RoomInterest {
|
|
kind: "room";
|
|
officeId: string;
|
|
floorId: string;
|
|
roomId: string;
|
|
}
|
|
|
|
export type InterestCell =
|
|
| CaliforniaTileInterest
|
|
| CityInterest
|
|
| OfficeInterest
|
|
| FloorInterest
|
|
| RoomInterest;
|
|
|
|
/** Monotonic within one server epoch and bounded to an unsigned 32-bit integer. */
|
|
export type RealtimeSequence = number;
|
|
/** Unix epoch milliseconds, serialized as a safe integer. */
|
|
export type RealtimeTimestamp = number;
|
|
|
|
export interface GeographicPose {
|
|
space: "geographic";
|
|
lat: number;
|
|
lng: number;
|
|
altitudeM: number;
|
|
headingDeg: number;
|
|
pitchDeg: number;
|
|
}
|
|
|
|
export interface LocalPose {
|
|
space: "local";
|
|
/** The smallest spatial cell whose coordinates define this pose. */
|
|
cell: CityInterest | OfficeInterest | FloorInterest | RoomInterest;
|
|
xM: number;
|
|
yM: number;
|
|
zM: number;
|
|
headingDeg: number;
|
|
pitchDeg: number;
|
|
}
|
|
|
|
export type SpatialPose = GeographicPose | LocalPose;
|
|
|
|
export interface PoseVelocity {
|
|
xMps: number;
|
|
yMps: number;
|
|
zMps: number;
|
|
yawDegPerSec: number;
|
|
}
|
|
|
|
interface EntityPoseSnapshotBase {
|
|
sequence: RealtimeSequence;
|
|
timestampMs: RealtimeTimestamp;
|
|
pose: SpatialPose;
|
|
velocity: PoseVelocity;
|
|
}
|
|
|
|
export interface ActorPoseSnapshot extends EntityPoseSnapshotBase {
|
|
entity: "actor";
|
|
actorId: string;
|
|
kind: RealtimeActorKind;
|
|
}
|
|
|
|
export interface VehiclePoseSnapshot extends EntityPoseSnapshotBase {
|
|
entity: "vehicle";
|
|
vehicleId: string;
|
|
kind: RealtimeVehicleKind;
|
|
driverActorId: string | null;
|
|
steering: number;
|
|
wheelRadians: number;
|
|
}
|
|
|
|
/** Authoritative state needed to reproduce a piloted aircraft on another client. */
|
|
export interface AircraftPoseSnapshot extends EntityPoseSnapshotBase {
|
|
entity: "aircraft";
|
|
aircraftId: string;
|
|
kind: RealtimeAircraftKind;
|
|
pilotActorId: string;
|
|
rollDeg: number;
|
|
throttle: number;
|
|
rollInput: number;
|
|
pitchInput: number;
|
|
yawInput: number;
|
|
fanRadians: number;
|
|
}
|
|
|
|
export type EntityPoseSnapshot = ActorPoseSnapshot | VehiclePoseSnapshot | AircraftPoseSnapshot;
|
|
|
|
export interface JoinRequest {
|
|
type: "join-request";
|
|
protocolVersion: 1;
|
|
requestId: string;
|
|
actorId: string;
|
|
resumeToken: string | null;
|
|
lastReceivedSequence: RealtimeSequence | null;
|
|
interests: readonly InterestCell[];
|
|
}
|
|
|
|
export interface JoinGrant {
|
|
type: "join-grant";
|
|
protocolVersion: 1;
|
|
requestId: string;
|
|
sessionId: string;
|
|
actorId: string;
|
|
role: RealtimeMemberRole;
|
|
serverEpoch: string;
|
|
serverTimeMs: RealtimeTimestamp;
|
|
nextSequence: RealtimeSequence;
|
|
resumeToken: string;
|
|
interests: readonly InterestCell[];
|
|
initial: readonly EntityPoseSnapshot[];
|
|
}
|
|
|
|
export interface ResumeRequest {
|
|
type: "resume-request";
|
|
protocolVersion: 1;
|
|
requestId: string;
|
|
sessionId: string;
|
|
resumeToken: string;
|
|
serverEpoch: string;
|
|
lastReceivedSequence: RealtimeSequence;
|
|
interests: readonly InterestCell[];
|
|
}
|
|
|
|
export interface ResumeGrant {
|
|
type: "resume-grant";
|
|
protocolVersion: 1;
|
|
requestId: string;
|
|
sessionId: string;
|
|
serverEpoch: string;
|
|
serverTimeMs: RealtimeTimestamp;
|
|
nextSequence: RealtimeSequence;
|
|
resumeToken: string;
|
|
/** True means queued deltas bridge the requested sequence without a gap. */
|
|
continuous: boolean;
|
|
snapshot: readonly EntityPoseSnapshot[];
|
|
}
|
|
|
|
export interface PoseDelta {
|
|
type: "pose-delta";
|
|
protocolVersion: 1;
|
|
serverEpoch: string;
|
|
sequence: RealtimeSequence;
|
|
timestampMs: RealtimeTimestamp;
|
|
updates: readonly EntityPoseSnapshot[];
|
|
removedEntityIds: readonly string[];
|
|
}
|
|
|
|
export interface MembershipRevoked {
|
|
type: "membership-revoked";
|
|
protocolVersion: 1;
|
|
serverEpoch: string;
|
|
sequence: RealtimeSequence;
|
|
timestampMs: RealtimeTimestamp;
|
|
sessionId: string;
|
|
actorId: string;
|
|
reason: RealtimeRevocationReason;
|
|
reconnectAllowed: boolean;
|
|
}
|
|
|
|
export type ClientRealtimeMessage = JoinRequest | ResumeRequest;
|
|
export type ServerRealtimeMessage = JoinGrant | ResumeGrant | PoseDelta | MembershipRevoked;
|
|
|
|
export type RealtimeValidationResult<T> =
|
|
| { ok: true; value: T }
|
|
| { ok: false; error: string };
|
|
|
|
export interface MotionLimits {
|
|
maximumHorizontalSpeedMps: number;
|
|
maximumVerticalSpeedMps: number;
|
|
maximumTurnRateDegPerSec: number;
|
|
/** Allows quantization and packet jitter without permitting teleportation. */
|
|
positionSlackM: number;
|
|
minimumDeltaSeconds?: number;
|
|
maximumDeltaSeconds?: number;
|
|
}
|
|
|
|
export type MotionValidationResult =
|
|
| { ok: true; horizontalSpeedMps: number; verticalSpeedMps: number; turnRateDegPerSec: number }
|
|
| {
|
|
ok: false;
|
|
reason: "identity-mismatch" | "space-mismatch" | "time-invalid" | "speed-exceeded";
|
|
};
|
|
|
|
export interface InterpolationOptions {
|
|
interpolationDelayMs?: number;
|
|
maximumExtrapolationMs?: number;
|
|
capacity?: number;
|
|
}
|
|
|
|
export type BufferedSampleMode = "exact" | "interpolated" | "extrapolated" | "held";
|
|
|
|
export interface BufferedPoseSample {
|
|
mode: BufferedSampleMode;
|
|
pose: SpatialPose;
|
|
velocity: PoseVelocity;
|
|
timestampMs: RealtimeTimestamp;
|
|
sourceSequence: RealtimeSequence;
|
|
}
|