Add type checks and default creation functions for cone, torus, and dialogue-related entities
This commit is contained in:
@@ -821,6 +821,36 @@ export function isRadialPrismVertexId(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isConeFaceId(value: unknown): value is ConeFaceId {
|
||||||
|
return value === "bottom" || (typeof value === "string" && value.startsWith("side-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isConeEdgeId(value: unknown): value is ConeEdgeId {
|
||||||
|
return (
|
||||||
|
typeof value === "string" &&
|
||||||
|
(value.startsWith("bottom-") || value.startsWith("side-"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isConeVertexId(value: unknown): value is ConeVertexId {
|
||||||
|
return value === "apex" || (typeof value === "string" && value.startsWith("bottom-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTorusFaceId(value: unknown): value is TorusFaceId {
|
||||||
|
return typeof value === "string" && value.startsWith("face-");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTorusEdgeId(value: unknown): value is TorusEdgeId {
|
||||||
|
return (
|
||||||
|
typeof value === "string" &&
|
||||||
|
(value.startsWith("major-") || value.startsWith("tube-"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTorusVertexId(value: unknown): value is TorusVertexId {
|
||||||
|
return typeof value === "string" && value.startsWith("vertex-");
|
||||||
|
}
|
||||||
|
|
||||||
export function isFaceUvRotationQuarterTurns(value: unknown): value is FaceUvRotationQuarterTurns {
|
export function isFaceUvRotationQuarterTurns(value: unknown): value is FaceUvRotationQuarterTurns {
|
||||||
return typeof value === "number" && FACE_UV_ROTATION_QUARTER_TURNS.includes(value as FaceUvRotationQuarterTurns);
|
return typeof value === "number" && FACE_UV_ROTATION_QUARTER_TURNS.includes(value as FaceUvRotationQuarterTurns);
|
||||||
}
|
}
|
||||||
@@ -898,11 +928,26 @@ export function createDefaultWedgeBrushFaces(): WedgeBrushFaces {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createDefaultRadialPrismBrushFaces(
|
export function createDefaultRadialPrismBrushFaces(
|
||||||
sideCount = 12
|
sideCount = DEFAULT_RADIAL_PRISM_SIDE_COUNT
|
||||||
): Record<RadialPrismFaceId, BrushFace> {
|
): Record<RadialPrismFaceId, BrushFace> {
|
||||||
return createDefaultBrushFaces(getRadialPrismFaceIds(sideCount));
|
return createDefaultBrushFaces(getRadialPrismFaceIds(sideCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createDefaultConeBrushFaces(
|
||||||
|
sideCount = DEFAULT_CONE_SIDE_COUNT
|
||||||
|
): Record<ConeFaceId, BrushFace> {
|
||||||
|
return createDefaultBrushFaces(getConeFaceIds(sideCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createDefaultTorusBrushFaces(
|
||||||
|
majorSegmentCount = DEFAULT_TORUS_MAJOR_SEGMENT_COUNT,
|
||||||
|
tubeSegmentCount = DEFAULT_TORUS_TUBE_SEGMENT_COUNT
|
||||||
|
): Record<TorusFaceId, BrushFace> {
|
||||||
|
return createDefaultBrushFaces(
|
||||||
|
getTorusFaceIds(majorSegmentCount, tubeSegmentCount)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function createDefaultBoxBrushWaterSettings(): BoxBrushWaterSettings {
|
export function createDefaultBoxBrushWaterSettings(): BoxBrushWaterSettings {
|
||||||
return {
|
return {
|
||||||
colorHex: DEFAULT_BOX_BRUSH_WATER_SETTINGS.colorHex,
|
colorHex: DEFAULT_BOX_BRUSH_WATER_SETTINGS.colorHex,
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { createOpaqueId } from "../core/ids";
|
import { createOpaqueId } from "../core/ids";
|
||||||
import type { Vec3 } from "../core/vector";
|
import type { Vec3 } from "../core/vector";
|
||||||
|
import {
|
||||||
|
areProjectDialoguesEqual,
|
||||||
|
cloneProjectDialogue,
|
||||||
|
type ProjectDialogue
|
||||||
|
} from "../dialogues/project-dialogues";
|
||||||
import { normalizeTimeOfDayHours } from "../document/project-time-settings";
|
import { normalizeTimeOfDayHours } from "../document/project-time-settings";
|
||||||
import { isHexColorString } from "../document/world-settings";
|
import { isHexColorString } from "../document/world-settings";
|
||||||
|
|
||||||
@@ -74,7 +79,8 @@ export interface NpcEntity extends PositionedEntity {
|
|||||||
presence: NpcPresence;
|
presence: NpcPresence;
|
||||||
yawDegrees: number;
|
yawDegrees: number;
|
||||||
modelAssetId: string | null;
|
modelAssetId: string | null;
|
||||||
dialogueId: string | null;
|
dialogues: ProjectDialogue[];
|
||||||
|
defaultDialogueId: string | null;
|
||||||
collider: NpcColliderSettings;
|
collider: NpcColliderSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1298,6 +1304,34 @@ function normalizeNpcDialogueId(
|
|||||||
return normalizedDialogueId.length === 0 ? null : normalizedDialogueId;
|
return normalizedDialogueId.length === 0 ? null : normalizedDialogueId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeNpcDialogues(
|
||||||
|
dialogues: ProjectDialogue[] | undefined
|
||||||
|
): ProjectDialogue[] {
|
||||||
|
if (dialogues === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialogues.map(cloneProjectDialogue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeNpcDefaultDialogueId(
|
||||||
|
defaultDialogueId: string | null | undefined,
|
||||||
|
dialogues: readonly ProjectDialogue[],
|
||||||
|
legacyDialogueId?: string | null | undefined
|
||||||
|
): string | null {
|
||||||
|
const normalizedDefaultDialogueId = normalizeNpcDialogueId(
|
||||||
|
defaultDialogueId ?? legacyDialogueId ?? null
|
||||||
|
);
|
||||||
|
|
||||||
|
if (normalizedDefaultDialogueId === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialogues.some((dialogue) => dialogue.id === normalizedDefaultDialogueId)
|
||||||
|
? normalizedDefaultDialogueId
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
export function normalizeInteractablePrompt(prompt: string): string {
|
export function normalizeInteractablePrompt(prompt: string): string {
|
||||||
const normalizedPrompt = prompt.trim();
|
const normalizedPrompt = prompt.trim();
|
||||||
|
|
||||||
@@ -1455,9 +1489,11 @@ export function createNpcEntity(
|
|||||||
| "presence"
|
| "presence"
|
||||||
| "yawDegrees"
|
| "yawDegrees"
|
||||||
| "modelAssetId"
|
| "modelAssetId"
|
||||||
| "dialogueId"
|
| "dialogues"
|
||||||
|
| "defaultDialogueId"
|
||||||
>
|
>
|
||||||
> & {
|
> & {
|
||||||
|
dialogueId?: string | null;
|
||||||
collider?: Partial<NpcColliderSettings>;
|
collider?: Partial<NpcColliderSettings>;
|
||||||
} = {}
|
} = {}
|
||||||
): NpcEntity {
|
): NpcEntity {
|
||||||
@@ -1468,8 +1504,11 @@ export function createNpcEntity(
|
|||||||
const modelAssetId = normalizeNpcModelAssetId(
|
const modelAssetId = normalizeNpcModelAssetId(
|
||||||
overrides.modelAssetId ?? DEFAULT_NPC_MODEL_ASSET_ID
|
overrides.modelAssetId ?? DEFAULT_NPC_MODEL_ASSET_ID
|
||||||
);
|
);
|
||||||
const dialogueId = normalizeNpcDialogueId(
|
const dialogues = normalizeNpcDialogues(overrides.dialogues);
|
||||||
overrides.dialogueId ?? DEFAULT_NPC_DIALOGUE_ID
|
const defaultDialogueId = normalizeNpcDefaultDialogueId(
|
||||||
|
overrides.defaultDialogueId ?? DEFAULT_NPC_DIALOGUE_ID,
|
||||||
|
dialogues,
|
||||||
|
overrides.dialogueId
|
||||||
);
|
);
|
||||||
const collider = createNpcColliderSettings(overrides.collider);
|
const collider = createNpcColliderSettings(overrides.collider);
|
||||||
|
|
||||||
@@ -1490,7 +1529,8 @@ export function createNpcEntity(
|
|||||||
presence,
|
presence,
|
||||||
yawDegrees: normalizeYawDegrees(yawDegrees),
|
yawDegrees: normalizeYawDegrees(yawDegrees),
|
||||||
modelAssetId,
|
modelAssetId,
|
||||||
dialogueId,
|
dialogues,
|
||||||
|
defaultDialogueId,
|
||||||
collider
|
collider
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1802,7 +1842,11 @@ export function areEntityInstancesEqual(left: EntityInstance, right: EntityInsta
|
|||||||
areNpcPresencesEqual(left.presence, typedRight.presence) &&
|
areNpcPresencesEqual(left.presence, typedRight.presence) &&
|
||||||
left.yawDegrees === typedRight.yawDegrees &&
|
left.yawDegrees === typedRight.yawDegrees &&
|
||||||
left.modelAssetId === typedRight.modelAssetId &&
|
left.modelAssetId === typedRight.modelAssetId &&
|
||||||
left.dialogueId === typedRight.dialogueId &&
|
left.defaultDialogueId === typedRight.defaultDialogueId &&
|
||||||
|
left.dialogues.length === typedRight.dialogues.length &&
|
||||||
|
left.dialogues.every((dialogue, index) =>
|
||||||
|
areProjectDialoguesEqual(dialogue, typedRight.dialogues[index]!)
|
||||||
|
) &&
|
||||||
left.collider.mode === typedRight.collider.mode &&
|
left.collider.mode === typedRight.collider.mode &&
|
||||||
left.collider.eyeHeight === typedRight.collider.eyeHeight &&
|
left.collider.eyeHeight === typedRight.collider.eyeHeight &&
|
||||||
left.collider.capsuleRadius === typedRight.collider.capsuleRadius &&
|
left.collider.capsuleRadius === typedRight.collider.capsuleRadius &&
|
||||||
|
|||||||
Reference in New Issue
Block a user