From 2a60efc5aba7477b4ed26239d92468b924e767c5 Mon Sep 17 00:00:00 2001 From: lee-at-zoo-corp Date: Tue, 18 Mar 2025 20:06:36 -0400 Subject: [PATCH] Move engineStreamMachine as a global actor; tons of more work --- src/App.tsx | 34 +- src/clientSideScene/CameraControls.ts | 5 +- src/components/EngineStream.tsx | 44 +- src/components/ModelStateIndicator.tsx | 3 +- src/components/ModelingMachineProvider.tsx | 1 - src/components/Stream.tsx | 414 ------------------ src/lang/std/engineConnection.ts | 6 +- src/lib/selections.ts | 5 +- src/machines/appMachine.ts | 12 +- .../engineStreamMachine.ts} | 103 ++--- src/machines/machineConstants.ts | 1 + 11 files changed, 92 insertions(+), 536 deletions(-) delete mode 100644 src/components/Stream.tsx rename src/{hooks/useEngineStreamContext.ts => machines/engineStreamMachine.ts} (75%) diff --git a/src/App.tsx b/src/App.tsx index 8e1f3edfc..6966db7d3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -41,7 +41,6 @@ import { onboardingPaths } from '@src/routes/Onboarding/paths' maybeWriteToDisk() .then(() => {}) .catch(() => {}) -import EngineStreamContext from 'hooks/useEngineStreamContext' import { EngineStream } from 'components/EngineStream' export function App() { @@ -67,8 +66,6 @@ export function App() { const ref = useRef(null) // Stream related refs and data - const videoRef = useRef(null) - const canvasRef = useRef(null) let [searchParams] = useSearchParams() const pool = searchParams.get('pool') @@ -86,7 +83,7 @@ export function App() { useHotKeyListener() const settings = useSettings() - const token = useToken() + const authToken = useToken() const coreDumpManager = useMemo( () => @@ -94,7 +91,7 @@ export function App() { engineCommandManager, codeManager, rustContext, - token + authToken ), [] ) @@ -157,26 +154,13 @@ export function App() { /> - - - {/* */} - - - - - - + + {/* */} + + + + + ) } diff --git a/src/clientSideScene/CameraControls.ts b/src/clientSideScene/CameraControls.ts index 63dfbc436..761dc4772 100644 --- a/src/clientSideScene/CameraControls.ts +++ b/src/clientSideScene/CameraControls.ts @@ -480,12 +480,13 @@ export class CameraControls { if (this.syncDirection === 'engineToClient') { const newCmdId = uuidv4() + const { videoRef } = engineStreamActor.getSnapshot().context // Nonsense to do anything until the video stream is established. - if (!this.engineCommandManager.elVideo) return + if (!videoRef.current) return const { x, y } = getNormalisedCoordinates( event, - this.engineCommandManager.elVideo, + videoRef.current, this.engineCommandManager.streamDimensions ) this.throttledEngCmd({ diff --git a/src/components/EngineStream.tsx b/src/components/EngineStream.tsx index 294622b69..46b69c0c9 100644 --- a/src/components/EngineStream.tsx +++ b/src/components/EngineStream.tsx @@ -1,6 +1,5 @@ import { MouseEventHandler, useEffect, useRef } from 'react' import { useAppState } from 'AppState' -import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useModelingContext } from 'hooks/useModelingContext' import { useNetworkContext } from 'hooks/useNetworkContext' import { NetworkHealthState } from 'hooks/useNetworkStatus' @@ -14,31 +13,34 @@ import { PATHS } from 'lib/paths' import { IndexLoaderData } from 'lib/types' import { err, reportRejection, trap } from 'lib/trap' import { getArtifactOfTypes } from 'lang/std/artifactGraph' -import { clearSceneAndBustCache } from 'lang/wasm' import { ViewControlContextMenu } from './ViewControlMenu' +import { useSettings, engineStreamActor } from 'machines/appMachine' import { commandBarActor, useCommandBarState } from 'machines/commandBarMachine' +import { EngineStreamState, EngineStreamTransition } from 'machines/engineStreamMachine' import { useSelector } from '@xstate/react' -import useEngineStreamContext, { - EngineStreamState, - EngineStreamTransition, -} from 'hooks/useEngineStreamContext' import { REASONABLE_TIME_TO_REFRESH_STREAM_SIZE } from 'lib/timings' -export const EngineStream = () => { +export const EngineStream = (props: { + pool: string | null, + authToken: string | undefined, +}) => { const { setAppState } = useAppState() const { overallState } = useNetworkContext() - const { settings } = useSettingsAuthContext() + const settings = useSettings() + + const engineStreamState = useSelector(engineStreamActor, (state) => state) + const { file } = useRouteLoaderData(PATHS.FILE) as IndexLoaderData const last = useRef(Date.now()) const videoWrapperRef = useRef(null) const settingsEngine = { - theme: settings.context.app.theme.current, - enableSSAO: settings.context.app.enableSSAO.current, - highlightEdges: settings.context.modeling.highlightEdges.current, - showScaleGrid: settings.context.modeling.showScaleGrid.current, - cameraProjection: settings.context.modeling.cameraProjection.current, + theme: settings.app.theme.current, + enableSSAO: settings.modeling.enableSSAO.current, + highlightEdges: settings.modeling.highlightEdges.current, + showScaleGrid: settings.modeling.showScaleGrid.current, + cameraProjection: settings.modeling.cameraProjection.current, } const { state: modelingMachineState, send: modelingMachineActorSend } = @@ -46,10 +48,7 @@ export const EngineStream = () => { const commandBarState = useCommandBarState() - const engineStreamActor = useEngineStreamContext.useActorRef() - const engineStreamState = engineStreamActor.getSnapshot() - - const streamIdleMode = settings.context.app.streamIdleMode.current + const streamIdleMode = settings.app.streamIdleMode.current const startOrReconfigureEngine = () => { engineStreamActor.send({ @@ -80,6 +79,15 @@ export const EngineStream = () => { play ) + engineStreamActor.send({ + type: EngineStreamTransition.SetPool, + data: { pool: props.pool }, + }) + engineStreamActor.send({ + type: EngineStreamTransition.SetAuthToken, + data: { authToken: props.authToken }, + }) + return () => { engineCommandManager.tearDown() engineCommandManager.removeEventListener( @@ -325,7 +333,7 @@ export const EngineStream = () => { No canvas support { const [commands] = useEngineCommands() const [isDone, setIsDone] = useState(false) - const engineStreamActor = useEngineStreamContext.useActorRef() - const engineStreamState = engineStreamActor.getSnapshot() + const engineStreamState = useSelector(engineStreamActor, (state) => state) const lastCommandType = commands[commands.length - 1]?.type diff --git a/src/components/ModelingMachineProvider.tsx b/src/components/ModelingMachineProvider.tsx index 45b67bf9f..13e88dd17 100644 --- a/src/components/ModelingMachineProvider.tsx +++ b/src/components/ModelingMachineProvider.tsx @@ -147,7 +147,6 @@ export const ModelingMachineProvider = ({ showScaleGrid, cameraOrbit, enableSSAO, - cameraProjection, }, } = useSettings() const navigate = useNavigate() diff --git a/src/components/Stream.tsx b/src/components/Stream.tsx deleted file mode 100644 index 9cf166a38..000000000 --- a/src/components/Stream.tsx +++ /dev/null @@ -1,414 +0,0 @@ -import { useAppStream } from '@src/AppState' -import type { MouseEventHandler } from 'react' -import { useEffect, useRef, useState } from 'react' -import { useRouteLoaderData } from 'react-router-dom' - -import { ClientSideScene } from '@src/clientSideScene/ClientSideSceneComp' -import Loading from '@src/components/Loading' -import { ViewControlContextMenu } from '@src/components/ViewControlMenu' -import { useModelingContext } from '@src/hooks/useModelingContext' -import { useNetworkContext } from '@src/hooks/useNetworkContext' -import { NetworkHealthState } from '@src/hooks/useNetworkStatus' -import { getArtifactOfTypes } from '@src/lang/std/artifactGraph' -import { - DisconnectingType, - EngineCommandManagerEvents, - EngineConnectionStateType, -} from '@src/lang/std/engineConnection' -import { btnName } from '@src/lib/cameraControls' -import { PATHS } from '@src/lib/paths' -import { sendSelectEventToEngine } from '@src/lib/selections' -import { - engineCommandManager, - kclManager, - sceneInfra, -} from '@src/lib/singletons' -import { err, reportRejection } from '@src/lib/trap' -import type { IndexLoaderData } from '@src/lib/types' -import { uuidv4 } from '@src/lib/utils' -import { useSettings } from '@src/machines/appMachine' -import { useCommandBarState } from '@src/machines/commandBarMachine' - -enum StreamState { - Playing = 'playing', - Paused = 'paused', - Resuming = 'resuming', - Unset = 'unset', -} - -export const Stream = () => { - const [isLoading, setIsLoading] = useState(true) - const videoWrapperRef = useRef(null) - const videoRef = useRef(null) - const settings = useSettings() - const { state, send } = useModelingContext() - const commandBarState = useCommandBarState() - const { mediaStream } = useAppStream() - const { overallState, immediateState } = useNetworkContext() - const [streamState, setStreamState] = useState(StreamState.Unset) - const { file } = useRouteLoaderData(PATHS.FILE) as IndexLoaderData - - const IDLE = settings.app.streamIdleMode.current - - const isNetworkOkay = - overallState === NetworkHealthState.Ok || - overallState === NetworkHealthState.Weak - - engineCommandManager.elVideo = videoRef.current - - /** - * Execute code and show a "building scene message" - * in Stream.tsx in the meantime. - * - * I would like for this to live somewhere more central, - * but it seems to me that we need the video element ref - * to be able to play the video after the code has been - * executed. If we can find a way to do this from a more - * central place, we can move this code there. - */ - function executeCodeAndPlayStream() { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - kclManager.executeCode().then(async () => { - await videoRef.current?.play().catch((e) => { - console.warn('Video playing was prevented', e, videoRef.current) - }) - setStreamState(StreamState.Playing) - - // Only call zoom_to_fit once when the stream starts to center the scene. - await engineCommandManager.sendSceneCommand({ - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'zoom_to_fit', - object_ids: [], // leave empty to zoom to all objects - padding: 0.1, // padding around the objects - animated: false, // don't animate the zoom for now - }, - }) - }) - } - - /** - * Subscribe to execute code when the file changes - * but only if the scene is already ready. - * See onSceneReady for the initial scene setup. - */ - useEffect(() => { - if (engineCommandManager.engineConnection?.isReady() && file?.path) { - console.log('execute on file change') - executeCodeAndPlayStream() - } - }, [file?.path, engineCommandManager.engineConnection]) - - useEffect(() => { - if ( - immediateState.type === EngineConnectionStateType.Disconnecting && - immediateState.value.type === DisconnectingType.Pause - ) { - setStreamState(StreamState.Paused) - } - }, [immediateState]) - - // Linux has a default behavior to paste text on middle mouse up - // This adds a listener to block that pasting if the click target - // is not a text input, so users can move in the 3D scene with - // middle mouse drag with a text input focused without pasting. - useEffect(() => { - const handlePaste = (e: ClipboardEvent) => { - const isHtmlElement = e.target && e.target instanceof HTMLElement - const isEditable = - (isHtmlElement && !('explicitOriginalTarget' in e)) || - ('explicitOriginalTarget' in e && - ((e.explicitOriginalTarget as HTMLElement).contentEditable === - 'true' || - ['INPUT', 'TEXTAREA'].some( - (tagName) => - tagName === (e.explicitOriginalTarget as HTMLElement).tagName - ))) - if (!isEditable) { - e.preventDefault() - e.stopPropagation() - e.stopImmediatePropagation() - } - } - - globalThis?.window?.document?.addEventListener('paste', handlePaste, { - capture: true, - }) - - const IDLE_TIME_MS = 1000 * 60 * 2 - let timeoutIdIdleA: ReturnType | undefined = undefined - - const teardown = () => { - // Already paused - if (streamState === StreamState.Paused) return - - videoRef.current?.pause() - setStreamState(StreamState.Paused) - sceneInfra.modelingSend({ type: 'Cancel' }) - // Give video time to pause - window.requestAnimationFrame(() => { - engineCommandManager.tearDown({ idleMode: true }) - }) - } - - const onVisibilityChange = () => { - if (globalThis.window.document.visibilityState === 'hidden') { - clearTimeout(timeoutIdIdleA) - timeoutIdIdleA = setTimeout(teardown, IDLE_TIME_MS) - } else if (!engineCommandManager.engineConnection?.isReady()) { - clearTimeout(timeoutIdIdleA) - setStreamState(StreamState.Resuming) - } - } - - // Teardown everything if we go hidden or reconnect - if (IDLE) { - globalThis?.window?.document?.addEventListener( - 'visibilitychange', - onVisibilityChange - ) - } - - let timeoutIdIdleB: ReturnType | undefined = undefined - - const onAnyInput = () => { - if (streamState === StreamState.Playing) { - // Clear both timers - clearTimeout(timeoutIdIdleA) - clearTimeout(timeoutIdIdleB) - timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS) - } - if (streamState === StreamState.Paused) { - setStreamState(StreamState.Resuming) - } - } - - if (IDLE) { - globalThis?.window?.document?.addEventListener('keydown', onAnyInput) - globalThis?.window?.document?.addEventListener('mousemove', onAnyInput) - globalThis?.window?.document?.addEventListener('mousedown', onAnyInput) - globalThis?.window?.document?.addEventListener('scroll', onAnyInput) - globalThis?.window?.document?.addEventListener('touchstart', onAnyInput) - } - - if (IDLE) { - timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS) - } - - /** - * Add a listener to execute code and play the stream - * on initial stream setup. - */ - engineCommandManager.addEventListener( - EngineCommandManagerEvents.SceneReady, - executeCodeAndPlayStream - ) - - return () => { - engineCommandManager.removeEventListener( - EngineCommandManagerEvents.SceneReady, - executeCodeAndPlayStream - ) - globalThis?.window?.document?.removeEventListener('paste', handlePaste, { - capture: true, - }) - if (IDLE) { - clearTimeout(timeoutIdIdleA) - clearTimeout(timeoutIdIdleB) - - globalThis?.window?.document?.removeEventListener( - 'visibilitychange', - onVisibilityChange - ) - globalThis?.window?.document?.removeEventListener('keydown', onAnyInput) - globalThis?.window?.document?.removeEventListener( - 'mousemove', - onAnyInput - ) - globalThis?.window?.document?.removeEventListener( - 'mousedown', - onAnyInput - ) - globalThis?.window?.document?.removeEventListener('scroll', onAnyInput) - globalThis?.window?.document?.removeEventListener( - 'touchstart', - onAnyInput - ) - } - } - }, [IDLE, streamState]) - - useEffect(() => { - if ( - typeof window === 'undefined' || - typeof RTCPeerConnection === 'undefined' - ) - return - if (!videoRef.current) return - if (!mediaStream) return - - // The browser complains if we try to load a new stream without pausing first. - // Do not immediately play the stream! - // we instead use a setTimeout to play the stream in the next event loop - try { - videoRef.current.srcObject = mediaStream - videoRef.current.pause() - setTimeout(() => { - videoRef.current?.play().catch((e) => { - console.warn('Video playing was prevented', e, videoRef.current) - }) - }) - } catch (e) { - console.warn('Attempted to pause stream while play was still loading', e) - } - - send({ - type: 'Set context', - data: { - videoElement: videoRef.current, - }, - }) - - setIsLoading(false) - }, [mediaStream]) - - const handleClick: MouseEventHandler = (e) => { - // If we've got no stream or connection, don't do anything - if (!isNetworkOkay) return - if (!videoRef.current) return - // If we're in sketch mode, don't send a engine-side select event - if (state.matches('Sketch')) return - // Only respect default plane selection if we're on a selection command argument - if ( - state.matches({ idle: 'showPlanes' }) && - !( - commandBarState.matches('Gathering arguments') && - commandBarState.context.currentArgument?.inputType === 'selection' - ) - ) - return - // If we're mousing up from a camera drag, don't send a select event - if (sceneInfra.camControls.wasDragging === true) return - - if (btnName(e.nativeEvent).left) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - sendSelectEventToEngine(e) - } - } - - /** - * On double-click of sketch entities we automatically enter sketch mode with the selected sketch, - * allowing for quick editing of sketches. TODO: This should be moved to a more central place. - */ - const enterSketchModeIfSelectingSketch: MouseEventHandler = ( - e - ) => { - if ( - !isNetworkOkay || - !videoRef.current || - state.matches('Sketch') || - state.matches({ idle: 'showPlanes' }) || - sceneInfra.camControls.wasDragging === true || - !btnName(e.nativeEvent).left - ) { - return - } - - sendSelectEventToEngine(e) - .then(({ entity_id }) => { - if (!entity_id) { - // No entity selected. This is benign - return - } - const path = getArtifactOfTypes( - { key: entity_id, types: ['path', 'solid2d', 'segment', 'helix'] }, - kclManager.artifactGraph - ) - if (err(path)) { - return path - } - sceneInfra.modelingSend({ type: 'Enter sketch' }) - }) - .catch(reportRejection) - } - - return ( - // eslint-disable-next-line jsx-a11y/no-static-element-interactions -
e.preventDefault()} - onContextMenuCapture={(e) => e.preventDefault()} - > -
- ) -} diff --git a/src/lang/std/engineConnection.ts b/src/lang/std/engineConnection.ts index ca1c54da5..6bd54164f 100644 --- a/src/lang/std/engineConnection.ts +++ b/src/lang/std/engineConnection.ts @@ -841,7 +841,9 @@ class EngineConnection extends EventTarget { // Bust the cache before anything ;(async () => { - await clearSceneAndBustCache(kclManager.engineCommandManager) + await rustContext.clearSceneAndBustCache( + kclManager.engineCommandManager.settings + ) })().catch(reportRejection) this.dispatchEvent( @@ -1395,8 +1397,6 @@ export class EngineCommandManager extends EventTarget { height: 1337, } - elVideo: HTMLVideoElement | null = null - _commandLogCallBack: (command: CommandLog[]) => void = () => {} subscriptions: { diff --git a/src/lib/selections.ts b/src/lib/selections.ts index a0196234d..163274e5e 100644 --- a/src/lib/selections.ts +++ b/src/lib/selections.ts @@ -649,12 +649,13 @@ export async function sendSelectEventToEngine( e: React.MouseEvent ) { // No video stream to normalise against, return immediately - if (!engineCommandManager.elVideo) + const engineStreamState = engineStreamActor.getSnapshot().context + if (!engineStreamState.videoRef.current) return Promise.reject('video element not ready') const { x, y } = getNormalisedCoordinates( e, - engineCommandManager.elVideo, + engineStreamState.videoRef.current, engineCommandManager.streamDimensions ) const res = await engineCommandManager.sendSceneCommand({ diff --git a/src/machines/appMachine.ts b/src/machines/appMachine.ts index 29f0b676e..4423ce9df 100644 --- a/src/machines/appMachine.ts +++ b/src/machines/appMachine.ts @@ -6,10 +6,11 @@ import { authMachine } from '@src/machines/authMachine' import { ACTOR_IDS } from '@src/machines/machineConstants' import { settingsMachine } from '@src/machines/settingsMachine' -const { AUTH, SETTINGS } = ACTOR_IDS +const { AUTH, SETTINGS, ENGINE_STREAM } = ACTOR_IDS const appMachineActors = { [AUTH]: authMachine, [SETTINGS]: settingsMachine, + [ENGINE_STREAM]: engineStreamMachine, } as const const appMachine = setup({ @@ -29,6 +30,11 @@ const appMachine = setup({ systemId: SETTINGS, input: createSettings(), }), + spawnChild(ENGINE_STREAM, { + id: ENGINE_STREAM, + systemId: ENGINE_STREAM, + input: engineStreamContextCreate(), + }), ], }) @@ -61,3 +67,7 @@ export const useSettings = () => const { currentProject, ...settings } = state.context return settings }) + +export const engineStreamActor = appActor.system.get(ENGINE_STREAM) as ActorRefFrom< + typeof engineStreamMachine +> diff --git a/src/hooks/useEngineStreamContext.ts b/src/machines/engineStreamMachine.ts similarity index 75% rename from src/hooks/useEngineStreamContext.ts rename to src/machines/engineStreamMachine.ts index a89ac22b0..190dd91d3 100644 --- a/src/hooks/useEngineStreamContext.ts +++ b/src/machines/engineStreamMachine.ts @@ -1,9 +1,7 @@ import { uuidv4 } from 'lib/utils' -import { makeDefaultPlanes, clearSceneAndBustCache } from 'lang/wasm' import { MutableRefObject } from 'react' import { setup, assign, fromPromise } from 'xstate' -import { createActorContext } from '@xstate/react' -import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons' +import { rustContext, kclManager, sceneInfra, engineCommandManager } from 'lib/singletons' import { trap } from 'lib/trap' import { Vector3, Vector4 } from 'three' @@ -19,7 +17,9 @@ export enum EngineStreamState { } export enum EngineStreamTransition { - SetMediaStream = 'set-context', + SetMediaStream = 'set-media-stream', + SetPool = 'set-pool', + SetAuthToken = 'set-auth-token', Play = 'play', Resume = 'resume', Pause = 'pause', @@ -35,6 +35,15 @@ export interface EngineStreamContext { zoomToFit: boolean } +export const engineStreamContextCreate = (): EngineStreamContext => ({ + pool: null, + authToken: undefined, + mediaStream: null, + videoRef: { current: null }, + canvasRef: { current: null }, + zoomToFit: true, +}) + export function getDimensions(streamWidth: number, streamHeight: number) { const factorOf = 4 const maxResolution = 2160 @@ -47,11 +56,11 @@ export function getDimensions(streamWidth: number, streamHeight: number) { return { width: quadWidth, height: quadHeight } } -export function holdOntoVideoFrameInCanvas( +export async function holdOntoVideoFrameInCanvas( video: HTMLVideoElement, canvas: HTMLCanvasElement ) { - video.pause() + await video.pause() canvas.width = video.videoWidth canvas.height = video.videoHeight canvas.style.width = video.videoWidth + 'px' @@ -64,7 +73,7 @@ export function holdOntoVideoFrameInCanvas( ctx.drawImage(video, 0, 0, canvas.width, canvas.height) } -const engineStreamMachine = setup({ +export const engineStreamMachine = setup({ types: { context: {} as EngineStreamContext, input: {} as EngineStreamContext, @@ -88,7 +97,7 @@ const engineStreamMachine = setup({ video.style.display = 'block' canvas.style.display = 'none' - await sceneInfra.camControls.restoreCameraPosition() + // await sceneInfra.camControls.restoreCameraPosition() video.srcObject = mediaStream await video.play() @@ -105,12 +114,12 @@ const engineStreamMachine = setup({ const video = context.videoRef.current if (!video) return - video.pause() + await video.pause() const canvas = context.canvasRef.current if (!canvas) return - holdOntoVideoFrameInCanvas(video, canvas) + await holdOntoVideoFrameInCanvas(video, canvas) // Make sure we're on the next frame for no flickering between canvas // and the video elements. @@ -126,57 +135,6 @@ const engineStreamMachine = setup({ context.mediaStream?.getVideoTracks()[0].stop() video.srcObject = null - const reqDefaultCameraGetSettings = - await engineCommandManager.sendSceneCommand({ - // CameraControls subscribes to default_camera_get_settings response events - // firing this at connection ensure the camera's are synced initially - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'default_camera_get_settings', - }, - }) - - if ( - reqDefaultCameraGetSettings === null || - !reqDefaultCameraGetSettings.success - ) - return - if ( - !('modeling_response' in reqDefaultCameraGetSettings.resp.data) - ) - return - if ( - reqDefaultCameraGetSettings.resp.data.modeling_response.type === - 'empty' - ) - return - if ( - !( - 'settings' in - reqDefaultCameraGetSettings.resp.data.modeling_response.data - ) - ) - return - - const center = - reqDefaultCameraGetSettings.resp.data.modeling_response.data - .settings.center - const pos = - reqDefaultCameraGetSettings.resp.data.modeling_response.data - .settings.pos - - sceneInfra.camControls.old = { - camera: sceneInfra.camControls.camera.clone(), - target: new Vector3(center.x, center.y, center.z), - } - - sceneInfra.camControls.old.camera.position.set( - pos.x, - pos.y, - pos.z - ) - engineCommandManager.tearDown({ idleMode: true }) })() ) @@ -215,7 +173,7 @@ const engineStreamMachine = setup({ // If we don't pause there could be a really bad flicker // on reconfiguration (resize, for example) - holdOntoVideoFrameInCanvas(video, canvas) + await holdOntoVideoFrameInCanvas(video, canvas) canvas.style.display = 'block' window.requestAnimationFrame(() => { @@ -231,9 +189,6 @@ const engineStreamMachine = setup({ height, token: context.authToken, settings: settingsNext, - makeDefaultPlanes: () => { - return makeDefaultPlanes(kclManager.engineCommandManager) - }, }) event.modelingMachineActorSend({ @@ -250,11 +205,24 @@ const engineStreamMachine = setup({ ), }, }).createMachine({ - context: (initial) => initial.input, initial: EngineStreamState.Off, + context: (initial) => initial.input, states: { [EngineStreamState.Off]: { + reenter: true, on: { + [EngineStreamTransition.SetPool]: { + target: EngineStreamState.Setup, + actions: [ + assign({ pool: ({ context, event }) => event.data.pool }), + ], + }, + [EngineStreamTransition.SetAuthToken]: { + target: EngineStreamState.Setup, + actions: [ + assign({ authToken: ({ context, event }) => event.data.authToken }), + ], + }, [EngineStreamTransition.StartOrReconfigureEngine]: { target: EngineStreamState.On, }, @@ -267,6 +235,7 @@ const engineStreamMachine = setup({ input: (args) => args, }, on: { + // Transition requested by engineConnection [EngineStreamTransition.SetMediaStream]: { target: EngineStreamState.On, actions: [ @@ -335,5 +304,3 @@ const engineStreamMachine = setup({ }, }, }) - -export default createActorContext(engineStreamMachine) diff --git a/src/machines/machineConstants.ts b/src/machines/machineConstants.ts index 782d57964..50986d3a3 100644 --- a/src/machines/machineConstants.ts +++ b/src/machines/machineConstants.ts @@ -1,4 +1,5 @@ export const ACTOR_IDS = { AUTH: 'auth', SETTINGS: 'settings', + ENGINE_STREAM: 'engine_stream', } as const