t2-mapper/src/stream/entityBridge.ts
2026-03-09 12:38:40 -07:00

185 lines
5.5 KiB
TypeScript

import type { StreamEntity } from "./types";
import type {
GameEntity,
ShapeEntity,
PlayerEntity,
ForceFieldBareEntity,
ExplosionEntity,
TracerEntity,
SpriteEntity,
AudioEmitterEntity,
CameraEntity,
WayPointEntity,
} from "../state/gameEntityTypes";
import type { SceneTSStatic } from "../scene/types";
/** Common fields extracted from a StreamEntity for positioned game entities. */
function positionedBase(entity: StreamEntity, spawnTime?: number) {
return {
id: entity.id,
className: entity.className ?? entity.type,
ghostIndex: entity.ghostIndex,
dataBlockId: entity.dataBlockId,
shapeHint: entity.shapeHint,
spawnTime,
position: entity.position,
rotation: entity.rotation,
velocity: entity.velocity,
keyframes: [
{
time: spawnTime ?? 0,
position: entity.position ?? [0, 0, 0] as [number, number, number],
rotation: entity.rotation ?? [0, 0, 0, 1] as [number, number, number, number],
},
],
};
}
/** Convert a StreamEntity to a GameEntity for the entity store. */
export function streamEntityToGameEntity(
entity: StreamEntity,
spawnTime?: number,
): GameEntity {
// Scene infrastructure — routed from sceneData
if (entity.sceneData) {
const base = {
id: entity.id,
className: entity.className ?? entity.type,
ghostIndex: entity.ghostIndex,
dataBlockId: entity.dataBlockId,
shapeHint: entity.shapeHint,
spawnTime,
};
switch (entity.sceneData.className) {
case "TerrainBlock":
return { ...base, renderType: "TerrainBlock", terrainData: entity.sceneData };
case "InteriorInstance":
return { ...base, renderType: "InteriorInstance", interiorData: entity.sceneData };
case "Sky":
return { ...base, renderType: "Sky", skyData: entity.sceneData };
case "Sun":
return { ...base, renderType: "Sun", sunData: entity.sceneData };
case "WaterBlock":
return { ...base, renderType: "WaterBlock", waterData: entity.sceneData };
case "MissionArea":
return { ...base, renderType: "MissionArea", missionAreaData: entity.sceneData };
case "TSStatic":
// TSStatic is rendered as a shape — extract shapeName from scene data.
return {
...positionedBase(entity, spawnTime),
renderType: "Shape",
shapeName: (entity.sceneData as SceneTSStatic).shapeName,
shapeType: "TSStatic",
dataBlock: entity.dataBlock,
} satisfies ShapeEntity;
}
}
// Projectile visuals
if (entity.visual?.kind === "tracer") {
return {
...positionedBase(entity, spawnTime),
renderType: "Tracer",
visual: entity.visual,
dataBlock: entity.dataBlock,
direction: entity.direction,
} satisfies TracerEntity;
}
if (entity.visual?.kind === "sprite") {
return {
...positionedBase(entity, spawnTime),
renderType: "Sprite",
visual: entity.visual,
} satisfies SpriteEntity;
}
// Player
if (entity.type === "Player") {
return {
...positionedBase(entity, spawnTime),
renderType: "Player",
shapeName: entity.dataBlock,
dataBlock: entity.dataBlock,
weaponShape: entity.weaponShape,
playerName: entity.playerName,
iffColor: entity.iffColor,
threads: entity.threads,
weaponImageState: entity.weaponImageState,
weaponImageStates: entity.weaponImageStates,
headPitch: entity.headPitch,
headYaw: entity.headYaw,
targetRenderFlags: entity.targetRenderFlags,
} satisfies PlayerEntity;
}
// Explosion
if (entity.type === "Explosion") {
return {
...positionedBase(entity, spawnTime),
renderType: "Explosion",
shapeName: entity.dataBlock,
dataBlock: entity.dataBlock,
explosionDataBlockId: entity.explosionDataBlockId,
faceViewer: entity.faceViewer,
} satisfies ExplosionEntity;
}
// Force field
if (entity.className === "ForceFieldBare") {
return {
...positionedBase(entity, spawnTime),
renderType: "ForceFieldBare",
} satisfies ForceFieldBareEntity;
}
// Audio emitter
if (entity.className === "AudioEmitter") {
return {
...positionedBase(entity, spawnTime),
renderType: "AudioEmitter",
audioFileName: entity.audioFileName,
audioVolume: entity.audioVolume,
audioIs3D: entity.audioIs3D,
audioIsLooping: entity.audioIsLooping ?? true,
audioMinDistance: entity.audioMinDistance,
audioMaxDistance: entity.audioMaxDistance,
audioMinLoopGap: entity.audioMinLoopGap,
audioMaxLoopGap: entity.audioMaxLoopGap,
} satisfies AudioEmitterEntity;
}
// WayPoint
if (entity.className === "WayPoint") {
return {
...positionedBase(entity, spawnTime),
renderType: "WayPoint",
label: entity.label,
} satisfies WayPointEntity;
}
// Camera
if (entity.className === "Camera") {
return {
...positionedBase(entity, spawnTime),
renderType: "Camera",
} satisfies CameraEntity;
}
// Default: generic DTS shape
return {
...positionedBase(entity, spawnTime),
renderType: "Shape",
shapeName: entity.dataBlock,
shapeType:
entity.className === "Turret"
? "Turret"
: entity.className === "Item"
? "Item"
: "StaticShape",
dataBlock: entity.dataBlock,
weaponShape: entity.weaponShape,
threads: entity.threads,
targetRenderFlags: entity.targetRenderFlags,
iffColor: entity.iffColor,
} satisfies ShapeEntity;
}