feat(editor-core): 添加用户系统自动注册功能 (#283)

* feat(editor-core): 添加用户系统自动注册功能

- IUserCodeService 新增 registerSystems/unregisterSystems/getRegisteredSystems 方法
- UserCodeService 实现系统检测、实例化和场景注册逻辑
- ServiceRegistry 在预览开始时注册用户系统,停止时移除
- 热更新时自动重新加载用户系统
- 更新 System 脚本模板添加 @ECSSystem 装饰器

* feat(editor-core): 添加编辑器脚本支持(Inspector/Gizmo)

- registerEditorExtensions 实际注册用户 Inspector 和 Gizmo
- 添加 unregisterEditorExtensions 方法
- ServiceRegistry 在项目加载时编译并加载编辑器脚本
- 项目关闭时自动清理编辑器扩展
- 添加 Inspector 和 Gizmo 脚本创建模板
This commit is contained in:
YHH
2025-12-05 18:28:11 +08:00
committed by GitHub
parent 823e0c1d94
commit 3d5fcc1a55
4 changed files with 389 additions and 58 deletions

View File

@@ -275,31 +275,22 @@ export class ${className} extends Component {
category: 'Script',
getContent: (fileName: string) => {
const className = fileName.replace(/\.ts$/, '');
return `import { EntitySystem, Matcher, type Entity } from '@esengine/ecs-framework';
return `import { EntitySystem, Matcher, ECSSystem, type Entity } from '@esengine/ecs-framework';
/**
* ${className}
*/
@ECSSystem('${className}')
export class ${className} extends EntitySystem {
// 定义系统处理的组件类型
// Define component types this system processes
protected getMatcher(): Matcher {
// 返回匹配器,指定需要哪些组件
// Return matcher specifying required components
// return Matcher.all(SomeComponent);
return Matcher.empty();
constructor() {
// 定义系统处理的组件类型 | Define component types this system processes
// super(Matcher.all(SomeComponent));
super(Matcher.empty());
}
protected updateEntity(entity: Entity, deltaTime: number): void {
// 处理每个实体
// Process each entity
// 处理每个实体 | Process each entity
}
// 可选:系统初始化
// Optional: System initialization
// onInitialize(): void {
// super.onInitialize();
// }
}
`;
}
@@ -320,6 +311,86 @@ export function ${name.charAt(0).toLowerCase() + name.slice(1)}(): void {
// 在这里编写代码
// Write your code here
}
`;
}
},
{
id: 'ts-inspector',
label: 'Inspector',
extension: '.ts',
icon: 'FileCode',
category: 'Editor',
getContent: (fileName: string) => {
const className = fileName.replace(/\.ts$/, '');
return `import React from 'react';
import type { Component } from '@esengine/ecs-framework';
import type { IComponentInspector, ComponentInspectorContext } from '@esengine/editor-core';
/**
* ${className}
*
* 自定义组件检查器 | Custom component inspector
* 放置在 scripts/editor/ 目录下 | Place in scripts/editor/ directory
*/
export class ${className} implements IComponentInspector {
readonly id = '${className.toLowerCase()}';
readonly name = '${className}';
readonly priority = 10;
// 目标组件类型名称 | Target component type names
readonly targetComponents = ['YourComponent'];
canHandle(component: Component): boolean {
return this.targetComponents.includes(component.constructor.name);
}
render(context: ComponentInspectorContext): React.ReactElement {
const { component } = context;
return React.createElement('div', { className: 'custom-inspector' },
React.createElement('h4', null, '${className}'),
React.createElement('pre', null, JSON.stringify(component, null, 2))
);
}
}
`;
}
},
{
id: 'ts-gizmo',
label: 'Gizmo',
extension: '.ts',
icon: 'FileCode',
category: 'Editor',
getContent: (fileName: string) => {
const className = fileName.replace(/\.ts$/, '');
return `import type { Component, Entity } from '@esengine/ecs-framework';
import type { IGizmoRenderData } from '@esengine/editor-core';
/**
* ${className}
*
* 自定义 Gizmo 提供者 | Custom Gizmo provider
* 放置在 scripts/editor/ 目录下 | Place in scripts/editor/ directory
*/
export class ${className} {
// 目标组件类型 | Target component type
// 需要替换为实际的组件类 | Replace with actual component class
readonly targetComponent = null; // YourComponent
draw(component: Component, entity: Entity, isSelected: boolean): IGizmoRenderData[] {
// 返回要绘制的 Gizmo 数据 | Return gizmo data to draw
return [
{
type: 'circle',
x: 0,
y: 0,
radius: 10,
strokeColor: isSelected ? '#00ff00' : '#ffffff',
strokeWidth: 2
}
];
}
}
`;
}
}