Skip to content

Commit

Permalink
IR-6241 - fix: example routes mounting and state update issues (#842)
Browse files Browse the repository at this point in the history
* example routes mounting and state update issues

* Fix renderer canvas setup

* Update ClientInputHooks.tsx

* Update FeathersHooks.tsx

* Update PostProcessingComponent.test.tsx

* Update ClientInputHooks.tsx

* Update ClientInputHooks.test.tsx

* address PR comments

* undo accidental commit

* Update ClientInputHooks.tsx

---------

Co-authored-by: Josh Field <10372036+HexaField@users.noreply.github.com>
  • Loading branch information
speigg and HexaField authored Dec 17, 2024
1 parent 603b576 commit 7de00f3
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 35 deletions.
20 changes: 4 additions & 16 deletions packages/client-core/src/hooks/useEngineCanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,15 @@ Infinite Reality Engine. All Rights Reserved.
*/

import { getComponent, getOptionalMutableComponent, hasComponent } from '@ir-engine/ecs'
import { getState, none, useHookstate, useMutableState } from '@ir-engine/hyperflux'
import { getState, none, useMutableState } from '@ir-engine/hyperflux'
import { EngineState } from '@ir-engine/spatial/src/EngineState'
import { destroySpatialViewer, initializeSpatialViewer } from '@ir-engine/spatial/src/initializeEngine'
import { RendererComponent } from '@ir-engine/spatial/src/renderer/WebGLRendererSystem'
import { useEffect } from 'react'

export const useEngineCanvas = (ref: React.RefObject<HTMLElement>) => {
const lastRef = useHookstate(() => ref.current)

useEffect(() => {
if (ref.current !== lastRef.value) {
lastRef.set(ref.current)
}
}, [ref.current])

useEffect(() => {
if (!lastRef.value) return

const parent = lastRef.value as HTMLElement
const parent = ref.current as HTMLElement

const canvas = document.getElementById('engine-renderer-canvas') as HTMLCanvasElement

Expand All @@ -63,17 +53,15 @@ export const useEngineCanvas = (ref: React.RefObject<HTMLElement>) => {
originalParent.appendChild(canvas)
canvas.hidden = true
}
}, [lastRef.value])
}, [])

/** Essentially mount/unmount upon the attach/detatch state of the ref node */
useEffect(() => {
if (!lastRef.value) return
const canvas = document.getElementById('engine-renderer-canvas') as HTMLCanvasElement
initializeSpatialViewer(canvas)
return () => {
destroySpatialViewer()
}
}, [!!lastRef.value])
}, [])

/**
* Since the viewer and XR reference spaces can technically exist without the other,
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/utils/FeathersHooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export const useService = <S extends keyof ServiceTypes, M extends Methods>(
// prettier-ignore
return API.instance.service(serviceName)[method](...args)
.then((res) => {
//console.log(`API: ${serviceName}.${method}`, ...args, res)
state[serviceName][queryId].merge({
response: res,
status: 'success',
Expand Down
6 changes: 2 additions & 4 deletions packages/editor/src/panels/viewport/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,9 @@ function ViewportContainer() {
{sceneName.value ? <SelectionBox viewportRef={ref} toolbarRef={toolbarRef} /> : null}
{sceneName.value ? <TransformGizmoTool /> : null}
{sceneName.value ? <CameraGizmoTool viewportRef={ref} toolbarRef={toolbarRef} /> : null}
<div id="engine-renderer-canvas-container" ref={ref} className="absolute h-full w-full" />
{sceneName.value ? (
<>
<div id="engine-renderer-canvas-container" ref={ref} className="absolute h-full w-full" />
{rootEntity.value && <SceneLoadingProgress key={rootEntity.value} rootEntity={rootEntity.value} />}
</>
<>{rootEntity.value && <SceneLoadingProgress key={rootEntity.value} rootEntity={rootEntity.value} />}</>
) : (
<div className="flex h-full w-full flex-col justify-center gap-2">
<img src={clientSettings?.appTitle} className="block scale-[.8]" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ const execute = () => {
normalizedHips.matrixWorld.multiplyMatrices(newWorldMatrix, normalizedHips.matrix)
normalizedHips.matrixWorld.scale(new Vector3(100, 100, 100))
for (const boneName of VRMHumanBoneList) {
const bone = getComponent(rigComponent.bonesToEntities[boneName], NormalizedBoneComponent)
const bone = getOptionalComponent(rigComponent.bonesToEntities[boneName], NormalizedBoneComponent)
if (!bone) continue
bone.scale.setScalar(1)
bone.updateMatrix()
Expand Down
24 changes: 22 additions & 2 deletions packages/hyperflux/src/hooks/useImmediateEffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ All portions of the code written by the Infinite Reality Engine team are Copyrig
Infinite Reality Engine. All Rights Reserved.
*/

