Refactor sequence step handling to use clips

This commit is contained in:
2026-04-15 00:18:24 +02:00
parent 10e0c52fee
commit f13188bf32
4 changed files with 39 additions and 32 deletions

View File

@@ -197,7 +197,7 @@ import {
createProjectSequence,
type ProjectSequenceLibrary
} from "../sequencer/project-sequences";
import type { SequenceStep } from "../sequencer/project-sequence-steps";
import type { SequenceClip } from "../sequencer/project-sequence-steps";
import {
createScenePath,
createScenePathPoint,
@@ -3517,7 +3517,7 @@ function readProjectDialogueLibrary(
};
}
function readProjectSequenceStep(value: unknown, label: string): SequenceStep {
function readProjectSequenceClip(value: unknown, label: string): SequenceClip {
if (!isRecord(value)) {
throw new Error(`${label} must be an object.`);
}
@@ -3574,7 +3574,7 @@ function readProjectSequenceStep(value: unknown, label: string): SequenceStep {
: expectBoolean(value.visible, `${label}.visible`)
};
default:
throw new Error(`${label}.type must be a supported sequence step.`);
throw new Error(`${label}.type must be a supported sequence clip.`);
}
}
@@ -3606,10 +3606,14 @@ function readProjectSequenceLibrary(
throw new Error(`${label}.sequences.${sequenceKey} must be an object.`);
}
const stepsValue = sequenceValue.steps;
const clipsValue = Array.isArray(sequenceValue.clips)
? sequenceValue.clips
: sequenceValue.steps;
if (!Array.isArray(stepsValue)) {
throw new Error(`${label}.sequences.${sequenceKey}.steps must be an array.`);
if (!Array.isArray(clipsValue)) {
throw new Error(
`${label}.sequences.${sequenceKey}.clips must be an array.`
);
}
sequences[sequenceKey] = createProjectSequence({
@@ -3618,10 +3622,10 @@ function readProjectSequenceLibrary(
sequenceValue.title,
`${label}.sequences.${sequenceKey}.title`
),
steps: stepsValue.map((stepValue, stepIndex) =>
readProjectSequenceStep(
stepValue,
`${label}.sequences.${sequenceKey}.steps.${stepIndex}`
clips: clipsValue.map((clipValue, clipIndex) =>
readProjectSequenceClip(
clipValue,
`${label}.sequences.${sequenceKey}.clips.${clipIndex}`
)
)
});

View File

@@ -4805,40 +4805,40 @@ function validateProjectSequence(
);
}
if (sequence.steps.length === 0) {
if (sequence.clips.length === 0) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-project-sequence-steps-empty",
"Project sequences must contain at least one step.",
`${path}.steps`
"invalid-project-sequence-clips-empty",
"Project sequences must contain at least one clip.",
`${path}.clips`
)
);
return;
}
for (const [stepIndex, step] of sequence.steps.entries()) {
const stepPath = `${path}.steps.${stepIndex}`;
for (const [clipIndex, clip] of sequence.clips.entries()) {
const clipPath = `${path}.clips.${clipIndex}`;
switch (step.type) {
switch (clip.type) {
case "controlEffect":
validateProjectSchedulerEffect(
step.effect,
`${stepPath}.effect`,
clip.effect,
`${clipPath}.effect`,
context,
diagnostics
);
break;
case "startDialogue":
if (
projectResources.dialogues.dialogues[step.dialogueId] === undefined
projectResources.dialogues.dialogues[clip.dialogueId] === undefined
) {
diagnostics.push(
createDiagnostic(
"error",
"missing-sequence-dialogue-resource",
`Dialogue ${step.dialogueId} does not exist in the project dialogue library.`,
`${stepPath}.dialogueId`
`Dialogue ${clip.dialogueId} does not exist in the project dialogue library.`,
`${clipPath}.dialogueId`
)
);
}

View File

@@ -32,7 +32,8 @@ import {
type ProjectSequenceLibrary
} from "../sequencer/project-sequences";
export const SCENE_DOCUMENT_VERSION = 53 as const;
export const SCENE_DOCUMENT_VERSION = 54 as const;
export const PROJECT_SEQUENCE_CLIPS_SCENE_DOCUMENT_VERSION = 54 as const;
export const PROJECT_SEQUENCE_LIBRARY_SCENE_DOCUMENT_VERSION = 53 as const;
export const PLAYER_START_PAUSE_BINDINGS_SCENE_DOCUMENT_VERSION = 52 as const;
export const NPC_DIALOGUE_REFERENCE_SCENE_DOCUMENT_VERSION = 51 as const;

View File

@@ -1,14 +1,15 @@
import { createOpaqueId } from "../core/ids";
import {
cloneSequenceStep,
cloneSequenceClip,
type SequenceClip,
type SequenceStep
} from "./project-sequence-steps";
export interface ProjectSequence {
id: string;
title: string;
steps: SequenceStep[];
clips: SequenceClip[];
}
export interface ProjectSequenceLibrary {
@@ -33,13 +34,14 @@ export function createEmptyProjectSequenceLibrary(): ProjectSequenceLibrary {
export function createProjectSequence(
overrides: Partial<Pick<ProjectSequence, "id" | "title">> & {
clips?: SequenceClip[];
steps?: SequenceStep[];
} = {}
): ProjectSequence {
return {
id: overrides.id ?? createOpaqueId("sequence"),
title: normalizeProjectSequenceTitle(overrides.title ?? "Sequence"),
steps: overrides.steps?.map(cloneSequenceStep) ?? []
clips: (overrides.clips ?? overrides.steps)?.map(cloneSequenceClip) ?? []
};
}
@@ -49,7 +51,7 @@ export function cloneProjectSequence(
return {
id: sequence.id,
title: sequence.title,
steps: sequence.steps.map(cloneSequenceStep)
clips: sequence.clips.map(cloneSequenceClip)
};
}
@@ -73,19 +75,19 @@ export function areProjectSequencesEqual(
if (
left.id !== right.id ||
left.title !== right.title ||
left.steps.length !== right.steps.length
left.clips.length !== right.clips.length
) {
return false;
}
return left.steps.every((step, index) => {
const rightStep = right.steps[index];
return left.clips.every((clip, index) => {
const rightClip = right.clips[index];
if (rightStep === undefined) {
if (rightClip === undefined) {
return false;
}
return JSON.stringify(step) === JSON.stringify(rightStep);
return JSON.stringify(clip) === JSON.stringify(rightClip);
});
}