diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.spec.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.spec.ts index 256094d8c..75a77c6cc 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.spec.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.spec.ts @@ -9,6 +9,9 @@ const getContext = () => ({ componentPutOperations: { [Transform.componentId]: jest.fn() }, + componentDeleteOperations: { + [Transform.componentId]: jest.fn() + }, engine: { RootEntity: 0 as Entity } @@ -71,7 +74,7 @@ describe('EcsEntity', () => { const Transform = components.Transform(engine) entity.deleteComponent(Transform) expect(entity.usedComponents.size).toBe(0) - expect(mockedContext.componentPutOperations[Transform.componentId]).toBeCalledWith(entity, Transform) + expect(mockedContext.componentDeleteOperations[Transform.componentId]).toBeCalledWith(entity, Transform) }) it('components and native engine', () => { diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.ts index 779235200..344020f8f 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/EcsEntity.ts @@ -46,13 +46,17 @@ export class EcsEntity extends BABYLON.TransformNode { } putComponent(component: ComponentDefinition) { + const ctx = this.context.deref()! + const operation = ctx.componentPutOperations[component.componentId] this.usedComponents.set(component.componentId, component) - this.context.deref()!.componentPutOperations[component.componentId]?.call(null, this, component) + operation?.call(null, this, component) } deleteComponent(component: ComponentDefinition) { + const ctx = this.context.deref()! + const operation = ctx.componentDeleteOperations[component.componentId] this.usedComponents.delete(component.componentId) - this.context.deref()!.componentPutOperations[component.componentId]?.call(null, this, component) + operation?.call(null, this, component) } /** diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/SceneContext.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/SceneContext.ts index 23fe803e2..41efa8b42 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/SceneContext.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/SceneContext.ts @@ -7,7 +7,7 @@ import future from 'fp-future' import { createEditorComponents } from '../../sdk/components' import { ComponentOperation } from './component-operations' import { EcsEntity } from './EcsEntity' -import { putEntitySelectedComponent } from './editorComponents/selection' +import { deleteEntitySelectedComponent, putEntitySelectedComponent } from './editorComponents/selection' import { putBillboardComponent } from './sdkComponents/billboard' import { putGltfContainerComponent } from './sdkComponents/gltf-container' import { putMeshRendererComponent } from './sdkComponents/mesh-renderer' @@ -77,6 +77,21 @@ export class SceneContext { [this.editorComponents.Lock.componentId]: putLockComponent } + readonly componentDeleteOperations: Record = { + [this.Transform.componentId]: putTransformComponent, + [this.MeshRenderer.componentId]: putMeshRendererComponent, + [this.Material.componentId]: putMaterialComponent, + [this.Billboard.componentId]: putBillboardComponent, + [this.GltfContainer.componentId]: putGltfContainerComponent, + [this.TextShape.componentId]: putTextShapeComponent, + [this.NftShape.componentId]: putNftShapeComponent, + [this.VideoPlayer.componentId]: putVideoPlayerComponent, + [this.editorComponents.Selection.componentId]: deleteEntitySelectedComponent, + [this.editorComponents.Scene.componentId]: putSceneComponent, + [this.editorComponents.Hide.componentId]: putHideComponent, + [this.editorComponents.Lock.componentId]: putLockComponent + } + // this future is resolved when the scene is disposed readonly stopped = future() diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/hide.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/hide.ts index be699b353..4c63eb300 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/hide.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/hide.ts @@ -1,6 +1,6 @@ import { ComponentType } from '@dcl/ecs' import type { ComponentOperation } from '../component-operations' -import { updateGizmoManager } from './selection' +import { setGizmoManager, unsetGizmoManager } from './selection' export const putHideComponent: ComponentOperation = (entity, component) => { const container = entity.gltfContainer ?? entity.meshRenderer @@ -11,10 +11,10 @@ export const putHideComponent: ComponentOperation = (entity, component) => { const { value: isHidden } = (component.getOrNull(entity.entityId) as { value: boolean } | null) ?? {} container.setEnabled(!isHidden) if (isHidden) { - context.gizmos.unsetEntity() + unsetGizmoManager(entity) } else { const selectionValue = context.editorComponents.Selection.getOrNull(entity.entityId) - updateGizmoManager(entity, selectionValue) + if (selectionValue) setGizmoManager(entity, selectionValue) } } } diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/lock.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/lock.ts index 14845f9a0..f5673613d 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/lock.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/lock.ts @@ -1,6 +1,6 @@ import { ComponentType } from '@dcl/ecs' import type { ComponentOperation } from '../component-operations' -import { toggleSelection, updateGizmoManager } from './selection' +import { setGizmoManager, unsetGizmoManager } from './selection' export const putLockComponent: ComponentOperation = (entity, component) => { if (component.componentType === ComponentType.LastWriteWinElementSet) { @@ -8,12 +8,10 @@ export const putLockComponent: ComponentOperation = (entity, component) => { const { value: isLocked } = (component.getOrNull(entity.entityId) as { value: boolean } | null) ?? {} entity.setLock(!!isLocked) if (isLocked) { - toggleSelection(entity, false) - context.gizmos.unsetEntity() + unsetGizmoManager(entity) } else { const selectionValue = context.editorComponents.Selection.getOrNull(entity.entityId) - toggleSelection(entity, !!selectionValue) - updateGizmoManager(entity, selectionValue) + if (selectionValue) setGizmoManager(entity, selectionValue) } } } diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/selection.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/selection.ts index 41a395ebc..5ef0293db 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/selection.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/editorComponents/selection.ts @@ -1,6 +1,6 @@ -import { AbstractMesh, Color3, Gizmo } from '@babylonjs/core' +import { AbstractMesh, Color3 } from '@babylonjs/core' import { ComponentType } from '@dcl/ecs' -import { CoreComponents } from '../../../sdk/components' +import { CoreComponents, EditorComponentsTypes } from '../../../sdk/components' import { EcsEntity } from '../EcsEntity' import type { ComponentOperation } from '../component-operations' @@ -8,9 +8,16 @@ const highlightedMeshes = new Set() export const putEntitySelectedComponent: ComponentOperation = (entity, component) => { if (component.componentType === ComponentType.LastWriteWinElementSet) { - const componentValue = entity.isLocked() ? null : (component.getOrNull(entity.entityId) as { gizmo: number } | null) - toggleSelection(entity, !!componentValue) - updateGizmoManager(entity, componentValue) + if (entity.isLocked()) return deleteEntitySelectedComponent(entity, component) + + const componentValue = component.get(entity.entityId) as unknown as EditorComponentsTypes['Selection'] + setGizmoManager(entity, componentValue) + } +} + +export const deleteEntitySelectedComponent: ComponentOperation = (entity, component) => { + if (component.componentType === ComponentType.LastWriteWinElementSet) { + unsetGizmoManager(entity) } } @@ -38,26 +45,36 @@ export const toggleSelection = (entity: EcsEntity, value: boolean) => { } } -export const updateGizmoManager = (entity: EcsEntity, value: { gizmo: number } | null) => { +export const setGizmoManager = (entity: EcsEntity, value: { gizmo: number }) => { const context = entity.context.deref()! - const Transform = context.engine.getComponent(CoreComponents.TRANSFORM) + + if (!Transform.has(entity.entityId)) return + + toggleSelection(entity, true) + const selectedEntities = Array.from(context.engine.getEntitiesWith(context.editorComponents.Selection)) + const types = context.gizmos.getGizmoTypes() + const type = types[value?.gizmo || 0] + context.gizmos.setGizmoType(type) - for (const [_entity] of selectedEntities) { - if (entity.entityId === _entity && Transform.has(_entity)) { - context.gizmos.setEntity(entity) - const types = context.gizmos.getGizmoTypes() - const type = types[value?.gizmo || 0] - context.gizmos.setGizmoType(type) - return - } + if (selectedEntities.length === 1) { + context.gizmos.setEntity(entity) + } else if (selectedEntities.length > 1) { + context.gizmos.repositionGizmoOnCentroid() } +} + +export const unsetGizmoManager = (entity: EcsEntity) => { + const context = entity.context.deref()! + const selectedEntities = Array.from(context.engine.getEntitiesWith(context.editorComponents.Selection)) + const currentEntity = context.gizmos.getEntity() + + toggleSelection(entity, false) - if (selectedEntities.length === 0) { + if (currentEntity?.entityId === entity.entityId || selectedEntities.length === 0) { context.gizmos.unsetEntity() } else { - // TODO: this will also execute when only one entity is selected, it works but it's not optimal... context.gizmos.repositionGizmoOnCentroid() } } diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/gizmo-manager.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/gizmo-manager.ts index 1fa7df108..55ec7b6f9 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/gizmo-manager.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/gizmo-manager.ts @@ -18,7 +18,7 @@ import { SceneContext } from './SceneContext' import { PatchedGizmoManager } from './gizmo-patch' import { ROOT } from '../../sdk/tree' -const GIZMO_DUMMY_NODE = "GIZMO_DUMMY_NODE" +const GIZMO_DUMMY_NODE = 'GIZMO_DUMMY_NODE' interface GizmoAxis { xGizmo: IAxisDragGizmo @@ -43,17 +43,14 @@ function areQuaternionsEqual(a: DclQuaternion, b: DclQuaternion) { } function calculateCenter(positions: Vector3[]): Vector3 { - if (positions.length === 0) throw new Error("No positions provided to calculate center") - - const sum = positions.reduce( - (acc, pos) => { - acc.x += pos.x - acc.y += pos.y - acc.z += pos.z - return acc - }, - new Vector3(0, 0, 0) - ) + if (positions.length === 0) throw new Error('No positions provided to calculate center') + + const sum = positions.reduce((acc, pos) => { + acc.x += pos.x + acc.y += pos.y + acc.z += pos.z + return acc + }, new Vector3(0, 0, 0)) return sum.scale(1 / positions.length) } @@ -200,7 +197,7 @@ export function createGizmoManager(context: SceneContext) { } // Map to store the original parent of each entity - const originalParents = new Map(); + const originalParents = new Map() // Check if a transform node for the gizmo already exists, or create one function getDummyNode(): TransformNode { @@ -375,7 +372,7 @@ export function createGizmoManager(context: SceneContext) { return isEnabled }, setEnabled, - setEntity(entity: EcsEntity | null) { + setEntity(entity: EcsEntity | null): void { if ( entity === lastEntity || !isEnabled || @@ -387,8 +384,7 @@ export function createGizmoManager(context: SceneContext) { } restoreOriginalParents() if (areMultipleEntitiesSelected()) { - repositionGizmoOnCentroid() - return + return repositionGizmoOnCentroid() } else { gizmoManager.attachToNode(entity) lastEntity = entity