Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/core/scene/common/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type IPublicSelectionService = Pick<ISelectionService,
>;

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': [];
}
4 changes: 2 additions & 2 deletions src/core/scene/scene-process/service/core/base-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
31 changes: 18 additions & 13 deletions src/core/scene/scene-process/service/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ export class EngineService extends BaseService<IEngineEvents> 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;
Expand Down Expand Up @@ -232,7 +237,6 @@ export class EngineService extends BaseService<IEngineEvents> 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();
}
Expand All @@ -253,28 +257,29 @@ export class EngineService extends BaseService<IEngineEvents> 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();
}

Expand Down
47 changes: 28 additions & 19 deletions src/core/scene/scene-process/service/gizmo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<IGizmoEvents> implements IGizmoService {
gizmoRootNode!: Node;
Expand Down Expand Up @@ -190,11 +200,11 @@ export class GizmoService extends BaseService<IGizmoEvents> 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();
Expand Down Expand Up @@ -366,32 +376,31 @@ export class GizmoService extends BaseService<IGizmoEvents> 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
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/scene/scene-process/service/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class NodeService extends BaseService<INodeEvents> 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;
}
Expand Down Expand Up @@ -96,7 +96,7 @@ export class NodeService extends BaseService<INodeEvents> 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();
Expand Down
16 changes: 11 additions & 5 deletions src/core/scene/scene-process/service/particle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -73,8 +78,8 @@ export class ParticleService extends BaseService<Record<string, never>> {
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) {
Expand All @@ -87,13 +92,14 @@ export class ParticleService extends BaseService<Record<string, never>> {
});
}

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() {
Expand Down
40 changes: 31 additions & 9 deletions src/core/scene/scene-process/service/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ISelectionEvents> implements ISelectionService {
private _uuids: string[] = [];
Expand All @@ -11,23 +27,29 @@ export class SelectionService extends BaseService<ISelectionEvents> 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 {
const index = this._uuids.indexOf(uuid);
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 {
while (this._uuids.length > 0) {
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');
Expand All @@ -47,9 +69,9 @@ export class SelectionService extends BaseService<ISelectionEvents> 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) {
Expand All @@ -63,9 +85,9 @@ export class SelectionService extends BaseService<ISelectionEvents> 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) {
Expand Down
8 changes: 4 additions & 4 deletions tests/__snapshots__/dts-snapshot.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
Loading