Feature/editor optimization (#251)

* refactor: 编辑器/运行时架构拆分与构建系统升级

* feat(core): 层级系统重构与UI变换矩阵修复

* refactor: 移除 ecs-components 聚合包并修复跨包组件查找问题

* fix(physics): 修复跨包组件类引用问题

* feat: 统一运行时架构与浏览器运行支持

* feat(asset): 实现浏览器运行时资产加载系统

* fix: 修复文档、CodeQL安全问题和CI类型检查错误

* fix: 修复文档、CodeQL安全问题和CI类型检查错误

* fix: 修复文档、CodeQL安全问题、CI类型检查和测试错误

* test: 补齐核心模块测试用例,修复CI构建配置

* fix: 修复测试用例中的类型错误和断言问题

* fix: 修复 turbo build:npm 任务的依赖顺序问题

* fix: 修复 CI 构建错误并优化构建性能
This commit is contained in:
YHH
2025-12-01 22:28:51 +08:00
committed by GitHub
parent 189714c727
commit b42a7b4e43
468 changed files with 18301 additions and 9075 deletions

View File

@@ -0,0 +1,194 @@
import { Core, Entity, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
import { BaseCommand } from '../BaseCommand';
/**
* 拖放位置类型
*/
export enum DropPosition {
/** 在目标之前 */
BEFORE = 'before',
/** 在目标内部(作为子级) */
INSIDE = 'inside',
/** 在目标之后 */
AFTER = 'after'
}
/**
* 重新设置实体父级命令
*
* 支持拖拽重排功能,可以将实体移动到:
* - 另一个实体之前 (BEFORE)
* - 另一个实体内部作为子级 (INSIDE)
* - 另一个实体之后 (AFTER)
*/
export class ReparentEntityCommand extends BaseCommand {
private oldParentId: number | null;
private oldSiblingIndex: number;
constructor(
private entityStore: EntityStoreService,
private messageHub: MessageHub,
private entity: Entity,
private targetEntity: Entity,
private dropPosition: DropPosition
) {
super();
// 保存原始状态用于撤销
const hierarchy = entity.getComponent(HierarchyComponent);
this.oldParentId = hierarchy?.parentId ?? null;
// 获取在兄弟列表中的原始索引
this.oldSiblingIndex = this.getSiblingIndex(entity);
}
execute(): void {
const scene = Core.scene;
if (!scene) {
console.warn('[ReparentEntityCommand] No scene available');
return;
}
const hierarchySystem = scene.getSystem(HierarchySystem);
if (!hierarchySystem) {
console.warn('[ReparentEntityCommand] No HierarchySystem found');
return;
}
// 确保目标实体有 HierarchyComponent
if (!this.targetEntity.getComponent(HierarchyComponent)) {
this.targetEntity.addComponent(new HierarchyComponent());
}
console.log(`[ReparentEntityCommand] Moving ${this.entity.name} to ${this.targetEntity.name} (${this.dropPosition})`);
switch (this.dropPosition) {
case DropPosition.INSIDE:
// 移动到目标实体内部作为最后一个子级
hierarchySystem.setParent(this.entity, this.targetEntity);
break;
case DropPosition.BEFORE:
case DropPosition.AFTER:
// 移动到目标实体的同级
this.moveToSibling(hierarchySystem);
break;
}
this.entityStore.syncFromScene();
this.messageHub.publish('entity:reparented', {
entityId: this.entity.id,
targetId: this.targetEntity.id,
position: this.dropPosition
});
}
undo(): void {
const scene = Core.scene;
if (!scene) return;
const hierarchySystem = scene.getSystem(HierarchySystem);
if (!hierarchySystem) return;
// 恢复到原始父级
const oldParent = this.oldParentId !== null
? scene.findEntityById(this.oldParentId)
: null;
if (oldParent) {
// 恢复到原始父级的指定位置
hierarchySystem.insertChildAt(oldParent, this.entity, this.oldSiblingIndex);
} else {
// 恢复到根级
hierarchySystem.setParent(this.entity, null);
}
this.entityStore.syncFromScene();
this.messageHub.publish('entity:reparented', {
entityId: this.entity.id,
targetId: null,
position: 'undo'
});
}
getDescription(): string {
const positionText = this.dropPosition === DropPosition.INSIDE
? '移入'
: this.dropPosition === DropPosition.BEFORE ? '移动到前面' : '移动到后面';
return `${positionText}: ${this.entity.name} -> ${this.targetEntity.name}`;
}
/**
* 移动到目标的同级位置
*/
private moveToSibling(hierarchySystem: HierarchySystem): void {
const targetHierarchy = this.targetEntity.getComponent(HierarchyComponent);
const targetParentId = targetHierarchy?.parentId ?? null;
const scene = Core.scene;
if (!scene) return;
// 获取目标的父实体
const targetParent = targetParentId !== null
? scene.findEntityById(targetParentId)
: null;
// 获取目标在兄弟列表中的索引
let targetIndex = this.getSiblingIndex(this.targetEntity);
// 根据放置位置调整索引
if (this.dropPosition === DropPosition.AFTER) {
targetIndex++;
}
// 如果移动到同一父级下,需要考虑原位置对索引的影响
const entityHierarchy = this.entity.getComponent(HierarchyComponent);
const entityParentId = entityHierarchy?.parentId ?? null;
const bSameParent = entityParentId === targetParentId;
if (bSameParent) {
const currentIndex = this.getSiblingIndex(this.entity);
if (currentIndex < targetIndex) {
targetIndex--;
}
}
console.log(`[ReparentEntityCommand] moveToSibling: targetParent=${targetParent?.name ?? 'ROOT'}, targetIndex=${targetIndex}`);
if (targetParent) {
// 有父级,插入到父级的指定位置
hierarchySystem.insertChildAt(targetParent, this.entity, targetIndex);
} else {
// 目标在根级
// 先确保实体移动到根级
if (entityParentId !== null) {
hierarchySystem.setParent(this.entity, null);
}
// 然后调整根级顺序
this.entityStore.reorderEntity(this.entity.id, targetIndex);
}
}
/**
* 获取实体在兄弟列表中的索引
*/
private getSiblingIndex(entity: Entity): number {
const scene = Core.scene;
if (!scene) return 0;
const hierarchy = entity.getComponent(HierarchyComponent);
const parentId = hierarchy?.parentId;
if (parentId === null || parentId === undefined) {
// 根级实体,从 EntityStoreService 获取
return this.entityStore.getRootEntityIds().indexOf(entity.id);
}
const parent = scene.findEntityById(parentId);
if (!parent) return 0;
const parentHierarchy = parent.getComponent(HierarchyComponent);
return parentHierarchy?.childIds.indexOf(entity.id) ?? 0;
}
}