From 2dd2050e1553aa973682e1ad4b10459caf489dcb Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Tue, 14 Apr 2026 03:01:46 +0200 Subject: [PATCH] Update applyRuntimeProjectScheduleToControlState to handle baselineResolved and add helper functions --- .../runtime-project-scheduler.ts | 156 +++++++++++++++++- 1 file changed, 150 insertions(+), 6 deletions(-) diff --git a/src/runtime-three/runtime-project-scheduler.ts b/src/runtime-three/runtime-project-scheduler.ts index e5ca8121..2636fb96 100644 --- a/src/runtime-three/runtime-project-scheduler.ts +++ b/src/runtime-three/runtime-project-scheduler.ts @@ -210,14 +210,40 @@ function resolveRuntimeScheduledControlRoutines(options: { export function applyRuntimeProjectScheduleToControlState( resolved: RuntimeResolvedControlState, - schedule: RuntimeResolvedProjectScheduleState + schedule: RuntimeResolvedProjectScheduleState, + baselineResolved: RuntimeResolvedControlState = resolved ): RuntimeResolvedControlState { - let nextResolved = cloneRuntimeResolvedControlState(resolved); + let nextResolved = cloneRuntimeResolvedControlState(baselineResolved); + + for (const state of resolved.discrete) { + if ( + state.source.kind === "default" || + state.source.kind === "scheduler" || + state.type === "actorPresence" + ) { + continue; + } + + nextResolved = applyControlEffectToResolvedState( + nextResolved, + cloneDiscreteStateAsEffect(state), + state.source + ); + } + + for (const channel of resolved.channels) { + if ( + channel.source.kind === "default" || + channel.source.kind === "scheduler" + ) { + continue; + } + + nextResolved = applyChannelValueAsEffect(nextResolved, channel); + } + nextResolved.discrete = nextResolved.discrete.filter( - (state) => state.type !== "actorPresence" && state.source.kind !== "scheduler" - ); - nextResolved.channels = nextResolved.channels.filter( - (channel) => channel.source.kind !== "scheduler" + (state) => state.type !== "actorPresence" ); for (const actorState of schedule.actors) { @@ -246,3 +272,121 @@ export function applyRuntimeProjectScheduleToControlState( return nextResolved; } + +function cloneDiscreteStateAsEffect( + state: RuntimeResolvedControlState["discrete"][number] +): ControlEffect { + switch (state.type) { + case "actorPresence": + return createSetActorPresenceControlEffect({ + target: state.target, + active: state.value + }); + case "modelVisibility": + return { + type: "setModelInstanceVisible", + target: state.target, + visible: state.value + }; + case "soundPlayback": + return state.value + ? { + type: "playSound", + target: state.target + } + : { + type: "stopSound", + target: state.target + }; + case "modelAnimationPlayback": + return state.clipName === null + ? { + type: "stopModelAnimation", + target: state.target + } + : { + type: "playModelAnimation", + target: state.target, + clipName: state.clipName, + loop: state.loop + }; + case "lightEnabled": + return { + type: "setLightEnabled", + target: state.target, + enabled: state.value + }; + case "lightColor": + return { + type: "setLightColor", + target: state.target, + colorHex: state.value + }; + case "interactionEnabled": + return { + type: "setInteractionEnabled", + target: state.target, + enabled: state.value + }; + case "ambientLightColor": + return { + type: "setAmbientLightColor", + target: state.target, + colorHex: state.value + }; + case "sunLightColor": + return { + type: "setSunLightColor", + target: state.target, + colorHex: state.value + }; + } +} + +function applyChannelValueAsEffect( + resolved: RuntimeResolvedControlState, + channel: RuntimeResolvedControlState["channels"][number] +): RuntimeResolvedControlState { + switch (channel.type) { + case "lightIntensity": + return applyControlEffectToResolvedState( + resolved, + { + type: "setLightIntensity", + target: channel.descriptor.target, + intensity: channel.value + }, + channel.source + ); + case "soundVolume": + return applyControlEffectToResolvedState( + resolved, + { + type: "setSoundVolume", + target: channel.descriptor.target, + volume: channel.value + }, + channel.source + ); + case "ambientLightIntensity": + return applyControlEffectToResolvedState( + resolved, + { + type: "setAmbientLightIntensity", + target: channel.descriptor.target, + intensity: channel.value + }, + channel.source + ); + case "sunLightIntensity": + return applyControlEffectToResolvedState( + resolved, + { + type: "setSunLightIntensity", + target: channel.descriptor.target, + intensity: channel.value + }, + channel.source + ); + } +}