From bb60afaf0c1fcafbfd7540209b6146fb6f793724 Mon Sep 17 00:00:00 2001 From: Manuel Martin Date: Wed, 24 Jan 2024 12:14:11 +0100 Subject: [PATCH] Handle inspected entity removal cases gracefully --- src/bit-components.js | 5 +-- src/bit-systems/inspect-system.ts | 17 ++++++---- src/bit-systems/object-menu.ts | 7 ++--- .../room/hooks/useObjectList.js | 31 +++++++++++++------ src/systems/camera-system.js | 12 ++----- 5 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/bit-components.js b/src/bit-components.js index ad46cb8d7a..4065bf6280 100644 --- a/src/bit-components.js +++ b/src/bit-components.js @@ -100,8 +100,9 @@ export const PenActive = defineComponent(); export const PenUpdated = defineComponent(); export const HoverMenuChild = defineComponent(); export const Static = defineComponent(); -export const Inspectable = defineComponent(); -export const InspectTargetChanged = defineComponent(); +export const Inspectable = defineComponent({ + flags: Types.ui8 +}); export const Inspected = defineComponent(); export const PreventAudioBoost = defineComponent(); export const IgnoreSpaceBubble = defineComponent(); diff --git a/src/bit-systems/inspect-system.ts b/src/bit-systems/inspect-system.ts index b51aedd155..b9d3c72232 100644 --- a/src/bit-systems/inspect-system.ts +++ b/src/bit-systems/inspect-system.ts @@ -1,19 +1,24 @@ -import { defineQuery, enterQuery, exitQuery, hasComponent, removeComponent } from "bitecs"; +import { defineQuery, enterQuery, exitQuery } from "bitecs"; import { HubsWorld } from "../app"; -import { InspectTargetChanged, Inspected } from "../bit-components"; +import { Inspectable, Inspected } from "../bit-components"; import { CameraSystem } from "../systems/camera-system"; -import { anyEntityWith } from "../utils/bit-utils"; + +export const INSPECTABLE_FLAGS = { + TARGET_CHANGED: 1 << 0 +}; const inspectedQuery = defineQuery([Inspected]); const inspectedEnterQuery = enterQuery(inspectedQuery); const inspectedExitQuery = exitQuery(inspectedQuery); export function inspectSystem(world: HubsWorld, cameraSystem: CameraSystem) { inspectedExitQuery(world).forEach(eid => { - cameraSystem.uninspect(hasComponent(world, InspectTargetChanged, eid)); - removeComponent(world, InspectTargetChanged, eid); + const targetChanged = Boolean(Inspectable.flags[eid] & INSPECTABLE_FLAGS.TARGET_CHANGED); + cameraSystem.uninspect(targetChanged); + Inspectable.flags[eid] = 0; }); inspectedEnterQuery(world).forEach(eid => { const obj = world.eid2obj.get(eid); - cameraSystem.inspect(obj, 1.5, hasComponent(world, InspectTargetChanged, eid)); + const targetChanged = Boolean(Inspectable.flags[eid] & INSPECTABLE_FLAGS.TARGET_CHANGED); + cameraSystem.inspect(obj, 1.5, targetChanged); }); } diff --git a/src/bit-systems/object-menu.ts b/src/bit-systems/object-menu.ts index d1379ff73d..10562b0372 100644 --- a/src/bit-systems/object-menu.ts +++ b/src/bit-systems/object-menu.ts @@ -23,8 +23,7 @@ import { MediaMirrored, Inspected, Inspectable, - Deletable, - InspectTargetChanged + Deletable } from "../bit-components"; import { anyEntityWith, @@ -45,6 +44,7 @@ import { canPin, setPinned } from "../utils/bit-pinning-helper"; import { ObjectMenuTransformFlags } from "../inflators/object-menu-transform"; import { COLLISION_LAYERS } from "../constants"; import { FLOATY_OBJECT_FLAGS } from "../systems/floaty-object-system"; +import { INSPECTABLE_FLAGS } from "./inspect-system"; // Working variables. const _vec3_1 = new Vector3(); const _vec3_2 = new Vector3(); @@ -226,7 +226,7 @@ function handleHeldEnter(world: HubsWorld, eid: EntityID, menuEid: EntityID) { if (!hasComponent(world, Inspected, ObjectMenu.targetRef[menuEid])) { ObjectMenu.flags[menuEid] &= ~ObjectMenuFlags.Visible; addComponent(world, Inspected, ObjectMenu.targetRef[menuEid]); - addComponent(world, InspectTargetChanged, ObjectMenu.targetRef[menuEid]); + Inspectable.flags[ObjectMenu.targetRef[menuEid]] |= INSPECTABLE_FLAGS.TARGET_CHANGED; } break; } @@ -246,7 +246,6 @@ function handleHeldExit(world: HubsWorld, eid: EntityID, menuEid: EntityID) { if (hasComponent(world, Inspected, ObjectMenu.targetRef[menuEid])) { ObjectMenu.flags[menuEid] |= ObjectMenuFlags.Visible; removeComponent(world, Inspected, ObjectMenu.targetRef[menuEid]); - addComponent(world, InspectTargetChanged, ObjectMenu.targetRef[menuEid]); } break; } diff --git a/src/react-components/room/hooks/useObjectList.js b/src/react-components/room/hooks/useObjectList.js index 8dfc130270..2af615955b 100644 --- a/src/react-components/room/hooks/useObjectList.js +++ b/src/react-components/room/hooks/useObjectList.js @@ -117,6 +117,11 @@ export function ObjectListProvider({ scene, children }) { eid: eid })); setObjects(objects); + + const inspected = anyEntityWith(APP.world, Inspected); + if (!inspected || !objects.find(o => o.eid === inspected)) { + setSelectedObject(null); + } } else { const objects = scene.systems["listed-media"].els.sort(mediaSortAframe).map(el => ({ id: el.object3D.id, @@ -126,6 +131,13 @@ export function ObjectListProvider({ scene, children }) { el })); setObjects(objects); + + const cameraSystem = scene.systems["hubs-systems"].cameraSystem; + const inspectedEl = cameraSystem.inspectable && cameraSystem.inspectable.el; + + if (!inspectedEl || !objects.find(o => o.el === inspectedEl)) { + setSelectedObject(null); + } } } @@ -145,32 +157,31 @@ export function ObjectListProvider({ scene, children }) { scene.removeEventListener("listed_media_changed", updateMediaEntities); clearTimeout(timeout); }; - }, [scene, setObjects]); + }, [scene, setObjects, setSelectedObject]); useEffect(() => { function onInspectTargetChanged() { - const cameraSystem = scene.systems["hubs-systems"].cameraSystem; - if (shouldUseNewLoader()) { - const inspectedEid = cameraSystem.inspectable && cameraSystem.inspectable.eid; + const inspected = anyEntityWith(APP.world, Inspected); - if (inspectedEid) { - const object = objects.find(o => o.eid === inspectedEid); + if (inspected) { + const object = objects.find(o => o.eid === inspected); if (object) { setSelectedObject(object); } else { setSelectedObject({ - id: APP.world.eid2obj.get(inspectedEid)?.id, - name: getDisplayString(getUrl(inspectedEid)), - type: getMediaType(inspectedEid), - eid: inspectedEid + id: APP.world.eid2obj.get(inspected)?.id, + name: getDisplayString(getUrl(inspected)), + type: getMediaType(inspected), + eid: inspected }); } } else { setSelectedObject(null); } } else { + const cameraSystem = scene.systems["hubs-systems"].cameraSystem; const inspectedEl = cameraSystem.inspectable && cameraSystem.inspectable.el; if (inspectedEl) { diff --git a/src/systems/camera-system.js b/src/systems/camera-system.js index d555330479..1f04aec521 100644 --- a/src/systems/camera-system.js +++ b/src/systems/camera-system.js @@ -8,14 +8,7 @@ import { qsGet } from "../utils/qs_truthy"; const customFOV = qsGet("fov"); const enableThirdPersonMode = qsTruthy("thirdPerson"); import { Layers } from "../camera-layers"; -import { - HoveredRemoteRight, - InspectTargetChanged, - Inspectable, - Inspected, - LocalAvatar, - RemoteAvatar -} from "../bit-components"; +import { HoveredRemoteRight, Inspectable, Inspected, LocalAvatar, RemoteAvatar } from "../bit-components"; import { anyEntityWith, findAncestorWithAnyComponent, @@ -23,6 +16,7 @@ import { shouldUseNewLoader } from "../utils/bit-utils"; import { addComponent, defineQuery, removeComponent } from "bitecs"; +import { INSPECTABLE_FLAGS } from "../bit-systems/inspect-system"; function getInspectableInHierarchy(eid) { let inspectable = findAncestorWithComponent(APP.world, Inspectable, eid); @@ -473,7 +467,7 @@ export class CameraSystem { if (hoveredQuery(APP.world).length) { const hovered = hoveredQuery(APP.world)[0]; addComponent(APP.world, Inspected, hovered); - addComponent(APP.world, InspectTargetChanged, hovered); + Inspectable.flags[hovered] |= INSPECTABLE_FLAGS.TARGET_CHANGED; } } else { const hoverEl = this.interaction.state.rightRemote.hovered || this.interaction.state.leftRemote.hovered;