refactor(plugin): 重构插件系统架构,统一类型导入路径 (#296)

* refactor(plugin): 重构插件系统架构,统一类型导入路径

## 主要更改

### 新增 @esengine/plugin-types 包
- 提供打破循环依赖的最小类型定义
- 包含 ServiceToken, createServiceToken, PluginServiceRegistry, IEditorModuleBase

### engine-core 类型统一
- IPlugin<T> 泛型参数改为 T = unknown
- 所有运行时类型(IRuntimeModule, ModuleManifest, SystemContext)在此定义
- 新增 PluginServiceRegistry.ts 导出服务令牌相关类型

### editor-core 类型优化
- 重命名 IPluginLoader.ts 为 EditorModule.ts
- 新增 IEditorPlugin = IPlugin<IEditorModuleLoader> 类型别名
- 移除弃用别名 IPluginLoader, IRuntimeModuleLoader

### 编辑器插件更新
- 所有 9 个编辑器插件使用 IEditorPlugin 类型
- 统一从 editor-core 导入编辑器类型

### 服务令牌规范
- 各模块在 tokens.ts 中定义自己的服务接口和令牌
- 遵循"谁定义接口,谁导出 Token"原则

## 导入规范

| 场景 | 导入来源 |
|------|---------|
| 运行时模块 | @esengine/engine-core |
| 编辑器插件 | @esengine/editor-core |
| 服务令牌 | @esengine/engine-core |

* refactor(plugin): 完善服务令牌规范,统一运行时模块

## 更改内容

### 运行时模块优化
- particle: 使用 PluginServiceRegistry 获取依赖服务
- physics-rapier2d: 通过服务令牌注册/获取物理查询接口
- tilemap: 使用服务令牌获取物理系统依赖
- sprite: 导出服务令牌
- ui: 导出服务令牌
- behavior-tree: 使用服务令牌系统

### 资产系统增强
- IAssetManager 接口扩展
- 加载器使用服务令牌获取依赖

### 运行时核心
- GameRuntime 使用 PluginServiceRegistry
- 导出服务令牌相关类型

### 编辑器服务
- EngineService 适配新的服务令牌系统
- AssetRegistryService 优化

* fix: 修复 editor-app 和 behavior-tree-editor 中的类型引用

- editor-app/PluginLoader.ts: 使用 IPlugin 替代 IPluginLoader
- behavior-tree-editor: 使用 IEditorPlugin 替代 IPluginLoader

* fix(ui): 添加缺失的 ecs-engine-bindgen 依赖

UIRuntimeModule 使用 EngineBridgeToken,需要声明对 ecs-engine-bindgen 的依赖

* fix(type): 解决 ServiceToken 跨包类型兼容性问题

- 在 engine-core 中直接定义 ServiceToken 和 PluginServiceRegistry
  而不是从 plugin-types 重新导出,确保 tsup 生成的类型声明
  以 engine-core 作为类型来源
- 移除 RuntimeResolver.ts 中的硬编码模块 ID 检查,
  改用 module.json 中的 name 配置
- 修复 pnpm-lock.yaml 中的依赖记录

* refactor(arch): 改进架构设计,移除硬编码

- 统一类型导出:editor-core 从 engine-core 导入 IEditorModuleBase
- RuntimeResolver: 将硬编码路径改为配置常量和搜索路径列表
- 添加跨平台安装路径支持(Windows/macOS/Linux)
- 使用 ENGINE_WASM_CONFIG 配置引擎 WASM 文件信息
- IBundlePackOptions 添加 preloadBundles 配置项

* fix(particle): 添加缺失的 ecs-engine-bindgen 依赖

ParticleRuntimeModule 导入了 @esengine/ecs-engine-bindgen 的 tokens,
但 package.json 中未声明该依赖,导致 CI 构建失败。

* fix(physics-rapier2d): 移除不存在的 PhysicsSystemContext 导出

PhysicsRuntimeModule 中不存在该类型,导致 type-check 失败
This commit is contained in:
YHH
2025-12-08 21:10:57 +08:00
committed by GitHub
parent 2476379af1
commit c3b7250f85
86 changed files with 1813 additions and 551 deletions

View File

@@ -4,11 +4,13 @@
*
* UI
* Define editor-specific module interfaces and UI descriptor types.
*
* IEditorModuleLoader engine-core IEditorModuleBase
* IEditorModuleLoader extends IEditorModuleBase from engine-core.
*/
import type { ServiceContainer } from '@esengine/ecs-framework';
// 从 PluginDescriptor 重新导出(来源于 engine-core
// 统一从 engine-core 导入所有类型,避免直接依赖 plugin-types
export type {
LoadingPhase,
SystemContext,
@@ -17,7 +19,8 @@ export type {
ModuleManifest,
ModuleCategory,
ModulePlatform,
ModuleExports
ModuleExports,
IEditorModuleBase
} from './PluginDescriptor';
// ============================================================================
@@ -219,23 +222,23 @@ export interface FileCreationTemplate {
// 编辑器模块接口 | Editor Module Interface
// ============================================================================
import type { IEditorModuleBase } from './PluginDescriptor';
/**
*
* Editor module loader
*
* IEditorModuleBase UI
* Extends IEditorModuleBase and adds editor-specific UI descriptor methods.
*
* IEditorModuleBase:
* Lifecycle methods inherited from IEditorModuleBase:
* - install(services) / uninstall()
* - onEditorReady() / onProjectOpen() / onProjectClose()
* - onSceneLoaded() / onSceneSaving()
* - setLocale()
*/
export interface IEditorModuleLoader {
/**
*
* Install editor module
*/
install(services: ServiceContainer): Promise<void>;
/**
*
* Uninstall editor module
*/
uninstall?(): Promise<void>;
export interface IEditorModuleLoader extends IEditorModuleBase {
/**
*
* Get panel descriptors
@@ -289,44 +292,38 @@ export interface IEditorModuleLoader {
* Get file creation templates
*/
getFileCreationTemplates?(): FileCreationTemplate[];
// ===== 生命周期钩子 | Lifecycle hooks =====
/** 编辑器就绪 | Editor ready */
onEditorReady?(): void | Promise<void>;
/** 项目打开 | Project open */
onProjectOpen?(projectPath: string): void | Promise<void>;
/** 项目关闭 | Project close */
onProjectClose?(): void | Promise<void>;
/** 场景加载 | Scene loaded */
onSceneLoaded?(scenePath: string): void;
/** 场景保存前 | Before scene save */
onSceneSaving?(scenePath: string): boolean | void;
/** 设置语言 | Set locale */
setLocale?(locale: string): void;
}
// ============================================================================
// 类型别名(向后兼容)| Type Aliases (backward compatibility)
// 编辑器插件类型 | Editor Plugin Type
// ============================================================================
/**
* IPluginLoader
*
* @deprecated 使 IPlugin IPluginLoader IPlugin
* @deprecated Use IPlugin instead. IPluginLoader is just an alias for IPlugin.
*/
export type { IPlugin as IPluginLoader } from './PluginDescriptor';
import type { IPlugin } from './PluginDescriptor';
/**
* IRuntimeModuleLoader
*
* Editor plugin type
*
* @deprecated 使 IRuntimeModule
* @deprecated Use IRuntimeModule instead.
* 使
* IPlugin editorModule IEditorModuleLoader
*
* This is the type to use when developing editor plugins.
* It's a specialized version of IPlugin with editorModule typed as IEditorModuleLoader.
*
* @example
* ```typescript
* import { IEditorPlugin, IEditorModuleLoader } from '@esengine/editor-core';
*
* class MyEditorModule implements IEditorModuleLoader {
* async install(services) { ... }
* getPanels() { return [...]; }
* }
*
* export const MyPlugin: IEditorPlugin = {
* manifest,
* runtimeModule: new MyRuntimeModule(),
* editorModule: new MyEditorModule()
* };
* ```
*/
export type { IRuntimeModule as IRuntimeModuleLoader } from './PluginDescriptor';
export type IEditorPlugin = IPlugin<IEditorModuleLoader>;

View File

@@ -7,6 +7,7 @@
*/
// 从 engine-core 重新导出所有类型
// 包括 IEditorModuleBase原来在 plugin-types 中定义,现在统一从 engine-core 导出)
export type {
LoadingPhase,
SystemContext,
@@ -15,7 +16,8 @@ export type {
ModuleManifest,
ModuleCategory,
ModulePlatform,
ModuleExports
ModuleExports,
IEditorModuleBase
} from '@esengine/engine-core';
/**

View File

@@ -14,7 +14,7 @@ import type {
import type {
SystemContext,
IEditorModuleLoader
} from './IPluginLoader';
} from './EditorModule';
import { EntityCreationRegistry } from '../Services/EntityCreationRegistry';
import { ComponentActionRegistry } from '../Services/ComponentActionRegistry';
import { FileActionRegistry } from '../Services/FileActionRegistry';
@@ -821,22 +821,18 @@ export class PluginManager implements IService {
this.currentContext = context;
logger.info('Creating systems for scene...');
console.log('[PluginManager] createSystemsForScene called, context.assetManager:', context.assetManager ? 'exists' : 'null');
const sortedPlugins = this.sortByLoadingPhase('runtime');
console.log('[PluginManager] Sorted plugins for runtime:', sortedPlugins);
// 第一阶段:创建所有系统
// Phase 1: Create all systems
for (const pluginId of sortedPlugins) {
const plugin = this.plugins.get(pluginId);
console.log(`[PluginManager] Plugin ${pluginId}: enabled=${plugin?.enabled}, state=${plugin?.state}, hasRuntimeModule=${!!plugin?.plugin.runtimeModule}`);
if (!plugin?.enabled || plugin.state === 'error') continue;
const runtimeModule = plugin.plugin.runtimeModule;
if (runtimeModule?.createSystems) {
try {
console.log(`[PluginManager] Calling createSystems for: ${pluginId}`);
runtimeModule.createSystems(scene, context);
logger.debug(`Systems created for: ${pluginId}`);
} catch (e) {

View File

@@ -4,5 +4,5 @@
*/
export * from './PluginDescriptor';
export * from './IPluginLoader';
export * from './EditorModule';
export * from './PluginManager';

View File

@@ -12,7 +12,7 @@
* Uses .meta files to persistently store each asset's GUID.
*/
import { Core, createLogger, PlatformDetector } from '@esengine/ecs-framework';
import { Core, createLogger, PlatformDetector, type IService } from '@esengine/ecs-framework';
import { MessageHub } from './MessageHub';
import {
AssetMetaManager,
@@ -219,8 +219,12 @@ class SimpleAssetDatabase {
/**
* Asset Registry Service
* 资产注册表服务
*
* 实现 IService 接口以便与 ServiceContainer 集成
* Implements IService interface for ServiceContainer integration
*/
export class AssetRegistryService {
export class AssetRegistryService implements IService {
private _database: SimpleAssetDatabase;
private _projectPath: string | null = null;
private _manifest: AssetManifest | null = null;

View File

@@ -6,9 +6,9 @@
import { injectable } from 'tsyringe';
import type { IService } from '@esengine/ecs-framework';
import type { ComponentAction } from '../Plugin/IPluginLoader';
import type { ComponentAction } from '../Plugin/EditorModule';
// Re-export ComponentAction type from Plugin system
export type { ComponentAction } from '../Plugin/IPluginLoader';
export type { ComponentAction } from '../Plugin/EditorModule';
@injectable()
export class ComponentActionRegistry implements IService {

View File

@@ -1,8 +1,8 @@
import { IService } from '@esengine/ecs-framework';
import type { FileActionHandler, FileCreationTemplate } from '../Plugin/IPluginLoader';
import type { FileActionHandler, FileCreationTemplate } from '../Plugin/EditorModule';
// Re-export for backwards compatibility
export type { FileCreationTemplate } from '../Plugin/IPluginLoader';
export type { FileCreationTemplate } from '../Plugin/EditorModule';
/**
* 资产创建消息映射

View File

@@ -1,7 +1,7 @@
import type { IService } from '@esengine/ecs-framework';
import { Injectable } from '@esengine/ecs-framework';
import { createLogger } from '@esengine/ecs-framework';
import type { ISerializer } from '../Plugin/IPluginLoader';
import type { ISerializer } from '../Plugin/EditorModule';
const logger = createLogger('SerializerRegistry');

View File

@@ -89,7 +89,7 @@ export interface ToolbarItem {
}
// Re-export PanelPosition and PanelDescriptor from Plugin system
export { PanelPosition, type PanelDescriptor } from '../Plugin/IPluginLoader';
export { PanelPosition, type PanelDescriptor } from '../Plugin/EditorModule';
/**
* UI 扩展点类型
@@ -103,4 +103,4 @@ export enum UIExtensionType {
}
// Re-export EntityCreationTemplate from Plugin system
export type { EntityCreationTemplate } from '../Plugin/IPluginLoader';
export type { EntityCreationTemplate } from '../Plugin/EditorModule';