mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-03-13 17:30:56 +00:00
185 lines
5.5 KiB
TypeScript
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;
|
|
}
|