From eff3c1bdb26c61a345325363225da5a466fc90a2 Mon Sep 17 00:00:00 2001 From: fengyuzhe Date: Tue, 12 May 2026 11:00:31 +0800 Subject: [PATCH] SelectService broadcasts an event, changing the UUID parameter to node path. --- src/core/scene/common/selection.ts | 4 +- .../service/core/base-service.ts | 4 +- .../scene/scene-process/service/engine.ts | 31 +++++++----- src/core/scene/scene-process/service/gizmo.ts | 47 +++++++++++-------- src/core/scene/scene-process/service/node.ts | 4 +- .../scene/scene-process/service/particle.ts | 16 +++++-- .../scene/scene-process/service/selection.ts | 40 ++++++++++++---- tests/__snapshots__/dts-snapshot.test.ts.snap | 8 ++-- 8 files changed, 98 insertions(+), 56 deletions(-) diff --git a/src/core/scene/common/selection.ts b/src/core/scene/common/selection.ts index 19a69ad4c..cf945a524 100644 --- a/src/core/scene/common/selection.ts +++ b/src/core/scene/common/selection.ts @@ -12,7 +12,7 @@ export type IPublicSelectionService = Pick; export interface ISelectionEvents { - 'selection:select': [uuid: string, uuids: string[]]; - 'selection:unselect': [uuid: string, uuids: string[]]; + 'selection:select': [path: string, paths: string[]]; + 'selection:unselect': [path: string, paths: string[]]; 'selection:clear': []; } diff --git a/src/core/scene/scene-process/service/core/base-service.ts b/src/core/scene/scene-process/service/core/base-service.ts index 4a7860be5..e5eb0f6d2 100644 --- a/src/core/scene/scene-process/service/core/base-service.ts +++ b/src/core/scene/scene-process/service/core/base-service.ts @@ -40,8 +40,8 @@ export interface IServiceEvents { onScriptExecutionFinished?(): void; // Selection events - onSelectionSelect?(uuid: string, uuids: string[]): void; - onSelectionUnselect?(uuid: string, uuids: string[]): void; + onSelectionSelect?(path: string, paths: string[]): void; + onSelectionUnselect?(path: string, paths: string[]): void; onSelectionClear?(): void; } diff --git a/src/core/scene/scene-process/service/engine.ts b/src/core/scene/scene-process/service/engine.ts index 4f89c9bbb..9143f6e68 100644 --- a/src/core/scene/scene-process/service/engine.ts +++ b/src/core/scene/scene-process/service/engine.ts @@ -194,6 +194,11 @@ export class EngineService extends BaseService implements IEngine this._capture = b; } + private _getNodeByPath(path: string): Node | null { + const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; + return EditorExtends?.Node?.getNodeByPath?.(path) ?? null; + } + private _getNodeByUuid(uuid: string): Node | null { const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; return EditorExtends?.Node?.getNode?.(uuid) ?? null; @@ -232,7 +237,6 @@ export class EngineService extends BaseService implements IEngine const nodeUuids = Service.Selection?.query?.() ?? []; if (comp.node && nodeUuids.includes(comp.node.uuid)) { this.checkToSetAnimState([comp.node]); - // 与 cocos-editor ParticleManager 一致:新增的粒子组件自动播放 if (this._isParticleSystem3D(comp) && !(comp as any).isPlaying) { (comp as any).play(); } @@ -253,28 +257,29 @@ export class EngineService extends BaseService implements IEngine } // 与 cocos-editor SceneSelection 一致:选中/反选时检查粒子/地形组件 - onSelectionSelect(uuid: string, uuids: string[]) { - const selectedUuids = uuids?.length ? uuids : (Service.Selection?.query?.() ?? []); + onSelectionSelect(path: string, paths: string[]) { const nodes: Node[] = []; - for (const uid of selectedUuids) { - const node = this._getNodeByUuid(uid); + for (const p of paths) { + const node = this._getNodeByPath(p); if (node) nodes.push(node); } this.checkToSetAnimState(nodes); - this._playParticlesOnSelect(selectedUuids); + const uuids = nodes.map(n => n.uuid); + this._playParticlesOnSelect(uuids); void this.repaintInEditMode(); } - onSelectionUnselect(uuid: string, uuids: string[]) { - const selectedUuids = uuids?.length ? uuids : (Service.Selection?.query?.() ?? []); - const remaining = selectedUuids.filter((uid: string) => uid !== uuid); + onSelectionUnselect(path: string, paths: string[]) { + const unselectedNode = this._getNodeByPath(path); const nodes: Node[] = []; - for (const uid of remaining) { - const node = this._getNodeByUuid(uid); + for (const p of paths) { + const node = this._getNodeByPath(p); if (node) nodes.push(node); } - this.checkToSetAnimState(nodes); - this._pauseParticlesOnUnselect(selectedUuids); + const remaining = nodes.filter(n => n !== unselectedNode); + this.checkToSetAnimState(remaining); + const uuids = nodes.map(n => n.uuid); + this._pauseParticlesOnUnselect(uuids); void this.repaintInEditMode(); } diff --git a/src/core/scene/scene-process/service/gizmo.ts b/src/core/scene/scene-process/service/gizmo.ts index 791e80fdc..ed7e24f94 100644 --- a/src/core/scene/scene-process/service/gizmo.ts +++ b/src/core/scene/scene-process/service/gizmo.ts @@ -107,11 +107,21 @@ function walkNodeComponent(node: Node, callback: (comp: Component) => void): voi } } +function getNodeByPath(path: string): Node | null { + const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; + return EditorExtends?.Node?.getNodeByPath?.(path) ?? null; +} + function getNodeByUuid(uuid: string): Node | null { const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; return EditorExtends?.Node?.getNode?.(uuid) ?? null; } +function getNodePath(node: Node): string { + const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; + return EditorExtends?.Node?.getNodePath?.(node) ?? ''; +} + @register('Gizmo') export class GizmoService extends BaseService implements IGizmoService { gizmoRootNode!: Node; @@ -190,11 +200,11 @@ export class GizmoService extends BaseService implements IGizmoSer } // 与 cocos-editor 一致:直接监听 Selection 事件 - ServiceEvents.on('selection:select', (uuid: string) => { - this.onSelectionSelect(uuid); + ServiceEvents.on('selection:select', (path: string) => { + this.onSelectionSelect(path); }); - ServiceEvents.on('selection:unselect', (uuid: string) => { - this.onSelectionUnselect(uuid); + ServiceEvents.on('selection:unselect', (path: string) => { + this.onSelectionUnselect(path); }); ServiceEvents.on('selection:clear', () => { this.onSelectionClear(); @@ -366,32 +376,31 @@ export class GizmoService extends BaseService implements IGizmoSer // ── Selection integration ─────────────────────────────────────────────────── - onSelectionSelect(uuid: string): void { + onSelectionSelect(path: string): void { + const node = getNodeByPath(path); + if (!node) return; + const uuid = node.uuid; if (this._selection.includes(uuid)) return; this._selection.push(uuid); try { - const node = getNodeByUuid(uuid); - if (node) { - this.showAllGizmoOfNode(node); - this._onNodeSelectionChanged(node, true); - } + this.showAllGizmoOfNode(node); + this._onNodeSelectionChanged(node, true); } catch (e) { // Scene not ready } } - onSelectionUnselect(uuid: string): void { + onSelectionUnselect(path: string): void { + const node = getNodeByPath(path); + if (!node) return; + const uuid = node.uuid; const idx = this._selection.indexOf(uuid); if (idx >= 0) this._selection.splice(idx, 1); try { - const node = getNodeByUuid(uuid); - if (node) { - this._onNodeSelectionChanged(node, false); - // Only remove component gizmos on unselect, keep icon/persistent - walkNodeComponent(node, (component: Component) => { - this._removeGizmo('component', component); - }); - } + this._onNodeSelectionChanged(node, false); + walkNodeComponent(node, (component: Component) => { + this._removeGizmo('component', component); + }); } catch (e) { // Scene not ready } diff --git a/src/core/scene/scene-process/service/node.ts b/src/core/scene/scene-process/service/node.ts index cbb2ba131..fc37e7698 100644 --- a/src/core/scene/scene-process/service/node.ts +++ b/src/core/scene/scene-process/service/node.ts @@ -46,7 +46,7 @@ export class NodeService extends BaseService implements INodeServic canvasNeeded = paramsArray[0].canvasRequired ? true : false; const projectType = paramsArray[0]['project-type']; const workMode = params.workMode; - if (projectType && workMode && projectType !== workMode && paramsArray.length > 1) { + if (projectType && workMode && projectType !== workMode.toLowerCase() && paramsArray.length > 1) { assetUuid = paramsArray[1]['assetUuid'] || null; canvasNeeded = paramsArray[1].canvasRequired ? true : false; } @@ -96,7 +96,7 @@ export class NodeService extends BaseService implements INodeServic canvasRequired: canvasNeeded }); resultNode = node; - parent = await this.checkCanvasRequired(workMode, Boolean(canvasRequired), parent, params.position as Vec3) as Node; + parent = await this.checkCanvasRequired(workMode.toLowerCase(), Boolean(canvasRequired), parent, params.position as Vec3) as Node; } if (!resultNode) { resultNode = new cc.Node(); diff --git a/src/core/scene/scene-process/service/particle.ts b/src/core/scene/scene-process/service/particle.ts index 545b9769f..3b1c17656 100644 --- a/src/core/scene/scene-process/service/particle.ts +++ b/src/core/scene/scene-process/service/particle.ts @@ -3,6 +3,11 @@ import { Component, Node } from 'cc'; import { BaseService, register } from './core'; +function getNodeByPath(path: string): Node | null { + const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; + return EditorExtends?.Node?.getNodeByPath?.(path) ?? null; +} + function getNodeByUuid(uuid: string): Node | null { const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; return EditorExtends?.Node?.getNode?.(uuid) ?? null; @@ -73,8 +78,8 @@ export class ParticleService extends BaseService> { return result.filter((comp: any) => comp.enabled); } - onSelectionSelect(uuid: string, uuids: string[]) { - this._selectedUUIDs = uuids.slice(); + onSelectionSelect(path: string, paths: string[]) { + this._selectedUUIDs = paths.map(p => getNodeByPath(p)?.uuid).filter(Boolean) as string[]; const components = this._getSelectedParticleSystemComponents(); const willPlay = components.some(item => !this._stoppedSet.has(item)); if (willPlay) { @@ -87,13 +92,14 @@ export class ParticleService extends BaseService> { }); } - onSelectionUnselect(uuid: string, uuids: string[]) { + onSelectionUnselect(path: string, paths: string[]) { + const remainingUuids = paths.map(p => getNodeByPath(p)?.uuid).filter(Boolean) as string[]; this._getSelectedParticleSystemComponents().forEach((ps: any) => { - if (!uuids.includes(ps.node.uuid) && ps.isPlaying) { + if (!remainingUuids.includes(ps.node.uuid) && ps.isPlaying) { ps.pause(); } }); - this._selectedUUIDs = uuids.slice(); + this._selectedUUIDs = remainingUuids; } onSelectionClear() { diff --git a/src/core/scene/scene-process/service/selection.ts b/src/core/scene/scene-process/service/selection.ts index fc0e301c0..2776cae6c 100644 --- a/src/core/scene/scene-process/service/selection.ts +++ b/src/core/scene/scene-process/service/selection.ts @@ -2,6 +2,22 @@ import { BaseService } from './core'; import { register } from './core/decorator'; import type { ISelectionService, ISelectionEvents } from '../../common'; +function getNodeMgr() { + return ((cc as any).EditorExtends || (globalThis as any).EditorExtends)?.Node; +} + +function uuidToPath(uuid: string): string { + const NodeMgr = getNodeMgr(); + if (!NodeMgr) return ''; + const node = NodeMgr.getNode?.(uuid); + if (!node) return ''; + return NodeMgr.getNodePath(node) ?? ''; +} + +function uuidsToPath(uuids: string[]): string[] { + return uuids.map(uuidToPath).filter(Boolean); +} + @register('Selection') export class SelectionService extends BaseService implements ISelectionService { private _uuids: string[] = []; @@ -11,7 +27,9 @@ export class SelectionService extends BaseService implements I if (index !== -1) return; this._uuids.unshift(uuid); this._callFocusInEditor(uuid); - this.broadcast('selection:select', uuid, this._uuids.slice()); + const path = uuidToPath(uuid); + const paths = uuidsToPath(this._uuids); + this.broadcast('selection:select', path, paths); } unselect(uuid: string): void { @@ -19,7 +37,9 @@ export class SelectionService extends BaseService implements I if (index === -1) return; this._uuids.splice(index, 1); this._callLostFocusInEditor(uuid); - this.broadcast('selection:unselect', uuid, this._uuids.slice()); + const path = uuidToPath(uuid); + const paths = uuidsToPath(this._uuids); + this.broadcast('selection:unselect', path, paths); } clear(): void { @@ -27,7 +47,9 @@ export class SelectionService extends BaseService implements I const uuid = this._uuids.shift(); if (uuid) { this._callLostFocusInEditor(uuid); - this.emit('selection:unselect', uuid, this._uuids.slice()); + const path = uuidToPath(uuid); + const paths = uuidsToPath(this._uuids); + this.emit('selection:unselect', path, paths); } } this.broadcast('selection:clear'); @@ -47,9 +69,9 @@ export class SelectionService extends BaseService implements I private _callFocusInEditor(uuid: string): void { try { - const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; - if (!EditorExtends) return; - const node = EditorExtends.Node.getNode(uuid); + const NodeMgr = getNodeMgr(); + if (!NodeMgr) return; + const node = NodeMgr.getNode(uuid); if (!node?._components) return; for (const comp of node.components) { if (comp?.onFocusInEditor) { @@ -63,9 +85,9 @@ export class SelectionService extends BaseService implements I private _callLostFocusInEditor(uuid: string): void { try { - const EditorExtends = (cc as any).EditorExtends || (globalThis as any).EditorExtends; - if (!EditorExtends) return; - const node = EditorExtends.Node.getNode(uuid); + const NodeMgr = getNodeMgr(); + if (!NodeMgr) return; + const node = NodeMgr.getNode(uuid); if (!node?._components) return; for (const comp of node.components) { if (comp?.onLostFocusInEditor) { diff --git a/tests/__snapshots__/dts-snapshot.test.ts.snap b/tests/__snapshots__/dts-snapshot.test.ts.snap index de58824e8..416ec3835 100644 --- a/tests/__snapshots__/dts-snapshot.test.ts.snap +++ b/tests/__snapshots__/dts-snapshot.test.ts.snap @@ -5708,8 +5708,8 @@ export declare interface IServiceEvents { onAssetChanged?(uuid: string): void; onAssetRefreshed?(uuid: string): void; onScriptExecutionFinished?(): void; - onSelectionSelect?(uuid: string, uuids: string[]): void; - onSelectionUnselect?(uuid: string, uuids: string[]): void; + onSelectionSelect?(path: string, paths: string[]): void; + onSelectionUnselect?(path: string, paths: string[]): void; onSelectionClear?(): void; } export declare interface IServiceManager { @@ -7760,8 +7760,8 @@ export declare interface IServiceEvents { onAssetChanged?(uuid: string): void; onAssetRefreshed?(uuid: string): void; onScriptExecutionFinished?(): void; - onSelectionSelect?(uuid: string, uuids: string[]): void; - onSelectionUnselect?(uuid: string, uuids: string[]): void; + onSelectionSelect?(path: string, paths: string[]): void; + onSelectionUnselect?(path: string, paths: string[]): void; onSelectionClear?(): void; } export declare interface IServiceManager {