import { DependencyList, EffectCallback, useLayoutEffect, useRef } from 'react'
import { DependencyList, EffectCallback, useEffect, useLayoutEffect, useRef } from 'react'

function depsDiff(deps1, deps2) {
return !(
Expand All @@ -34,24 +34,44 @@ function depsDiff(deps1, deps2) {
)
}

function noop() {}

/**
* Run an effect immediately on mount and whenever deps change.
*
* WARNING: Do not use this hook in a context that may suspend,
* as the cleanup function will not be called on suspension,
* and the effect will be run again on resume.
*
* @param effect
* @param deps
*/
export function useImmediateEffect(effect: EffectCallback, deps?: DependencyList) {
const cleanupRef = useRef<any>()
const depsRef = useRef<any>()

if (!depsRef.current || depsDiff(depsRef.current, deps)) {
// only run effect on mount and whenever deps change
if (depsDiff(depsRef.current, deps)) {
depsRef.current = deps

// cleanup previous effect
if (cleanupRef.current) {
cleanupRef.current()
}

// run effect
cleanupRef.current = effect()
}

// make sure deps are hooked
useEffect(noop, deps)

// make sure final cleanup is called on unmount
useLayoutEffect(() => {
return () => {
if (cleanupRef.current) {
cleanupRef.current()
cleanupRef.current = undefined
}
}
}, [])
Expand Down
14 changes: 7 additions & 7 deletions packages/spatial/src/input/functions/ClientInputHooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ import { InputState } from '../state/InputState'
import ClientInputHooks from './ClientInputHooks'

const createMockHTMLCanvasElement = (ev: MockEventListener) => {
return {
addEventListener: ev.addEventListener,
removeEventListener: ev.removeEventListener,
getDrawingBufferSize: () => 0,
getContext: () => {},
parentElement: {
return new (class {
addEventListener = ev.addEventListener
removeEventListener = ev.removeEventListener
getDrawingBufferSize = () => 0
getContext = () => {}
parentElement = {
clientWidth: 100,
clientHeight: 100
}
} as any as HTMLCanvasElement
})() as any as HTMLCanvasElement
}

describe('ClientInputHooks', () => {
Expand Down
11 changes: 7 additions & 4 deletions packages/spatial/src/input/functions/ClientInputHooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
getOptionalComponent,
removeEntity,
setComponent,
useComponent,
useEntityContext
} from '@ir-engine/ecs'
import { getState, useImmediateEffect, useMutableState } from '@ir-engine/hyperflux'
Expand Down Expand Up @@ -203,11 +204,13 @@ export const useXRInputSources = () => {
export const CanvasInputReactor = () => {
const cameraEntity = useEntityContext()
const xrState = useMutableState(XRState)
const rendererComponent = useComponent(cameraEntity, RendererComponent)

useEffect(() => {
if (xrState.session.value) return // pointer input sources are automatically handled by webxr

const rendererComponent = getComponent(cameraEntity, RendererComponent)
const canvas = rendererComponent.canvas!
const canvas = rendererComponent.canvas.value
if (!canvas) return

/** Clear mouse events */
const pointerButtons = ['PrimaryClick', 'AuxiliaryClick', 'SecondaryClick'] as AnyButton[]
Expand Down Expand Up @@ -278,7 +281,7 @@ export const CanvasInputReactor = () => {
const pointerComponent = getOptionalComponent(pointerEntity, InputPointerComponent)
if (!pointerComponent) return

if (document.pointerLockElement === canvas) {
if (document.pointerLockElement === (canvas as HTMLCanvasElement)) {
pointerComponent.position.set(
pointerComponent.position.x + event.movementX / canvas.clientWidth,
pointerComponent.position.y - event.movementY / canvas.clientHeight
Expand Down Expand Up @@ -348,7 +351,7 @@ export const CanvasInputReactor = () => {
canvas.removeEventListener('click', onClick)
canvas.removeEventListener('wheel', onWheelEvent)
}
}, [xrState.session])
}, [xrState.session, rendererComponent.canvas])

return null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,10 @@ describe('PostProcessingComponent', async () => {

await act(() => rerender(null))

setComponent(rootEntity, RendererComponent)
const postProcessingComponent = getMutableComponent(testEntity, PostProcessingComponent)
postProcessingComponent.effects[effectKey].isActive.set(true)

setComponent(rootEntity, RendererComponent)
await act(() => rerender(null))

// @ts-ignore Allow access to the EffectPass.effects private field
Expand Down

0 comments on commit 7de00f3

Please sign in to comment.