diff --git a/packages/editor/src/systems/EditorControlSystem.tsx b/packages/editor/src/systems/EditorControlSystem.tsx index e76ae30a73..e08ef912bb 100644 --- a/packages/editor/src/systems/EditorControlSystem.tsx +++ b/packages/editor/src/systems/EditorControlSystem.tsx @@ -53,8 +53,12 @@ import { InputComponent } from '@etherealengine/spatial/src/input/components/Inp import { InputSourceComponent } from '@etherealengine/spatial/src/input/components/InputSourceComponent' import { InfiniteGridComponent } from '@etherealengine/spatial/src/renderer/components/InfiniteGridHelper' import { RendererState } from '@etherealengine/spatial/src/renderer/RendererState' -import { EntityTreeComponent } from '@etherealengine/spatial/src/transform/components/EntityTree' +import { + EntityTreeComponent, + getAncestorWithComponent +} from '@etherealengine/spatial/src/transform/components/EntityTree' +import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent' import { TransformGizmoControlComponent } from '../classes/TransformGizmoControlComponent' import { TransformGizmoControlledComponent } from '../classes/TransformGizmoControlledComponent' import { addMediaNode } from '../functions/addMediaNode' @@ -292,7 +296,14 @@ const execute = () => { clickedEntity = getComponent(clickedEntity, EntityTreeComponent).parentEntity! } if (hasComponent(clickedEntity, SourceComponent)) { - SelectionState.updateSelection([getComponent(clickedEntity, UUIDComponent)]) + const modelComponent = getAncestorWithComponent(clickedEntity, ModelComponent) + const ancestorModelEntity = modelComponent || clickedEntity + SelectionState.updateSelection([ + getComponent( + SelectionState.getSelectedEntities()[0] === ancestorModelEntity ? clickedEntity : ancestorModelEntity, + UUIDComponent + ) + ]) } } } diff --git a/packages/spatial/src/input/systems/ClientInputSystem.tsx b/packages/spatial/src/input/systems/ClientInputSystem.tsx index e331cbfa15..b7b0b75df5 100755 --- a/packages/spatial/src/input/systems/ClientInputSystem.tsx +++ b/packages/spatial/src/input/systems/ClientInputSystem.tsx @@ -235,8 +235,10 @@ const execute = () => { raycaster.set(inputRaycast.origin, inputRaycast.direction) raycaster.layers.enable(ObjectLayers.Default) + const inputState = getState(InputState) + const isEditing = getState(EngineState).isEditing // only heuristic is scene objects when in the editor - if (getState(EngineState).isEditing) { + if (isEditing) { const pickerObj = gizmoPickerObjects() // gizmo heuristic const inputObj = inputObjects() @@ -277,7 +279,7 @@ const execute = () => { intersectionData.add({ entity: hit.entity, distance: hit.distance }) } } - const inputState = getState(InputState) + // 3rd heuristic is bboxes for (const entity of inputState.inputBoundingBoxes) { const boundingBox = getComponent(entity, BoundingBoxComponent) @@ -286,19 +288,19 @@ const execute = () => { intersectionData.add({ entity, distance: inputRay.origin.distanceTo(bboxHitTarget) }) } } + } - // 4th heuristic is meshes - const objects = Array.from(inputState.inputMeshes) // gizmo heuristic - .filter((eid) => hasComponent(eid, GroupComponent)) - .map((eid) => getComponent(eid, GroupComponent)) - .flat() - - const hits = raycaster.intersectObjects(objects, true) - for (const hit of hits) { - const parentObject = Object3DUtils.findAncestor(hit.object, (obj) => obj.entity != undefined) - if (parentObject) { - intersectionData.add({ entity: parentObject.entity, distance: hit.distance }) - } + // 4th heuristic is meshes + const objects = (isEditing ? meshesQuery() : Array.from(inputState.inputMeshes)) // gizmo heuristic + .filter((eid) => hasComponent(eid, GroupComponent)) + .map((eid) => getComponent(eid, GroupComponent)) + .flat() + + const hits = raycaster.intersectObjects(objects, true) + for (const hit of hits) { + const parentObject = Object3DUtils.findAncestor(hit.object, (obj) => obj.entity != undefined) + if (parentObject) { + intersectionData.add({ entity: parentObject.entity, distance: hit.distance }) } } } @@ -672,6 +674,7 @@ const reactor = () => { const MeshInputReactor = () => { const entity = useEntityContext() const shouldReceiveInput = !!useAncestorWithComponent(entity, InputComponent) + useImmediateEffect(() => { const inputState = getState(InputState) if (shouldReceiveInput) inputState.inputMeshes.add(entity) diff --git a/packages/ui/src/components/editor/properties/link/index.tsx b/packages/ui/src/components/editor/properties/link/index.tsx index 05ae4d251a..d5bcccbad7 100644 --- a/packages/ui/src/components/editor/properties/link/index.tsx +++ b/packages/ui/src/components/editor/properties/link/index.tsx @@ -23,16 +23,21 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ -import React from 'react' +import React, { useEffect } from 'react' import { useTranslation } from 'react-i18next' import { PiLinkBreak } from 'react-icons/pi' -import { useComponent } from '@etherealengine/ecs' +import { getComponent, hasComponent, useComponent, UUIDComponent } from '@etherealengine/ecs' import { - EditorComponentType, commitProperty, + EditorComponentType, updateProperty } from '@etherealengine/editor/src/components/properties/Util' +import { EditorControlFunctions } from '@etherealengine/editor/src/functions/EditorControlFunctions' +import { + InteractableComponent, + XRUIActivationType +} from '@etherealengine/engine/src/interaction/components/InteractableComponent' import { getEntityErrors } from '@etherealengine/engine/src/scene/components/ErrorComponent' import { LinkComponent } from '@etherealengine/engine/src/scene/components/LinkComponent' import BooleanInput from '../../input/Boolean' @@ -49,6 +54,23 @@ export const LinkNodeEditor: EditorComponentType = (props) => { const linkComponent = useComponent(props.entity, LinkComponent) const errors = getEntityErrors(props.entity, LinkComponent) + useEffect(() => { + if (!hasComponent(props.entity, InteractableComponent)) { + EditorControlFunctions.addOrRemoveComponent([props.entity], InteractableComponent, true, { + label: LinkComponent.interactMessage, + uiInteractable: false, + clickInteract: true, + uiActivationType: XRUIActivationType.hover, + callbacks: [ + { + callbackID: LinkComponent.linkCallbackName, + target: getComponent(props.entity, UUIDComponent) + } + ] + }) + } + }, []) + return ( { const { t } = useTranslation() const mountComponent = useComponent(props.entity, MountPointComponent) - + const onChangeOffset = (value: Vector3) => { + getMutableComponent(props.entity, MountPointComponent).dismountOffset.set(value) + } + useEffect(() => { + if (!hasComponent(props.entity, InteractableComponent)) { + const mountPoint = getComponent(props.entity, MountPointComponent) + EditorControlFunctions.addOrRemoveComponent([props.entity], InteractableComponent, true, { + label: MountPointComponent.mountPointInteractMessages[mountPoint.type], + callbacks: [ + { + callbackID: MountPointComponent.mountCallbackName, + target: getComponent(props.entity, UUIDComponent) + } + ] + }) + } + }, []) return (