Add visibility and enabled properties to model instances, brushes, and entities
This commit is contained in:
@@ -16,6 +16,8 @@ export interface ModelInstance {
|
|||||||
kind: "modelInstance";
|
kind: "modelInstance";
|
||||||
assetId: string;
|
assetId: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
visible: boolean;
|
||||||
|
enabled: boolean;
|
||||||
position: Vec3;
|
position: Vec3;
|
||||||
rotationDegrees: Vec3;
|
rotationDegrees: Vec3;
|
||||||
scale: Vec3;
|
scale: Vec3;
|
||||||
@@ -42,6 +44,9 @@ export const DEFAULT_MODEL_INSTANCE_SCALE: Vec3 = {
|
|||||||
z: 1
|
z: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DEFAULT_MODEL_INSTANCE_VISIBLE = true;
|
||||||
|
export const DEFAULT_MODEL_INSTANCE_ENABLED = true;
|
||||||
|
|
||||||
export const DEFAULT_MODEL_INSTANCE_COLLISION_SETTINGS: ModelInstanceCollisionSettings = {
|
export const DEFAULT_MODEL_INSTANCE_COLLISION_SETTINGS: ModelInstanceCollisionSettings = {
|
||||||
mode: "none",
|
mode: "none",
|
||||||
visible: false
|
visible: false
|
||||||
@@ -117,7 +122,7 @@ function assertPositiveFiniteVec3(vector: Vec3, label: string) {
|
|||||||
|
|
||||||
export function createModelInstance(
|
export function createModelInstance(
|
||||||
overrides: Partial<
|
overrides: Partial<
|
||||||
Pick<ModelInstance, "id" | "name" | "position" | "rotationDegrees" | "scale" | "collision" | "animationClipName" | "animationAutoplay">
|
Pick<ModelInstance, "id" | "name" | "visible" | "enabled" | "position" | "rotationDegrees" | "scale" | "collision" | "animationClipName" | "animationAutoplay">
|
||||||
> &
|
> &
|
||||||
Pick<ModelInstance, "assetId">
|
Pick<ModelInstance, "assetId">
|
||||||
): ModelInstance {
|
): ModelInstance {
|
||||||
@@ -125,6 +130,8 @@ export function createModelInstance(
|
|||||||
const rotationDegrees = cloneVec3(overrides.rotationDegrees ?? DEFAULT_MODEL_INSTANCE_ROTATION_DEGREES);
|
const rotationDegrees = cloneVec3(overrides.rotationDegrees ?? DEFAULT_MODEL_INSTANCE_ROTATION_DEGREES);
|
||||||
const scale = cloneVec3(overrides.scale ?? DEFAULT_MODEL_INSTANCE_SCALE);
|
const scale = cloneVec3(overrides.scale ?? DEFAULT_MODEL_INSTANCE_SCALE);
|
||||||
const collision = cloneModelInstanceCollisionSettings(overrides.collision ?? DEFAULT_MODEL_INSTANCE_COLLISION_SETTINGS);
|
const collision = cloneModelInstanceCollisionSettings(overrides.collision ?? DEFAULT_MODEL_INSTANCE_COLLISION_SETTINGS);
|
||||||
|
const visible = overrides.visible ?? DEFAULT_MODEL_INSTANCE_VISIBLE;
|
||||||
|
const enabled = overrides.enabled ?? DEFAULT_MODEL_INSTANCE_ENABLED;
|
||||||
|
|
||||||
if (overrides.assetId.trim().length === 0) {
|
if (overrides.assetId.trim().length === 0) {
|
||||||
throw new Error("Model instance assetId must be a non-empty string.");
|
throw new Error("Model instance assetId must be a non-empty string.");
|
||||||
@@ -134,11 +141,21 @@ export function createModelInstance(
|
|||||||
assertFiniteVec3(rotationDegrees, "Model instance rotation");
|
assertFiniteVec3(rotationDegrees, "Model instance rotation");
|
||||||
assertPositiveFiniteVec3(scale, "Model instance scale");
|
assertPositiveFiniteVec3(scale, "Model instance scale");
|
||||||
|
|
||||||
|
if (typeof visible !== "boolean") {
|
||||||
|
throw new Error("Model instance visible must be a boolean.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof enabled !== "boolean") {
|
||||||
|
throw new Error("Model instance enabled must be a boolean.");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: overrides.id ?? createOpaqueId("model-instance"),
|
id: overrides.id ?? createOpaqueId("model-instance"),
|
||||||
kind: "modelInstance",
|
kind: "modelInstance",
|
||||||
assetId: overrides.assetId,
|
assetId: overrides.assetId,
|
||||||
name: normalizeModelInstanceName(overrides.name),
|
name: normalizeModelInstanceName(overrides.name),
|
||||||
|
visible,
|
||||||
|
enabled,
|
||||||
position,
|
position,
|
||||||
rotationDegrees,
|
rotationDegrees,
|
||||||
scale,
|
scale,
|
||||||
@@ -178,6 +195,8 @@ export function areModelInstancesEqual(left: ModelInstance, right: ModelInstance
|
|||||||
left.kind === right.kind &&
|
left.kind === right.kind &&
|
||||||
left.assetId === right.assetId &&
|
left.assetId === right.assetId &&
|
||||||
left.name === right.name &&
|
left.name === right.name &&
|
||||||
|
left.visible === right.visible &&
|
||||||
|
left.enabled === right.enabled &&
|
||||||
areVec3Equal(left.position, right.position) &&
|
areVec3Equal(left.position, right.position) &&
|
||||||
areVec3Equal(left.rotationDegrees, right.rotationDegrees) &&
|
areVec3Equal(left.rotationDegrees, right.rotationDegrees) &&
|
||||||
areVec3Equal(left.scale, right.scale) &&
|
areVec3Equal(left.scale, right.scale) &&
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ export interface BoxBrush {
|
|||||||
id: string;
|
id: string;
|
||||||
kind: "box";
|
kind: "box";
|
||||||
name?: string;
|
name?: string;
|
||||||
|
visible: boolean;
|
||||||
|
enabled: boolean;
|
||||||
center: Vec3;
|
center: Vec3;
|
||||||
rotationDegrees: Vec3;
|
rotationDegrees: Vec3;
|
||||||
size: Vec3;
|
size: Vec3;
|
||||||
@@ -152,6 +154,9 @@ export const DEFAULT_BOX_BRUSH_ROTATION_DEGREES: Vec3 = {
|
|||||||
z: 0
|
z: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DEFAULT_BOX_BRUSH_VISIBLE = true;
|
||||||
|
export const DEFAULT_BOX_BRUSH_ENABLED = true;
|
||||||
|
|
||||||
export const DEFAULT_BOX_BRUSH_WATER_FOAM_CONTACT_LIMIT = 6;
|
export const DEFAULT_BOX_BRUSH_WATER_FOAM_CONTACT_LIMIT = 6;
|
||||||
export const MAX_BOX_BRUSH_WATER_FOAM_CONTACT_LIMIT = 24;
|
export const MAX_BOX_BRUSH_WATER_FOAM_CONTACT_LIMIT = 24;
|
||||||
|
|
||||||
@@ -482,7 +487,7 @@ export function cloneBoxBrushVolumeSettings(volume: BoxBrushVolumeSettings): Box
|
|||||||
|
|
||||||
export function createBoxBrush(
|
export function createBoxBrush(
|
||||||
overrides: Partial<
|
overrides: Partial<
|
||||||
Pick<BoxBrush, "id" | "name" | "center" | "rotationDegrees" | "size" | "geometry" | "faces" | "volume" | "layerId" | "groupId">
|
Pick<BoxBrush, "id" | "name" | "visible" | "enabled" | "center" | "rotationDegrees" | "size" | "geometry" | "faces" | "volume" | "layerId" | "groupId">
|
||||||
> = {}
|
> = {}
|
||||||
): BoxBrush {
|
): BoxBrush {
|
||||||
const center = cloneVec3(overrides.center ?? DEFAULT_BOX_BRUSH_CENTER);
|
const center = cloneVec3(overrides.center ?? DEFAULT_BOX_BRUSH_CENTER);
|
||||||
@@ -490,15 +495,27 @@ export function createBoxBrush(
|
|||||||
const fallbackSize = cloneVec3(overrides.size ?? DEFAULT_BOX_BRUSH_SIZE);
|
const fallbackSize = cloneVec3(overrides.size ?? DEFAULT_BOX_BRUSH_SIZE);
|
||||||
const geometry = overrides.geometry === undefined ? createDefaultBoxBrushGeometry(fallbackSize) : cloneBoxBrushGeometry(overrides.geometry);
|
const geometry = overrides.geometry === undefined ? createDefaultBoxBrushGeometry(fallbackSize) : cloneBoxBrushGeometry(overrides.geometry);
|
||||||
const size = deriveBoxBrushSizeFromGeometry(geometry);
|
const size = deriveBoxBrushSizeFromGeometry(geometry);
|
||||||
|
const visible = overrides.visible ?? DEFAULT_BOX_BRUSH_VISIBLE;
|
||||||
|
const enabled = overrides.enabled ?? DEFAULT_BOX_BRUSH_ENABLED;
|
||||||
|
|
||||||
if (!hasPositiveBoxSize(size)) {
|
if (!hasPositiveBoxSize(size)) {
|
||||||
throw new Error("Box brush size must remain positive on every axis.");
|
throw new Error("Box brush size must remain positive on every axis.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof visible !== "boolean") {
|
||||||
|
throw new Error("Box brush visible must be a boolean.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof enabled !== "boolean") {
|
||||||
|
throw new Error("Box brush enabled must be a boolean.");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: overrides.id ?? createOpaqueId("brush"),
|
id: overrides.id ?? createOpaqueId("brush"),
|
||||||
kind: "box",
|
kind: "box",
|
||||||
name: normalizeBrushName(overrides.name),
|
name: normalizeBrushName(overrides.name),
|
||||||
|
visible,
|
||||||
|
enabled,
|
||||||
center,
|
center,
|
||||||
rotationDegrees,
|
rotationDegrees,
|
||||||
size,
|
size,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { isHexColorString } from "../document/world-settings";
|
|||||||
interface PositionedEntity {
|
interface PositionedEntity {
|
||||||
id: string;
|
id: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
visible: boolean;
|
||||||
|
enabled: boolean;
|
||||||
position: Vec3;
|
position: Vec3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,14 +220,14 @@ export interface InteractableEntity extends PositionedEntity {
|
|||||||
kind: "interactable";
|
kind: "interactable";
|
||||||
radius: number;
|
radius: number;
|
||||||
prompt: string;
|
prompt: string;
|
||||||
enabled: boolean;
|
interactionEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SceneExitEntity extends PositionedEntity {
|
export interface SceneExitEntity extends PositionedEntity {
|
||||||
kind: "sceneExit";
|
kind: "sceneExit";
|
||||||
radius: number;
|
radius: number;
|
||||||
prompt: string;
|
prompt: string;
|
||||||
enabled: boolean;
|
interactionEnabled: boolean;
|
||||||
targetSceneId: string;
|
targetSceneId: string;
|
||||||
targetEntryEntityId: string;
|
targetEntryEntityId: string;
|
||||||
}
|
}
|
||||||
@@ -290,6 +292,9 @@ export const DEFAULT_ENTITY_POSITION: Vec3 = {
|
|||||||
z: 0
|
z: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DEFAULT_ENTITY_VISIBLE = true;
|
||||||
|
export const DEFAULT_ENTITY_ENABLED = true;
|
||||||
|
|
||||||
export const DEFAULT_PLAYER_START_POSITION = DEFAULT_ENTITY_POSITION;
|
export const DEFAULT_PLAYER_START_POSITION = DEFAULT_ENTITY_POSITION;
|
||||||
export const DEFAULT_PLAYER_START_YAW_DEGREES = 0;
|
export const DEFAULT_PLAYER_START_YAW_DEGREES = 0;
|
||||||
export const DEFAULT_PLAYER_START_NAVIGATION_MODE: PlayerStartNavigationMode =
|
export const DEFAULT_PLAYER_START_NAVIGATION_MODE: PlayerStartNavigationMode =
|
||||||
@@ -1062,6 +1067,20 @@ export function normalizeEntityName(name: string | null | undefined): string | u
|
|||||||
return trimmedName.length === 0 ? undefined : trimmedName;
|
return trimmedName.length === 0 ? undefined : trimmedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveAuthoredEntityVisibility(visible: boolean | undefined): boolean {
|
||||||
|
const resolvedVisible = visible ?? DEFAULT_ENTITY_VISIBLE;
|
||||||
|
|
||||||
|
assertBoolean(resolvedVisible, "Entity visible");
|
||||||
|
return resolvedVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveAuthoredEntityEnabled(enabled: boolean | undefined): boolean {
|
||||||
|
const resolvedEnabled = enabled ?? DEFAULT_ENTITY_ENABLED;
|
||||||
|
|
||||||
|
assertBoolean(resolvedEnabled, "Entity enabled");
|
||||||
|
return resolvedEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
export function normalizeYawDegrees(yawDegrees: number): number {
|
export function normalizeYawDegrees(yawDegrees: number): number {
|
||||||
const normalizedYaw = yawDegrees % 360;
|
const normalizedYaw = yawDegrees % 360;
|
||||||
return normalizedYaw < 0 ? normalizedYaw + 360 : normalizedYaw;
|
return normalizedYaw < 0 ? normalizedYaw + 360 : normalizedYaw;
|
||||||
@@ -1078,7 +1097,7 @@ export function normalizeInteractablePrompt(prompt: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createPointLightEntity(
|
export function createPointLightEntity(
|
||||||
overrides: Partial<Pick<PointLightEntity, "id" | "name" | "position" | "colorHex" | "intensity" | "distance">> = {}
|
overrides: Partial<Pick<PointLightEntity, "id" | "name" | "visible" | "enabled" | "position" | "colorHex" | "intensity" | "distance">> = {}
|
||||||
): PointLightEntity {
|
): PointLightEntity {
|
||||||
const position = cloneVec3(overrides.position ?? DEFAULT_POINT_LIGHT_POSITION);
|
const position = cloneVec3(overrides.position ?? DEFAULT_POINT_LIGHT_POSITION);
|
||||||
const colorHex = overrides.colorHex ?? DEFAULT_POINT_LIGHT_COLOR_HEX;
|
const colorHex = overrides.colorHex ?? DEFAULT_POINT_LIGHT_COLOR_HEX;
|
||||||
@@ -1094,6 +1113,8 @@ export function createPointLightEntity(
|
|||||||
id: overrides.id ?? createOpaqueId("entity-point-light"),
|
id: overrides.id ?? createOpaqueId("entity-point-light"),
|
||||||
kind: "pointLight",
|
kind: "pointLight",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
colorHex,
|
colorHex,
|
||||||
intensity,
|
intensity,
|
||||||
@@ -1102,7 +1123,7 @@ export function createPointLightEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createSpotLightEntity(
|
export function createSpotLightEntity(
|
||||||
overrides: Partial<Pick<SpotLightEntity, "id" | "name" | "position" | "direction" | "colorHex" | "intensity" | "distance" | "angleDegrees">> = {}
|
overrides: Partial<Pick<SpotLightEntity, "id" | "name" | "visible" | "enabled" | "position" | "direction" | "colorHex" | "intensity" | "distance" | "angleDegrees">> = {}
|
||||||
): SpotLightEntity {
|
): SpotLightEntity {
|
||||||
const position = cloneVec3(overrides.position ?? DEFAULT_SPOT_LIGHT_POSITION);
|
const position = cloneVec3(overrides.position ?? DEFAULT_SPOT_LIGHT_POSITION);
|
||||||
const direction = cloneVec3(overrides.direction ?? DEFAULT_SPOT_LIGHT_DIRECTION);
|
const direction = cloneVec3(overrides.direction ?? DEFAULT_SPOT_LIGHT_DIRECTION);
|
||||||
@@ -1126,6 +1147,8 @@ export function createSpotLightEntity(
|
|||||||
id: overrides.id ?? createOpaqueId("entity-spot-light"),
|
id: overrides.id ?? createOpaqueId("entity-spot-light"),
|
||||||
kind: "spotLight",
|
kind: "spotLight",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
direction,
|
direction,
|
||||||
colorHex,
|
colorHex,
|
||||||
@@ -1139,7 +1162,7 @@ export function createPlayerStartEntity(
|
|||||||
overrides: Partial<
|
overrides: Partial<
|
||||||
Pick<
|
Pick<
|
||||||
PlayerStartEntity,
|
PlayerStartEntity,
|
||||||
"id" | "name" | "position" | "yawDegrees" | "navigationMode"
|
"id" | "name" | "visible" | "enabled" | "position" | "yawDegrees" | "navigationMode"
|
||||||
>
|
>
|
||||||
> & {
|
> & {
|
||||||
movementTemplate?: PlayerStartMovementTemplateOverrides;
|
movementTemplate?: PlayerStartMovementTemplateOverrides;
|
||||||
@@ -1173,6 +1196,8 @@ export function createPlayerStartEntity(
|
|||||||
id: overrides.id ?? createOpaqueId("entity-player-start"),
|
id: overrides.id ?? createOpaqueId("entity-player-start"),
|
||||||
kind: "playerStart",
|
kind: "playerStart",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
yawDegrees: normalizeYawDegrees(yawDegrees),
|
yawDegrees: normalizeYawDegrees(yawDegrees),
|
||||||
navigationMode,
|
navigationMode,
|
||||||
@@ -1183,7 +1208,7 @@ export function createPlayerStartEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createSceneEntryEntity(
|
export function createSceneEntryEntity(
|
||||||
overrides: Partial<Pick<SceneEntryEntity, "id" | "name" | "position" | "yawDegrees">> = {}
|
overrides: Partial<Pick<SceneEntryEntity, "id" | "name" | "visible" | "enabled" | "position" | "yawDegrees">> = {}
|
||||||
): SceneEntryEntity {
|
): SceneEntryEntity {
|
||||||
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
||||||
const yawDegrees = overrides.yawDegrees ?? DEFAULT_SCENE_ENTRY_YAW_DEGREES;
|
const yawDegrees = overrides.yawDegrees ?? DEFAULT_SCENE_ENTRY_YAW_DEGREES;
|
||||||
@@ -1198,6 +1223,8 @@ export function createSceneEntryEntity(
|
|||||||
id: overrides.id ?? createOpaqueId("entity-scene-entry"),
|
id: overrides.id ?? createOpaqueId("entity-scene-entry"),
|
||||||
kind: "sceneEntry",
|
kind: "sceneEntry",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
yawDegrees: normalizeYawDegrees(yawDegrees)
|
yawDegrees: normalizeYawDegrees(yawDegrees)
|
||||||
};
|
};
|
||||||
@@ -1207,7 +1234,7 @@ export function createSoundEmitterEntity(
|
|||||||
overrides: Partial<
|
overrides: Partial<
|
||||||
Pick<
|
Pick<
|
||||||
SoundEmitterEntity,
|
SoundEmitterEntity,
|
||||||
"id" | "name" | "position" | "audioAssetId" | "volume" | "refDistance" | "maxDistance" | "autoplay" | "loop"
|
"id" | "name" | "visible" | "enabled" | "position" | "audioAssetId" | "volume" | "refDistance" | "maxDistance" | "autoplay" | "loop"
|
||||||
>
|
>
|
||||||
> = {}
|
> = {}
|
||||||
): SoundEmitterEntity {
|
): SoundEmitterEntity {
|
||||||
@@ -1235,6 +1262,8 @@ export function createSoundEmitterEntity(
|
|||||||
id: overrides.id ?? createOpaqueId("entity-sound-emitter"),
|
id: overrides.id ?? createOpaqueId("entity-sound-emitter"),
|
||||||
kind: "soundEmitter",
|
kind: "soundEmitter",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
audioAssetId,
|
audioAssetId,
|
||||||
volume,
|
volume,
|
||||||
@@ -1246,7 +1275,7 @@ export function createSoundEmitterEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createTriggerVolumeEntity(
|
export function createTriggerVolumeEntity(
|
||||||
overrides: Partial<Pick<TriggerVolumeEntity, "id" | "name" | "position" | "size" | "triggerOnEnter" | "triggerOnExit">> = {}
|
overrides: Partial<Pick<TriggerVolumeEntity, "id" | "name" | "visible" | "enabled" | "position" | "size" | "triggerOnEnter" | "triggerOnExit">> = {}
|
||||||
): TriggerVolumeEntity {
|
): TriggerVolumeEntity {
|
||||||
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
||||||
const size = cloneVec3(overrides.size ?? DEFAULT_TRIGGER_VOLUME_SIZE);
|
const size = cloneVec3(overrides.size ?? DEFAULT_TRIGGER_VOLUME_SIZE);
|
||||||
@@ -1262,6 +1291,8 @@ export function createTriggerVolumeEntity(
|
|||||||
id: overrides.id ?? createOpaqueId("entity-trigger-volume"),
|
id: overrides.id ?? createOpaqueId("entity-trigger-volume"),
|
||||||
kind: "triggerVolume",
|
kind: "triggerVolume",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
size,
|
size,
|
||||||
triggerOnEnter,
|
triggerOnEnter,
|
||||||
@@ -1270,7 +1301,7 @@ export function createTriggerVolumeEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createTeleportTargetEntity(
|
export function createTeleportTargetEntity(
|
||||||
overrides: Partial<Pick<TeleportTargetEntity, "id" | "name" | "position" | "yawDegrees">> = {}
|
overrides: Partial<Pick<TeleportTargetEntity, "id" | "name" | "visible" | "enabled" | "position" | "yawDegrees">> = {}
|
||||||
): TeleportTargetEntity {
|
): TeleportTargetEntity {
|
||||||
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
||||||
const yawDegrees = overrides.yawDegrees ?? DEFAULT_TELEPORT_TARGET_YAW_DEGREES;
|
const yawDegrees = overrides.yawDegrees ?? DEFAULT_TELEPORT_TARGET_YAW_DEGREES;
|
||||||
@@ -1285,31 +1316,35 @@ export function createTeleportTargetEntity(
|
|||||||
id: overrides.id ?? createOpaqueId("entity-teleport-target"),
|
id: overrides.id ?? createOpaqueId("entity-teleport-target"),
|
||||||
kind: "teleportTarget",
|
kind: "teleportTarget",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
yawDegrees: normalizeYawDegrees(yawDegrees)
|
yawDegrees: normalizeYawDegrees(yawDegrees)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createInteractableEntity(
|
export function createInteractableEntity(
|
||||||
overrides: Partial<Pick<InteractableEntity, "id" | "name" | "position" | "radius" | "prompt" | "enabled">> = {}
|
overrides: Partial<Pick<InteractableEntity, "id" | "name" | "visible" | "enabled" | "position" | "radius" | "prompt" | "interactionEnabled">> = {}
|
||||||
): InteractableEntity {
|
): InteractableEntity {
|
||||||
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
const position = cloneVec3(overrides.position ?? DEFAULT_ENTITY_POSITION);
|
||||||
const radius = overrides.radius ?? DEFAULT_INTERACTABLE_RADIUS;
|
const radius = overrides.radius ?? DEFAULT_INTERACTABLE_RADIUS;
|
||||||
const prompt = normalizeInteractablePrompt(overrides.prompt ?? DEFAULT_INTERACTABLE_PROMPT);
|
const prompt = normalizeInteractablePrompt(overrides.prompt ?? DEFAULT_INTERACTABLE_PROMPT);
|
||||||
const enabled = overrides.enabled ?? true;
|
const interactionEnabled = overrides.interactionEnabled ?? true;
|
||||||
|
|
||||||
assertFiniteVec3(position, "Interactable position");
|
assertFiniteVec3(position, "Interactable position");
|
||||||
assertPositiveFiniteNumber(radius, "Interactable radius");
|
assertPositiveFiniteNumber(radius, "Interactable radius");
|
||||||
assertBoolean(enabled, "Interactable enabled");
|
assertBoolean(interactionEnabled, "Interactable interactionEnabled");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: overrides.id ?? createOpaqueId("entity-interactable"),
|
id: overrides.id ?? createOpaqueId("entity-interactable"),
|
||||||
kind: "interactable",
|
kind: "interactable",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
radius,
|
radius,
|
||||||
prompt,
|
prompt,
|
||||||
enabled
|
interactionEnabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1319,10 +1354,12 @@ export function createSceneExitEntity(
|
|||||||
SceneExitEntity,
|
SceneExitEntity,
|
||||||
| "id"
|
| "id"
|
||||||
| "name"
|
| "name"
|
||||||
|
| "visible"
|
||||||
|
| "enabled"
|
||||||
| "position"
|
| "position"
|
||||||
| "radius"
|
| "radius"
|
||||||
| "prompt"
|
| "prompt"
|
||||||
| "enabled"
|
| "interactionEnabled"
|
||||||
| "targetSceneId"
|
| "targetSceneId"
|
||||||
| "targetEntryEntityId"
|
| "targetEntryEntityId"
|
||||||
>
|
>
|
||||||
@@ -1333,7 +1370,7 @@ export function createSceneExitEntity(
|
|||||||
const prompt = normalizeInteractablePrompt(
|
const prompt = normalizeInteractablePrompt(
|
||||||
overrides.prompt ?? DEFAULT_SCENE_EXIT_PROMPT
|
overrides.prompt ?? DEFAULT_SCENE_EXIT_PROMPT
|
||||||
);
|
);
|
||||||
const enabled = overrides.enabled ?? true;
|
const interactionEnabled = overrides.interactionEnabled ?? true;
|
||||||
const targetSceneId = normalizeSceneReferenceId(
|
const targetSceneId = normalizeSceneReferenceId(
|
||||||
overrides.targetSceneId,
|
overrides.targetSceneId,
|
||||||
"Scene Exit target scene id"
|
"Scene Exit target scene id"
|
||||||
@@ -1345,16 +1382,18 @@ export function createSceneExitEntity(
|
|||||||
|
|
||||||
assertFiniteVec3(position, "Scene Exit position");
|
assertFiniteVec3(position, "Scene Exit position");
|
||||||
assertPositiveFiniteNumber(radius, "Scene Exit radius");
|
assertPositiveFiniteNumber(radius, "Scene Exit radius");
|
||||||
assertBoolean(enabled, "Scene Exit enabled");
|
assertBoolean(interactionEnabled, "Scene Exit interactionEnabled");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: overrides.id ?? createOpaqueId("entity-scene-exit"),
|
id: overrides.id ?? createOpaqueId("entity-scene-exit"),
|
||||||
kind: "sceneExit",
|
kind: "sceneExit",
|
||||||
name: normalizeEntityName(overrides.name),
|
name: normalizeEntityName(overrides.name),
|
||||||
|
visible: resolveAuthoredEntityVisibility(overrides.visible),
|
||||||
|
enabled: resolveAuthoredEntityEnabled(overrides.enabled),
|
||||||
position,
|
position,
|
||||||
radius,
|
radius,
|
||||||
prompt,
|
prompt,
|
||||||
enabled,
|
interactionEnabled,
|
||||||
targetSceneId,
|
targetSceneId,
|
||||||
targetEntryEntityId
|
targetEntryEntityId
|
||||||
};
|
};
|
||||||
@@ -1488,7 +1527,14 @@ export function cloneEntityRegistry(entities: Record<string, EntityInstance>): R
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function areEntityInstancesEqual(left: EntityInstance, right: EntityInstance): boolean {
|
export function areEntityInstancesEqual(left: EntityInstance, right: EntityInstance): boolean {
|
||||||
if (left.kind !== right.kind || left.id !== right.id || left.name !== right.name || !areVec3Equal(left.position, right.position)) {
|
if (
|
||||||
|
left.kind !== right.kind ||
|
||||||
|
left.id !== right.id ||
|
||||||
|
left.name !== right.name ||
|
||||||
|
left.visible !== right.visible ||
|
||||||
|
left.enabled !== right.enabled ||
|
||||||
|
!areVec3Equal(left.position, right.position)
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1560,14 +1606,18 @@ export function areEntityInstancesEqual(left: EntityInstance, right: EntityInsta
|
|||||||
}
|
}
|
||||||
case "interactable": {
|
case "interactable": {
|
||||||
const typedRight = right as InteractableEntity;
|
const typedRight = right as InteractableEntity;
|
||||||
return left.radius === typedRight.radius && left.prompt === typedRight.prompt && left.enabled === typedRight.enabled;
|
return (
|
||||||
|
left.radius === typedRight.radius &&
|
||||||
|
left.prompt === typedRight.prompt &&
|
||||||
|
left.interactionEnabled === typedRight.interactionEnabled
|
||||||
|
);
|
||||||
}
|
}
|
||||||
case "sceneExit": {
|
case "sceneExit": {
|
||||||
const typedRight = right as SceneExitEntity;
|
const typedRight = right as SceneExitEntity;
|
||||||
return (
|
return (
|
||||||
left.radius === typedRight.radius &&
|
left.radius === typedRight.radius &&
|
||||||
left.prompt === typedRight.prompt &&
|
left.prompt === typedRight.prompt &&
|
||||||
left.enabled === typedRight.enabled &&
|
left.interactionEnabled === typedRight.interactionEnabled &&
|
||||||
left.targetSceneId === typedRight.targetSceneId &&
|
left.targetSceneId === typedRight.targetSceneId &&
|
||||||
left.targetEntryEntityId === typedRight.targetEntryEntityId
|
left.targetEntryEntityId === typedRight.targetEntryEntityId
|
||||||
);
|
);
|
||||||
@@ -1605,6 +1655,10 @@ export function getPrimaryPlayerStartEntity(entities: Record<string, EntityInsta
|
|||||||
return getPlayerStartEntities(entities)[0] ?? null;
|
return getPlayerStartEntities(entities)[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPrimaryEnabledPlayerStartEntity(entities: Record<string, EntityInstance>): PlayerStartEntity | null {
|
||||||
|
return getPlayerStartEntities(entities).find((entity) => entity.enabled) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
export function getEntityKindLabel(kind: EntityKind): string {
|
export function getEntityKindLabel(kind: EntityKind): string {
|
||||||
return getEntityRegistryEntry(kind).label;
|
return getEntityRegistryEntry(kind).label;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user