From 326616e2c5f57a72eed2af5589ab01484fe4d34f Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Thu, 23 Apr 2026 02:39:52 +0200 Subject: [PATCH] auto-git: [change] tests/unit/runtime-host.test.ts --- tests/unit/runtime-host.test.ts | 126 ++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/tests/unit/runtime-host.test.ts b/tests/unit/runtime-host.test.ts index 69dbb4d9..82fe2b63 100644 --- a/tests/unit/runtime-host.test.ts +++ b/tests/unit/runtime-host.test.ts @@ -3,7 +3,10 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { createActiveSceneControlTargetRef, + createActivateCameraRigOverrideControlEffect, createActorControlTargetRef, + createCameraRigControlTargetRef, + createClearCameraRigOverrideControlEffect, createFollowActorPathControlEffect, createLightControlTargetRef, createModelInstanceControlTargetRef, @@ -366,6 +369,129 @@ describe("RuntimeHost", () => { host.dispose(); }); + it("routes camera rig control effects through the runtime override path", () => { + 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 defaultRig = createCameraRigEntity({ + id: "entity-camera-rig-default-control", + position: { + x: 0, + y: 3, + z: 6 + }, + defaultActive: true, + target: createCameraRigWorldPointTargetRef({ + x: 0, + y: 1.5, + z: 0 + }) + }); + const overrideRig = createCameraRigEntity({ + id: "entity-camera-rig-override-control", + position: { + x: 10, + y: 5, + z: -4 + }, + defaultActive: false, + target: createCameraRigWorldPointTargetRef({ + x: 1, + y: 2, + z: 0 + }) + }); + const triggerVolume = createTriggerVolumeEntity({ + id: "entity-trigger-camera-control" + }); + const runtimeScene = buildRuntimeSceneFromDocument({ + ...createEmptySceneDocument({ name: "Camera Control Runtime Scene" }), + entities: { + [defaultRig.id]: defaultRig, + [overrideRig.id]: overrideRig, + [triggerVolume.id]: triggerVolume + } + }); + const host = new RuntimeHost({ + enableRendering: false + }); + host.loadScene(runtimeScene); + + const activateEffect = createActivateCameraRigOverrideControlEffect({ + target: createCameraRigControlTargetRef(overrideRig.id) + }); + const clearEffect = createClearCameraRigOverrideControlEffect({ + target: createCameraRigControlTargetRef(overrideRig.id) + }); + const activateLink = createControlInteractionLink({ + id: "link-camera-activate", + sourceEntityId: triggerVolume.id, + effect: activateEffect + }); + const clearLink = createControlInteractionLink({ + id: "link-camera-clear", + sourceEntityId: triggerVolume.id, + effect: clearEffect + }); + const hostInternals = host as unknown as { + sceneReady: boolean; + activeCameraRigOverrideEntityId: string | null; + activeRuntimeCameraRig: { entityId: string } | null; + applyActiveCameraRig(dt: number): { entityId: string } | null; + createInteractionDispatcher(): { + dispatchControlEffect( + effect: ControlEffect, + link: InteractionLink + ): void; + }; + }; + const dispatcher = hostInternals.createInteractionDispatcher(); + + hostInternals.sceneReady = true; + expect(hostInternals.applyActiveCameraRig(0)?.entityId).toBe(defaultRig.id); + + dispatcher.dispatchControlEffect(activateEffect, activateLink); + + expect(hostInternals.activeCameraRigOverrideEntityId).toBe(overrideRig.id); + expect(hostInternals.applyActiveCameraRig(0)?.entityId).toBe(overrideRig.id); + expect(runtimeScene.control.resolved.discrete).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: "cameraRigOverride", + entityId: overrideRig.id, + source: { + kind: "interactionLink", + linkId: activateLink.id + } + }) + ]) + ); + + dispatcher.dispatchControlEffect(clearEffect, clearLink); + + expect(hostInternals.activeCameraRigOverrideEntityId).toBeNull(); + expect(hostInternals.applyActiveCameraRig(0)?.entityId).toBe(defaultRig.id); + expect(runtimeScene.control.resolved.discrete).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: "cameraRigOverride", + entityId: null, + source: { + kind: "interactionLink", + linkId: clearLink.id + } + }) + ]) + ); + + host.dispose(); + }); + it("resolves rail camera rigs from the target's nearest path progress and preserves look-around", () => { vi.spyOn(console, "warn").mockImplementation(() => undefined); vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({