Add scene entry and exit interfaces and update spawn logic
This commit is contained in:
@@ -96,6 +96,12 @@ export interface RuntimePlayerStart {
|
|||||||
collider: FirstPersonPlayerShape;
|
collider: FirstPersonPlayerShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RuntimeSceneEntry {
|
||||||
|
entityId: string;
|
||||||
|
position: Vec3;
|
||||||
|
yawDegrees: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RuntimeSoundEmitter {
|
export interface RuntimeSoundEmitter {
|
||||||
entityId: string;
|
entityId: string;
|
||||||
position: Vec3;
|
position: Vec3;
|
||||||
@@ -129,6 +135,16 @@ export interface RuntimeInteractable {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RuntimeSceneExit {
|
||||||
|
entityId: string;
|
||||||
|
position: Vec3;
|
||||||
|
radius: number;
|
||||||
|
prompt: string;
|
||||||
|
enabled: boolean;
|
||||||
|
targetSceneId: string;
|
||||||
|
targetEntryEntityId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RuntimePointLight {
|
export interface RuntimePointLight {
|
||||||
entityId: string;
|
entityId: string;
|
||||||
position: Vec3;
|
position: Vec3;
|
||||||
@@ -165,14 +181,16 @@ export interface RuntimeModelInstance {
|
|||||||
|
|
||||||
export interface RuntimeEntityCollection {
|
export interface RuntimeEntityCollection {
|
||||||
playerStarts: RuntimePlayerStart[];
|
playerStarts: RuntimePlayerStart[];
|
||||||
|
sceneEntries: RuntimeSceneEntry[];
|
||||||
soundEmitters: RuntimeSoundEmitter[];
|
soundEmitters: RuntimeSoundEmitter[];
|
||||||
triggerVolumes: RuntimeTriggerVolume[];
|
triggerVolumes: RuntimeTriggerVolume[];
|
||||||
teleportTargets: RuntimeTeleportTarget[];
|
teleportTargets: RuntimeTeleportTarget[];
|
||||||
interactables: RuntimeInteractable[];
|
interactables: RuntimeInteractable[];
|
||||||
|
sceneExits: RuntimeSceneExit[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RuntimeSpawnPoint {
|
export interface RuntimeSpawnPoint {
|
||||||
source: "playerStart" | "fallback";
|
source: "playerStart" | "sceneEntry" | "fallback";
|
||||||
entityId: string | null;
|
entityId: string | null;
|
||||||
position: Vec3;
|
position: Vec3;
|
||||||
yawDegrees: number;
|
yawDegrees: number;
|
||||||
@@ -193,9 +211,10 @@ export interface RuntimeSceneDefinition {
|
|||||||
spawn: RuntimeSpawnPoint;
|
spawn: RuntimeSpawnPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BuildRuntimeSceneOptions {
|
export interface BuildRuntimeSceneOptions {
|
||||||
navigationMode?: RuntimeNavigationMode;
|
navigationMode?: RuntimeNavigationMode;
|
||||||
loadedModelAssets?: Record<string, LoadedModelAsset>;
|
loadedModelAssets?: Record<string, LoadedModelAsset>;
|
||||||
|
sceneEntryId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneVec3(vector: Vec3): Vec3 {
|
function cloneVec3(vector: Vec3): Vec3 {
|
||||||
@@ -411,10 +430,12 @@ interface RuntimeSceneCollections {
|
|||||||
function buildRuntimeSceneCollections(document: SceneDocument): RuntimeSceneCollections {
|
function buildRuntimeSceneCollections(document: SceneDocument): RuntimeSceneCollections {
|
||||||
const runtimeEntities: RuntimeEntityCollection = {
|
const runtimeEntities: RuntimeEntityCollection = {
|
||||||
playerStarts: [],
|
playerStarts: [],
|
||||||
|
sceneEntries: [],
|
||||||
soundEmitters: [],
|
soundEmitters: [],
|
||||||
triggerVolumes: [],
|
triggerVolumes: [],
|
||||||
teleportTargets: [],
|
teleportTargets: [],
|
||||||
interactables: []
|
interactables: [],
|
||||||
|
sceneExits: []
|
||||||
};
|
};
|
||||||
const localLights: RuntimeLocalLightCollection = {
|
const localLights: RuntimeLocalLightCollection = {
|
||||||
pointLights: [],
|
pointLights: [],
|
||||||
@@ -451,6 +472,13 @@ function buildRuntimeSceneCollections(document: SceneDocument): RuntimeSceneColl
|
|||||||
collider: buildRuntimePlayerShape(entity)
|
collider: buildRuntimePlayerShape(entity)
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "sceneEntry":
|
||||||
|
runtimeEntities.sceneEntries.push({
|
||||||
|
entityId: entity.id,
|
||||||
|
position: cloneVec3(entity.position),
|
||||||
|
yawDegrees: entity.yawDegrees
|
||||||
|
});
|
||||||
|
break;
|
||||||
case "soundEmitter":
|
case "soundEmitter":
|
||||||
runtimeEntities.soundEmitters.push({
|
runtimeEntities.soundEmitters.push({
|
||||||
entityId: entity.id,
|
entityId: entity.id,
|
||||||
@@ -493,6 +521,17 @@ function buildRuntimeSceneCollections(document: SceneDocument): RuntimeSceneColl
|
|||||||
enabled: entity.enabled
|
enabled: entity.enabled
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "sceneExit":
|
||||||
|
runtimeEntities.sceneExits.push({
|
||||||
|
entityId: entity.id,
|
||||||
|
position: cloneVec3(entity.position),
|
||||||
|
radius: entity.radius,
|
||||||
|
prompt: entity.prompt,
|
||||||
|
enabled: entity.enabled,
|
||||||
|
targetSceneId: entity.targetSceneId,
|
||||||
|
targetEntryEntityId: entity.targetEntryEntityId
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assertNever(entity);
|
assertNever(entity);
|
||||||
}
|
}
|
||||||
@@ -537,6 +576,42 @@ function buildRuntimePlayerShape(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveRuntimeSpawn(
|
||||||
|
playerStart: RuntimePlayerStart | null,
|
||||||
|
sceneEntries: RuntimeSceneEntry[],
|
||||||
|
sceneBounds: RuntimeSceneBounds | null,
|
||||||
|
sceneEntryId: string | null | undefined
|
||||||
|
): RuntimeSpawnPoint {
|
||||||
|
if (sceneEntryId !== undefined && sceneEntryId !== null) {
|
||||||
|
const sceneEntry =
|
||||||
|
sceneEntries.find((entry) => entry.entityId === sceneEntryId) ?? null;
|
||||||
|
|
||||||
|
if (sceneEntry === null) {
|
||||||
|
throw new Error(
|
||||||
|
`Runtime build could not resolve Scene Entry ${sceneEntryId}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
source: "sceneEntry",
|
||||||
|
entityId: sceneEntry.entityId,
|
||||||
|
position: cloneVec3(sceneEntry.position),
|
||||||
|
yawDegrees: sceneEntry.yawDegrees
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerStart !== null) {
|
||||||
|
return {
|
||||||
|
source: "playerStart",
|
||||||
|
entityId: playerStart.entityId,
|
||||||
|
position: cloneVec3(playerStart.position),
|
||||||
|
yawDegrees: playerStart.yawDegrees
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildFallbackSpawn(sceneBounds);
|
||||||
|
}
|
||||||
|
|
||||||
export function buildRuntimeSceneFromDocument(document: SceneDocument, options: BuildRuntimeSceneOptions = {}): RuntimeSceneDefinition {
|
export function buildRuntimeSceneFromDocument(document: SceneDocument, options: BuildRuntimeSceneOptions = {}): RuntimeSceneDefinition {
|
||||||
assertRuntimeSceneBuildable(document, {
|
assertRuntimeSceneBuildable(document, {
|
||||||
navigationMode: options.navigationMode ?? "orbitVisitor",
|
navigationMode: options.navigationMode ?? "orbitVisitor",
|
||||||
@@ -606,14 +681,11 @@ export function buildRuntimeSceneFromDocument(document: SceneDocument, options:
|
|||||||
interactionLinks,
|
interactionLinks,
|
||||||
playerStart,
|
playerStart,
|
||||||
playerCollider,
|
playerCollider,
|
||||||
spawn:
|
spawn: resolveRuntimeSpawn(
|
||||||
playerStart === null
|
playerStart,
|
||||||
? buildFallbackSpawn(combinedSceneBounds)
|
collections.entities.sceneEntries,
|
||||||
: {
|
combinedSceneBounds,
|
||||||
source: "playerStart",
|
options.sceneEntryId
|
||||||
entityId: playerStart.entityId,
|
)
|
||||||
position: cloneVec3(playerStart.position),
|
|
||||||
yawDegrees: playerStart.yawDegrees
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user