feat: 集成Rust WASM渲染引擎与TypeScript ECS框架 (#228)

* feat: 集成Rust WASM渲染引擎与TypeScript ECS框架

* feat: 增强编辑器UI功能与跨平台支持

* fix: 修复CI测试和类型检查问题

* fix: 修复CI问题并提高测试覆盖率

* fix: 修复CI问题并提高测试覆盖率
This commit is contained in:
YHH
2025-11-21 10:03:18 +08:00
committed by GitHub
parent 8b9616837d
commit a768b890fd
107 changed files with 10221 additions and 477 deletions

View File

@@ -0,0 +1,54 @@
import { Entity, Component } from '@esengine/ecs-framework';
import { MessageHub } from '@esengine/editor-core';
import { BaseCommand } from '../BaseCommand';
/**
* 添加组件命令
*/
export class AddComponentCommand extends BaseCommand {
private component: Component | null = null;
constructor(
private messageHub: MessageHub,
private entity: Entity,
private ComponentClass: new () => Component,
private initialData?: Record<string, unknown>
) {
super();
}
execute(): void {
this.component = new this.ComponentClass();
// 应用初始数据
if (this.initialData) {
for (const [key, value] of Object.entries(this.initialData)) {
(this.component as any)[key] = value;
}
}
this.entity.addComponent(this.component);
this.messageHub.publish('component:added', {
entity: this.entity,
component: this.component
});
}
undo(): void {
if (!this.component) return;
this.entity.removeComponent(this.component);
this.messageHub.publish('component:removed', {
entity: this.entity,
componentType: this.ComponentClass.name
});
this.component = null;
}
getDescription(): string {
return `添加组件: ${this.ComponentClass.name}`;
}
}

View File

@@ -0,0 +1,57 @@
import { Entity, Component } from '@esengine/ecs-framework';
import { MessageHub } from '@esengine/editor-core';
import { BaseCommand } from '../BaseCommand';
/**
* 移除组件命令
*/
export class RemoveComponentCommand extends BaseCommand {
private componentData: Record<string, unknown> = {};
private ComponentClass: new () => Component;
constructor(
private messageHub: MessageHub,
private entity: Entity,
private component: Component
) {
super();
this.ComponentClass = component.constructor as new () => Component;
// 保存组件数据用于撤销
for (const key of Object.keys(component)) {
if (key !== 'entity' && key !== 'id') {
this.componentData[key] = (component as any)[key];
}
}
}
execute(): void {
this.entity.removeComponent(this.component);
this.messageHub.publish('component:removed', {
entity: this.entity,
componentType: this.ComponentClass.name
});
}
undo(): void {
const newComponent = new this.ComponentClass();
// 恢复数据
for (const [key, value] of Object.entries(this.componentData)) {
(newComponent as any)[key] = value;
}
this.entity.addComponent(newComponent);
this.component = newComponent;
this.messageHub.publish('component:added', {
entity: this.entity,
component: newComponent
});
}
getDescription(): string {
return `移除组件: ${this.ComponentClass.name}`;
}
}

View File

@@ -0,0 +1,76 @@
import { Entity, Component } from '@esengine/ecs-framework';
import { MessageHub } from '@esengine/editor-core';
import { BaseCommand } from '../BaseCommand';
import { ICommand } from '../ICommand';
/**
* 更新组件属性命令
*/
export class UpdateComponentCommand extends BaseCommand {
private oldValue: unknown;
constructor(
private messageHub: MessageHub,
private entity: Entity,
private component: Component,
private propertyName: string,
private newValue: unknown
) {
super();
this.oldValue = (component as any)[propertyName];
}
execute(): void {
(this.component as any)[this.propertyName] = this.newValue;
this.messageHub.publish('component:updated', {
entity: this.entity,
component: this.component,
propertyName: this.propertyName,
value: this.newValue
});
}
undo(): void {
(this.component as any)[this.propertyName] = this.oldValue;
this.messageHub.publish('component:updated', {
entity: this.entity,
component: this.component,
propertyName: this.propertyName,
value: this.oldValue
});
}
getDescription(): string {
return `更新 ${this.component.constructor.name}.${this.propertyName}`;
}
canMergeWith(other: ICommand): boolean {
if (!(other instanceof UpdateComponentCommand)) return false;
return (
this.entity === other.entity &&
this.component === other.component &&
this.propertyName === other.propertyName
);
}
mergeWith(other: ICommand): ICommand {
if (!(other instanceof UpdateComponentCommand)) {
throw new Error('无法合并不同类型的命令');
}
// 保留原始值,使用新命令的新值
const merged = new UpdateComponentCommand(
this.messageHub,
this.entity,
this.component,
this.propertyName,
other.newValue
);
merged.oldValue = this.oldValue;
return merged;
}
}

View File

@@ -0,0 +1,3 @@
export { AddComponentCommand } from './AddComponentCommand';
export { RemoveComponentCommand } from './RemoveComponentCommand';
export { UpdateComponentCommand } from './UpdateComponentCommand';

View File

@@ -0,0 +1,58 @@
import { Core, Entity } from '@esengine/ecs-framework';
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
import { BaseCommand } from '../BaseCommand';
/**
* 创建实体命令
*/
export class CreateEntityCommand extends BaseCommand {
private entity: Entity | null = null;
private entityId: number | null = null;
constructor(
private entityStore: EntityStoreService,
private messageHub: MessageHub,
private entityName: string,
private parentEntity?: Entity
) {
super();
}
execute(): void {
const scene = Core.scene;
if (!scene) {
throw new Error('场景未初始化');
}
this.entity = scene.createEntity(this.entityName);
this.entityId = this.entity.id;
if (this.parentEntity) {
this.parentEntity.addChild(this.entity);
}
this.entityStore.addEntity(this.entity, this.parentEntity);
this.entityStore.selectEntity(this.entity);
this.messageHub.publish('entity:added', { entity: this.entity });
}
undo(): void {
if (!this.entity) return;
this.entityStore.removeEntity(this.entity);
this.entity.destroy();
this.messageHub.publish('entity:removed', { entityId: this.entityId });
this.entity = null;
}
getDescription(): string {
return `创建实体: ${this.entityName}`;
}
getCreatedEntity(): Entity | null {
return this.entity;
}
}

View File

@@ -0,0 +1,91 @@
import { Core, Entity, Component } from '@esengine/ecs-framework';
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
import { BaseCommand } from '../BaseCommand';
/**
* 删除实体命令
*/
export class DeleteEntityCommand extends BaseCommand {
private entityId: number;
private entityName: string;
private parentEntity: Entity | null;
private components: Component[] = [];
private childEntities: Entity[] = [];
constructor(
private entityStore: EntityStoreService,
private messageHub: MessageHub,
private entity: Entity
) {
super();
this.entityId = entity.id;
this.entityName = entity.name;
this.parentEntity = entity.parent;
// 保存组件状态用于撤销
this.components = [...entity.components];
// 保存子实体
this.childEntities = [...entity.children];
}
execute(): void {
// 先移除子实体
for (const child of this.childEntities) {
this.entityStore.removeEntity(child);
}
this.entityStore.removeEntity(this.entity);
this.entity.destroy();
this.messageHub.publish('entity:removed', { entityId: this.entityId });
}
undo(): void {
const scene = Core.scene;
if (!scene) {
throw new Error('场景未初始化');
}
// 重新创建实体
const newEntity = scene.createEntity(this.entityName);
// 设置父实体
if (this.parentEntity) {
this.parentEntity.addChild(newEntity);
}
// 恢复组件
for (const component of this.components) {
// 创建组件副本
const ComponentClass = component.constructor as new () => Component;
const newComponent = new ComponentClass();
// 复制属性
for (const key of Object.keys(component)) {
if (key !== 'entity' && key !== 'id') {
(newComponent as any)[key] = (component as any)[key];
}
}
newEntity.addComponent(newComponent);
}
// 恢复子实体
for (const child of this.childEntities) {
newEntity.addChild(child);
this.entityStore.addEntity(child, newEntity);
}
this.entityStore.addEntity(newEntity, this.parentEntity ?? undefined);
this.entityStore.selectEntity(newEntity);
// 更新引用
this.entity = newEntity;
this.messageHub.publish('entity:added', { entity: newEntity });
}
getDescription(): string {
return `删除实体: ${this.entityName}`;
}
}

View File

@@ -0,0 +1,2 @@
export { CreateEntityCommand } from './CreateEntityCommand';
export { DeleteEntityCommand } from './DeleteEntityCommand';