Add set project scheduler command and update scene document to include scheduler
This commit is contained in:
49
src/commands/set-project-scheduler-command.ts
Normal file
49
src/commands/set-project-scheduler-command.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { createOpaqueId } from "../core/ids";
|
||||||
|
import {
|
||||||
|
cloneProjectScheduler,
|
||||||
|
type ProjectScheduler
|
||||||
|
} from "../scheduler/project-scheduler";
|
||||||
|
|
||||||
|
import type { EditorCommand } from "./command";
|
||||||
|
|
||||||
|
interface SetProjectSchedulerCommandOptions {
|
||||||
|
label: string;
|
||||||
|
scheduler: ProjectScheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSetProjectSchedulerCommand(
|
||||||
|
options: SetProjectSchedulerCommandOptions
|
||||||
|
): EditorCommand {
|
||||||
|
const nextScheduler = cloneProjectScheduler(options.scheduler);
|
||||||
|
let previousScheduler: ProjectScheduler | null = null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: createOpaqueId("command"),
|
||||||
|
label: options.label,
|
||||||
|
execute(context) {
|
||||||
|
const currentProjectDocument = context.getProjectDocument();
|
||||||
|
|
||||||
|
if (previousScheduler === null) {
|
||||||
|
previousScheduler = cloneProjectScheduler(
|
||||||
|
currentProjectDocument.scheduler
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.setProjectDocument({
|
||||||
|
...currentProjectDocument,
|
||||||
|
scheduler: cloneProjectScheduler(nextScheduler)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
undo(context) {
|
||||||
|
if (previousScheduler === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentProjectDocument = context.getProjectDocument();
|
||||||
|
context.setProjectDocument({
|
||||||
|
...currentProjectDocument,
|
||||||
|
scheduler: cloneProjectScheduler(previousScheduler)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -19,8 +19,13 @@ import {
|
|||||||
type ProjectTimeSettings
|
type ProjectTimeSettings
|
||||||
} from "./project-time-settings";
|
} from "./project-time-settings";
|
||||||
import { type ScenePath } from "./paths";
|
import { type ScenePath } from "./paths";
|
||||||
|
import {
|
||||||
|
createEmptyProjectScheduler,
|
||||||
|
type ProjectScheduler
|
||||||
|
} from "../scheduler/project-scheduler";
|
||||||
|
|
||||||
export const SCENE_DOCUMENT_VERSION = 45 as const;
|
export const SCENE_DOCUMENT_VERSION = 46 as const;
|
||||||
|
export const PROJECT_SCHEDULER_FOUNDATION_SCENE_DOCUMENT_VERSION = 46 as const;
|
||||||
export const CONTROL_SURFACE_FOUNDATION_SCENE_DOCUMENT_VERSION = 45 as const;
|
export const CONTROL_SURFACE_FOUNDATION_SCENE_DOCUMENT_VERSION = 45 as const;
|
||||||
export const NPC_PRESENCE_SCENE_DOCUMENT_VERSION = 44 as const;
|
export const NPC_PRESENCE_SCENE_DOCUMENT_VERSION = 44 as const;
|
||||||
export const PATH_FOUNDATION_SCENE_DOCUMENT_VERSION = 43 as const;
|
export const PATH_FOUNDATION_SCENE_DOCUMENT_VERSION = 43 as const;
|
||||||
@@ -136,6 +141,7 @@ export interface ProjectDocument {
|
|||||||
version: typeof SCENE_DOCUMENT_VERSION;
|
version: typeof SCENE_DOCUMENT_VERSION;
|
||||||
name: string;
|
name: string;
|
||||||
time: ProjectTimeSettings;
|
time: ProjectTimeSettings;
|
||||||
|
scheduler: ProjectScheduler;
|
||||||
activeSceneId: string;
|
activeSceneId: string;
|
||||||
scenes: Record<string, ProjectScene>;
|
scenes: Record<string, ProjectScene>;
|
||||||
materials: Record<string, MaterialDef>;
|
materials: Record<string, MaterialDef>;
|
||||||
@@ -147,6 +153,7 @@ export interface SceneDocument {
|
|||||||
version: typeof SCENE_DOCUMENT_VERSION;
|
version: typeof SCENE_DOCUMENT_VERSION;
|
||||||
name: string;
|
name: string;
|
||||||
time: ProjectTimeSettings;
|
time: ProjectTimeSettings;
|
||||||
|
scheduler: ProjectScheduler;
|
||||||
world: WorldSettings;
|
world: WorldSettings;
|
||||||
materials: Record<string, MaterialDef>;
|
materials: Record<string, MaterialDef>;
|
||||||
textures: Record<string, never>;
|
textures: Record<string, never>;
|
||||||
@@ -167,6 +174,7 @@ export function createEmptySceneDocument(
|
|||||||
version: SCENE_DOCUMENT_VERSION,
|
version: SCENE_DOCUMENT_VERSION,
|
||||||
name: overrides.name ?? "Untitled Scene",
|
name: overrides.name ?? "Untitled Scene",
|
||||||
time: overrides.time ?? createDefaultProjectTimeSettings(),
|
time: overrides.time ?? createDefaultProjectTimeSettings(),
|
||||||
|
scheduler: createEmptyProjectScheduler(),
|
||||||
world: overrides.world ?? createDefaultWorldSettings(),
|
world: overrides.world ?? createDefaultWorldSettings(),
|
||||||
materials: cloneMaterialRegistry(
|
materials: cloneMaterialRegistry(
|
||||||
overrides.materials ?? createStarterMaterialRegistry()
|
overrides.materials ?? createStarterMaterialRegistry()
|
||||||
@@ -211,7 +219,13 @@ export function createEmptyProjectDocument(
|
|||||||
overrides: Partial<
|
overrides: Partial<
|
||||||
Pick<
|
Pick<
|
||||||
ProjectDocument,
|
ProjectDocument,
|
||||||
"name" | "time" | "activeSceneId" | "materials" | "textures" | "assets"
|
| "name"
|
||||||
|
| "time"
|
||||||
|
| "scheduler"
|
||||||
|
| "activeSceneId"
|
||||||
|
| "materials"
|
||||||
|
| "textures"
|
||||||
|
| "assets"
|
||||||
>
|
>
|
||||||
> & {
|
> & {
|
||||||
sceneId?: string;
|
sceneId?: string;
|
||||||
@@ -230,6 +244,7 @@ export function createEmptyProjectDocument(
|
|||||||
version: SCENE_DOCUMENT_VERSION,
|
version: SCENE_DOCUMENT_VERSION,
|
||||||
name: overrides.name ?? DEFAULT_PROJECT_NAME,
|
name: overrides.name ?? DEFAULT_PROJECT_NAME,
|
||||||
time: overrides.time ?? createDefaultProjectTimeSettings(),
|
time: overrides.time ?? createDefaultProjectTimeSettings(),
|
||||||
|
scheduler: overrides.scheduler ?? createEmptyProjectScheduler(),
|
||||||
activeSceneId: initialScene.id,
|
activeSceneId: initialScene.id,
|
||||||
scenes: {
|
scenes: {
|
||||||
[initialScene.id]: initialScene
|
[initialScene.id]: initialScene
|
||||||
@@ -265,6 +280,7 @@ export function createSceneDocumentFromProject(
|
|||||||
version: projectDocument.version,
|
version: projectDocument.version,
|
||||||
name: scene.name,
|
name: scene.name,
|
||||||
time: projectDocument.time,
|
time: projectDocument.time,
|
||||||
|
scheduler: projectDocument.scheduler,
|
||||||
world: scene.world,
|
world: scene.world,
|
||||||
materials: projectDocument.materials,
|
materials: projectDocument.materials,
|
||||||
textures: projectDocument.textures,
|
textures: projectDocument.textures,
|
||||||
@@ -286,6 +302,7 @@ export function createProjectDocumentFromSceneDocument(
|
|||||||
version: SCENE_DOCUMENT_VERSION,
|
version: SCENE_DOCUMENT_VERSION,
|
||||||
name: projectName,
|
name: projectName,
|
||||||
time: sceneDocument.time,
|
time: sceneDocument.time,
|
||||||
|
scheduler: sceneDocument.scheduler,
|
||||||
activeSceneId: sceneId,
|
activeSceneId: sceneId,
|
||||||
scenes: {
|
scenes: {
|
||||||
[sceneId]: {
|
[sceneId]: {
|
||||||
@@ -318,6 +335,7 @@ export function applySceneDocumentToProject(
|
|||||||
...projectDocument,
|
...projectDocument,
|
||||||
version: SCENE_DOCUMENT_VERSION,
|
version: SCENE_DOCUMENT_VERSION,
|
||||||
time: sceneDocument.time,
|
time: sceneDocument.time,
|
||||||
|
scheduler: sceneDocument.scheduler,
|
||||||
materials: sceneDocument.materials,
|
materials: sceneDocument.materials,
|
||||||
textures: sceneDocument.textures,
|
textures: sceneDocument.textures,
|
||||||
assets: sceneDocument.assets,
|
assets: sceneDocument.assets,
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ export interface NpcActorUsage {
|
|||||||
entityName?: string;
|
entityName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProjectNpcActorRecord {
|
||||||
|
actorId: string;
|
||||||
|
label: string;
|
||||||
|
usages: NpcActorUsage[];
|
||||||
|
}
|
||||||
|
|
||||||
export function listNpcActorUsages(
|
export function listNpcActorUsages(
|
||||||
projectDocument: ProjectDocument,
|
projectDocument: ProjectDocument,
|
||||||
actorId: string
|
actorId: string
|
||||||
@@ -48,4 +54,52 @@ export function listNpcActorUsages(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return usages;
|
return usages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function listProjectNpcActors(
|
||||||
|
projectDocument: ProjectDocument
|
||||||
|
): ProjectNpcActorRecord[] {
|
||||||
|
const actorUsages = new Map<string, NpcActorUsage[]>();
|
||||||
|
|
||||||
|
for (const scene of Object.values(projectDocument.scenes)) {
|
||||||
|
for (const entity of getEntityInstances(scene.entities)) {
|
||||||
|
if (entity.kind !== "npc") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usages = actorUsages.get(entity.actorId) ?? [];
|
||||||
|
usages.push({
|
||||||
|
actorId: entity.actorId,
|
||||||
|
sceneId: scene.id,
|
||||||
|
sceneName: scene.name,
|
||||||
|
entityId: entity.id,
|
||||||
|
entityName: entity.name
|
||||||
|
});
|
||||||
|
actorUsages.set(entity.actorId, usages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...actorUsages.entries()]
|
||||||
|
.map(([actorId, usages]) => {
|
||||||
|
usages.sort((left, right) => {
|
||||||
|
return (
|
||||||
|
left.sceneName.localeCompare(right.sceneName) ||
|
||||||
|
left.sceneId.localeCompare(right.sceneId) ||
|
||||||
|
(left.entityName ?? "").localeCompare(right.entityName ?? "") ||
|
||||||
|
left.entityId.localeCompare(right.entityId)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
actorId,
|
||||||
|
label: usages[0]?.entityName?.trim() || actorId,
|
||||||
|
usages
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((left, right) => {
|
||||||
|
return (
|
||||||
|
left.label.localeCompare(right.label) ||
|
||||||
|
left.actorId.localeCompare(right.actorId)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user