Test NPC activity resolution from project scheduler

This commit is contained in:
2026-04-14 02:06:39 +02:00
parent 7ec0328eac
commit 6c4975c928

View File

@@ -2,17 +2,23 @@ import { waitFor } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
createActorControlTargetRef,
createLightControlTargetRef,
createSetActorPresenceControlEffect,
type ControlEffect,
createSetLightEnabledControlEffect,
createSetLightIntensityControlEffect
} from "../../src/controls/control-surface";
import { createEmptySceneDocument } from "../../src/document/scene-document";
import { createPointLightEntity } from "../../src/entities/entity-instances";
import {
createNpcEntity,
createPointLightEntity
} from "../../src/entities/entity-instances";
import {
createControlInteractionLink,
type InteractionLink
} from "../../src/interactions/interaction-links";
import { createProjectScheduleRoutine } from "../../src/scheduler/project-scheduler";
import { RapierCollisionWorld } from "../../src/runtime-three/rapier-collision-world";
import {
RuntimeHost,
@@ -195,4 +201,86 @@ describe("RuntimeHost", () => {
host.dispose();
});
it("re-resolves NPC activity from the project scheduler when the runtime clock advances", () => {
vi.spyOn(console, "warn").mockImplementation(() => undefined);
vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({
dispose: vi.fn(),
resolveThirdPersonCameraCollision: vi.fn(
(_pivot, desiredCameraPosition) => desiredCameraPosition
)
} as unknown as RapierCollisionWorld);
const npc = createNpcEntity({
id: "entity-npc-night-guard",
actorId: "actor-night-guard"
});
const document = createEmptySceneDocument();
document.entities[npc.id] = npc;
document.scheduler.routines["routine-night-guard"] =
createProjectScheduleRoutine({
id: "routine-night-guard",
title: "Night Shift",
target: createActorControlTargetRef(npc.actorId),
startHour: 20,
endHour: 4,
effect: createSetActorPresenceControlEffect({
target: createActorControlTargetRef(npc.actorId),
active: true
})
});
const runtimeScene = buildRuntimeSceneFromDocument(document);
const host = new RuntimeHost({
enableRendering: false
});
host.loadScene(runtimeScene);
const hostInternals = host as unknown as {
currentClockState: {
timeOfDayHours: number;
dayCount: number;
dayLengthMinutes: number;
} | null;
sceneReady: boolean;
runtimeScene: typeof runtimeScene | null;
syncRuntimeNpcScheduleToCurrentClock(): void;
};
expect(runtimeScene.entities.npcs).toEqual([]);
hostInternals.sceneReady = true;
hostInternals.currentClockState = {
timeOfDayHours: 21,
dayCount: 0,
dayLengthMinutes: 24
};
hostInternals.syncRuntimeNpcScheduleToCurrentClock();
expect(hostInternals.runtimeScene?.entities.npcs).toEqual([
expect.objectContaining({
entityId: npc.id,
actorId: npc.actorId,
activeRoutineTitle: "Night Shift"
})
]);
hostInternals.currentClockState = {
timeOfDayHours: 6,
dayCount: 1,
dayLengthMinutes: 24
};
hostInternals.syncRuntimeNpcScheduleToCurrentClock();
expect(hostInternals.runtimeScene?.entities.npcs).toEqual([]);
expect(hostInternals.runtimeScene?.npcDefinitions[0]).toEqual(
expect.objectContaining({
entityId: npc.id,
active: false,
activeRoutineTitle: null
})
);
host.dispose();
});
});