refactor: 代码规范化与依赖清理 (#317)

* refactor(deps): 统一编辑器包依赖配置 & 优化分层架构

- 将 ecs-engine-bindgen 提升为 Layer 1 核心包
- 统一 9 个编辑器包的依赖声明模式
- 清理废弃的包目录 (ui, ui-editor, network-*)

* refactor(tokens): 修复 PrefabService 令牌冲突 & 补充 module.json

- 将 editor-core 的 PrefabServiceToken 改名为 EditorPrefabServiceToken
  避免与 asset-system 的 PrefabServiceToken 冲突 (Symbol.for 冲突)
- 为 mesh-3d 添加 module.json
- 为 world-streaming 添加 module.json

* refactor(editor-core): 整理导出结构 & 添加 blueprint tokens.ts

- 按功能分组整理 editor-core 的 65 行导出
- 添加清晰的分组注释 (中英双语)
- 为 blueprint 添加占位符 tokens.ts

* chore(editor): 为 14 个编辑器插件包添加 module.json

统一编辑器包的模块配置,包含:
- isEditorPlugin 标识
- runtimeModule 关联
- exports 导出清单 (inspectors, panels, gizmos)

* refactor(core): 改进类型安全 - 减少 as any 使用

- 添加 GlobalTypes.ts 定义小游戏平台和 Chrome API 类型
- SoAStorage 使用 IComponentTypeMetadata 替代 as any
- PlatformDetector 使用类型安全的平台检测
- 添加 ISoAStorageStats/ISoAFieldStats 接口

* feat(editor): 添加 EditorServicesContext 解决 prop drilling

- 新增 contexts/EditorServicesContext.tsx 提供统一服务访问
- App.tsx 包裹 EditorServicesProvider
- 提供 useEditorServices/useMessageHub 等便捷 hooks
- SceneHierarchy 添加迁移注释,后续可移除 props

* docs(editor): 澄清 inspector 目录架构关系

- inspector/ 标记为内部实现,添加 @deprecated 警告
- inspectors/ 标记为公共 API 入口点
- 添加架构说明文档

* refactor(editor): 添加全局类型声明消除 window as any

- 创建 editor-app/src/global.d.ts 声明 Window 接口扩展
- 创建 editor-core/src/global.d.ts 声明 Window 接口扩展
- 更新 App.tsx 使用类型安全的 window 属性访问
- 更新 PluginLoader.ts 使用 window.__ESENGINE_PLUGINS__
- 更新 PluginSDKRegistry.ts 使用 window.__ESENGINE_SDK__
- 更新 UserCodeService.ts 使用类型安全的全局变量访问

* refactor(editor): 提取项目和场景操作到独立 hooks

- 创建 useProjectActions hook 封装项目操作
- 创建 useSceneActions hook 封装场景操作
- 为渐进式重构 App.tsx 做准备

* refactor(editor): 清理冗余代码和未使用文件

删除的目录和文件:
- application/state/ - 重复的状态管理(与 stores/ 重复)
- 8 个孤立 CSS 文件(对应组件不存在)
- AssetBrowser.tsx - 仅为 ContentBrowser 的向后兼容包装
- AssetPicker.tsx - 未被使用
- AssetPickerDialog.tsx (顶级) - 已被 dialogs/ 版本取代
- EntityInspector.tsx (顶级) - 已被 inspectors/views/ 版本取代

修复:
- 移除 App.tsx 中未使用的导入
- 更新 application/index.ts 移除已删除模块
- 修复 useProjectActions.ts 的 MutableRefObject 类型

* refactor(editor): 统一 inspectors 模块导出结构

- 在 inspectors/index.ts 重新导出 PropertyInspector
- 创建 inspectors/fields/index.ts barrel export
- 导出 views、fields、common 子模块
- 更新 EntityInspector 使用统一入口导入

* refactor(editor): 删除废弃的 Profiler 组件

删除未使用的组件(共 1059 行):
- ProfilerPanel.tsx (229 行)
- ProfilerWindow.tsx (589 行)
- ProfilerDockPanel.tsx (241 行)
- ProfilerPanel.css
- ProfilerDockPanel.css

保留:AdvancedProfiler + AdvancedProfilerWindow(正在使用)

* refactor(runtime-core): 统一依赖处理与插件状态管理

- 新增 DependencyUtils 统一拓扑排序和依赖验证
- 新增 PluginState 定义插件生命周期状态机
- 合并 UnifiedPluginLoader 到 PluginLoader
- 清理 index.ts 移除不必要的 Token re-exports
- 新增 RuntimeMode/UserCodeRealm/ImportMapGenerator

* refactor(editor-core): 使用统一的 ImportMapGenerator

- WebBuildPipeline 使用 runtime-core 的 generateImportMap
- UserCodeService 添加 ImportMap 相关接口

* feat(compiler): 增强 esbuild 查找策略

- 支持本地 node_modules、pnpm exec、npx、全局多种来源
- EngineService 使用 RuntimeMode

* refactor(runtime-core): 简化 GameRuntime 代码

- 合并 _disableGameLogicSystems/_enableGameLogicSystems 为 _setGameLogicSystemsEnabled
- 精简本地 Token 定义的注释

* refactor(editor-core): 引入 BaseRegistry 基类消除代码重复

- 新增 BaseRegistry 和 PrioritizedRegistry 基类
- 重构 CompilerRegistry, InspectorRegistry, FieldEditorRegistry
- 统一注册表的日志记录和错误处理

* refactor(editor-core): 扩展 BaseRegistry 重构

- ComponentInspectorRegistry 继承 PrioritizedRegistry
- EditorComponentRegistry 继承 BaseRegistry
- EntityCreationRegistry 继承 BaseRegistry
- PropertyRendererRegistry 继承 PrioritizedRegistry
- 导出 BaseRegistry 基类供外部使用
- 统一双语注释格式

* refactor(editor-core): 代码优雅性优化

CommandManager:
- 提取 tryMergeWithLast() 和 pushToUndoStack() 消除重复代码
- 统一双语注释格式

FileActionRegistry:
- 提取 normalizeExtension() 消除扩展名规范化重复
- 统一私有属性命名风格(_前缀)
- 使用 createRegistryToken 统一 Token 创建

BaseRegistry:
- 添加 IOrdered 接口
- 添加 sortByOrder() 排序辅助方法

EntityCreationRegistry:
- 使用 sortByOrder() 简化排序逻辑

* refactor(editor-core): 统一日志系统 & 代码规范优化

- GizmoRegistry: 使用 createLogger 替代 console.warn
- VirtualNodeRegistry: 使用 createLogger 替代 console.warn
- WindowRegistry: 使用 logger、添加 _ 前缀、导出 IWindowRegistry token
- EditorViewportService: 使用 createLogger 替代 console.warn
- ComponentActionRegistry: 使用 logger、添加 _ 前缀、返回值改进
- SettingsRegistry: 使用 logger、提取 ensureCategory/ensureSection 方法
- 添加 WindowRegistry 到主导出

* refactor(editor-core): ModuleRegistry 使用 logger 替代 console

* refactor(editor-core): SerializerRegistry/UIRegistry 添加 token 和 _ 前缀

* refactor(editor-core): UIRegistry 代码优雅性 & Token 命名统一

- UIRegistry: 提取 _sortByOrder 消除 6 处重复排序逻辑
- UIRegistry: 添加分节注释和双语文档
- FieldEditorRegistry: Token 重命名为 FieldEditorRegistryToken
- PropertyRendererRegistry: Token 重命名为 PropertyRendererRegistryToken

* refactor(core): 统一日志系统 - console 替换为 logger

- ComponentSerializer: 使用 logger 替代 console.warn
- ComponentRegistry: console.warn → logger.warn (已有 logger)
- SceneSerializer: 添加 logger,替换 console.warn/error
- SystemScheduler: 添加 logger,替换 console.warn
- VersionMigration: 添加 logger,替换所有 console.warn
- RuntimeModeService: console.error → logger.error
- Core.ts: _logger 改为 readonly,双语错误消息
- SceneSerializer 修复:使用 getComponentTypeName 替代 constructor.name

* fix(core): 修复 constructor.name 压缩后失效问题

- Scene.ts: 使用 system.systemName 替代 system.constructor.name
- CommandBuffer.ts: 使用 getComponentTypeName() 替代 constructor.name

* refactor(editor-core): 代码规范优化 - 私有方法命名 & 日志统一

- BuildService: console → logger
- FileActionRegistry: 添加 logger, 私有方法 _ 前缀
- SettingsRegistry: 私有方法 _ 前缀 (ensureCategory → _ensureCategory)

* refactor(core): Scene.ts 私有变量命名规范化

- logger → _logger (遵循私有变量 _ 前缀规范)

* refactor(editor-core): 服务类私有成员命名规范化

- CommandManager: 私有变量/方法添加 _ 前缀
  - undoStack/redoStack/config/isExecuting
  - tryMergeWithLast/pushToUndoStack
- LocaleService: 私有变量/方法添加 _ 前缀
  - currentLocale/translations/changeListeners
  - deepMerge/getNestedValue/loadSavedLocale/saveLocale

* refactor(core): 私有成员命名规范化 & 单例模式优化

- Component.ts: _idGenerator 私有静态变量规范化
- PlatformManager.ts: _instance, _adapter, _logger 规范化
- AutoProfiler.ts: _instance, _config 及所有私有方法规范化
- ProfilerSDK.ts: _instance, _config 及所有私有方法规范化
- ComponentPoolManager: _instance, _pools, _usageTracker 规范化
- GlobalEventBus: _instance 规范化
- 添加中英双语 JSDoc 注释

* refactor(editor-app,behavior-tree-editor): 私有成员 & 单例模式命名规范化

editor-app:
- EngineService: private static instance → _instance
- EditorEngineSync: 所有私有成员添加 _ 前缀
- RuntimeResolver: 所有私有成员和方法添加 _ 前缀
- SettingsService: 所有私有成员和方法添加 _ 前缀

behavior-tree-editor:
- GlobalBlackboardService: 所有私有成员和方法添加 _ 前缀
- NotificationService: private static instance → _instance
- NodeRegistryService: 所有私有成员和方法添加 _ 前缀
- TreeStateAdapter: private static instance → _instance

* fix(editor-runtime): 添加 editor-core 到 external 避免传递依赖问题

将 @esengine/editor-core 添加到 vite external 配置,
避免 editor-core → runtime-core → ecs-engine-bindgen 的传递依赖
被错误地打包进 editor-runtime.js,导致 CI 构建失败。

* fix(core): 修复空接口 lint 错误

将 IByteDanceMiniGameAPI、IAlipayMiniGameAPI、IBaiduMiniGameAPI 从空接口改为类型别名,修复 no-empty-object-type 规则报错
This commit is contained in:
YHH
2025-12-24 20:57:08 +08:00
committed by GitHub
parent 58f70a5783
commit dbc6793dc4
133 changed files with 6880 additions and 9141 deletions

View File

@@ -1,140 +1,601 @@
/**
* Runtime Plugin Manager
* 运行时插件管理器
* @zh 运行时插件管理器
* @en Runtime Plugin Manager
*
* @zh 提供插件生命周期管理的核心实现。
* @en Provides core implementation for plugin lifecycle management.
*
* @zh 设计原则 | Design principles:
* @en
* 1. 最小依赖 - 只依赖 ecs-framework 和 engine-core
* 2. 状态跟踪 - 详细的插件状态用于调试和 UI
* 3. 依赖验证 - 确保加载顺序正确
* 4. 错误隔离 - 单个插件失败不影响其他
*/
import { GlobalComponentRegistry, ServiceContainer } from '@esengine/ecs-framework';
import { GlobalComponentRegistry, ServiceContainer, createLogger } from '@esengine/ecs-framework';
import type { IScene } from '@esengine/ecs-framework';
import type { IRuntimePlugin, IRuntimeModule, SystemContext, ModuleManifest } from '@esengine/engine-core';
import {
topologicalSort,
resolveDependencyId,
getReverseDependencies,
type IDependable
} from './utils/DependencyUtils';
import type { PluginState } from './PluginState';
export type { IRuntimePlugin, IRuntimeModule, SystemContext, ModuleManifest };
export class RuntimePluginManager {
private _plugins = new Map<string, IRuntimePlugin>();
private _enabledPlugins = new Set<string>();
private _bInitialized = false;
const logger = createLogger('PluginManager');
// ============================================================================
// 类型定义 | Type Definitions
// ============================================================================
// PluginState 从 ./PluginState 重新导出
// PluginState is re-exported from ./PluginState
/**
* @zh 已注册的插件信息
* @en Registered plugin info
*/
export interface RegisteredPluginInfo {
/**
* @zh 插件实例
* @en Plugin instance
*/
plugin: IRuntimePlugin;
/**
* @zh 插件状态
* @en Plugin state
*/
state: PluginState;
/**
* @zh 是否启用
* @en Whether enabled
*/
enabled: boolean;
/**
* @zh 错误信息
* @en Error message
*/
error?: Error;
/**
* @zh 注册时间
* @en Registration time
*/
registeredAt: number;
/**
* @zh 激活时间
* @en Activation time
*/
activatedAt?: number;
/**
* @zh 创建的系统实例(用于清理)
* @en Created system instances (for cleanup)
*/
systemInstances?: any[];
}
/**
* @zh 插件配置
* @en Plugin configuration
*/
export interface RuntimePluginConfig {
/**
* @zh 启用的插件 ID 列表
* @en Enabled plugin ID list
*/
enabledPlugins: string[];
}
// ============================================================================
// RuntimePluginManager
// ============================================================================
/**
* @zh 运行时插件管理器
* @en Runtime Plugin Manager
*
* @zh 管理运行时插件的注册、初始化和生命周期。
* @en Manages registration, initialization, and lifecycle of runtime plugins.
*/
export class RuntimePluginManager {
private _plugins = new Map<string, RegisteredPluginInfo>();
private _initialized = false;
private _currentScene: IScene | null = null;
private _currentContext: SystemContext | null = null;
// ============================================================================
// 注册 | Registration
// ============================================================================
/**
* @zh 注册插件
* @en Register plugin
*
* @param plugin - @zh 插件实例 @en Plugin instance
*/
register(plugin: IRuntimePlugin): void {
const id = plugin.manifest.id;
if (this._plugins.has(id)) {
if (!plugin?.manifest?.id) {
logger.error('Cannot register plugin: invalid manifest');
return;
}
this._plugins.set(id, plugin);
if (plugin.manifest.defaultEnabled !== false) {
this._enabledPlugins.add(id);
const id = plugin.manifest.id;
if (this._plugins.has(id)) {
logger.warn(`Plugin ${id} is already registered, skipping`);
return;
}
const enabled = plugin.manifest.isCore === true ||
plugin.manifest.isEngineModule === true ||
plugin.manifest.defaultEnabled !== false;
this._plugins.set(id, {
plugin,
state: 'loading', // 已加载但未初始化
enabled,
registeredAt: Date.now()
});
logger.debug(`Plugin registered: ${id}`, {
enabled,
isCore: plugin.manifest.isCore,
isEngineModule: plugin.manifest.isEngineModule
});
}
/**
* @zh 批量注册插件
* @en Register multiple plugins
*
* @param plugins - @zh 插件列表 @en Plugin list
*/
registerMany(plugins: IRuntimePlugin[]): void {
for (const plugin of plugins) {
this.register(plugin);
}
}
enable(pluginId: string): void {
this._enabledPlugins.add(pluginId);
}
// ============================================================================
// 启用/禁用 | Enable/Disable
// ============================================================================
disable(pluginId: string): void {
this._enabledPlugins.delete(pluginId);
}
isEnabled(pluginId: string): boolean {
return this._enabledPlugins.has(pluginId);
}
loadConfig(config: { enabledPlugins: string[] }): void {
this._enabledPlugins.clear();
for (const id of config.enabledPlugins) {
this._enabledPlugins.add(id);
/**
* @zh 启用插件
* @en Enable plugin
*
* @param pluginId - @zh 插件 ID @en Plugin ID
* @returns @zh 是否成功 @en Whether successful
*/
enable(pluginId: string): boolean {
const info = this._plugins.get(pluginId);
if (!info) {
logger.error(`Plugin ${pluginId} not found`);
return false;
}
// 始终启用引擎核心模块
for (const [id, plugin] of this._plugins) {
if (plugin.manifest.isEngineModule) {
this._enabledPlugins.add(id);
if (info.plugin.manifest.isCore) {
logger.warn(`Core plugin ${pluginId} is always enabled`);
return true;
}
// 检查依赖 | Check dependencies
const deps = info.plugin.manifest.dependencies || [];
for (const dep of deps) {
const depId = resolveDependencyId(dep);
const depInfo = this._plugins.get(depId);
if (!depInfo?.enabled) {
logger.error(`Cannot enable ${pluginId}: dependency ${dep} is not enabled`);
return false;
}
}
info.enabled = true;
logger.info(`Plugin enabled: ${pluginId}`);
return true;
}
/**
* @zh 禁用插件
* @en Disable plugin
*
* @param pluginId - @zh 插件 ID @en Plugin ID
* @returns @zh 是否成功 @en Whether successful
*/
disable(pluginId: string): boolean {
const info = this._plugins.get(pluginId);
if (!info) {
logger.error(`Plugin ${pluginId} not found`);
return false;
}
if (info.plugin.manifest.isCore) {
logger.warn(`Core plugin ${pluginId} cannot be disabled`);
return false;
}
// 检查是否有其他插件依赖此插件(使用统一工具)
// Check if other plugins depend on this (using unified util)
const reverseDeps = this._getReverseDependencies(pluginId);
const enabledReverseDeps = Array.from(reverseDeps).filter(
id => this._plugins.get(id)?.enabled
);
if (enabledReverseDeps.length > 0) {
logger.error(`Cannot disable ${pluginId}: plugins ${enabledReverseDeps.join(', ')} depend on it`);
return false;
}
// 清理系统实例 | Cleanup system instances
if (info.systemInstances && this._currentScene) {
for (const system of info.systemInstances) {
try {
this._currentScene.removeSystem(system);
} catch (e) {
logger.warn(`Failed to remove system from ${pluginId}:`, e);
}
}
info.systemInstances = [];
}
info.enabled = false;
info.state = 'disabled';
logger.info(`Plugin disabled: ${pluginId}`);
return true;
}
/**
* @zh 检查插件是否启用
* @en Check if plugin is enabled
*/
isEnabled(pluginId: string): boolean {
return this._plugins.get(pluginId)?.enabled ?? false;
}
/**
* @zh 加载配置
* @en Load configuration
*
* @param config - @zh 插件配置 @en Plugin configuration
*/
loadConfig(config: RuntimePluginConfig): void {
const { enabledPlugins } = config;
for (const [id, info] of this._plugins) {
if (info.plugin.manifest.isCore || info.plugin.manifest.isEngineModule) {
info.enabled = true;
continue;
}
const shouldEnable = enabledPlugins.includes(id) ||
info.plugin.manifest.defaultEnabled === true;
info.enabled = shouldEnable;
}
logger.info('Plugin configuration loaded', {
enabled: Array.from(this._plugins.values()).filter(p => p.enabled).length,
total: this._plugins.size
});
}
// ============================================================================
// 初始化 | Initialization
// ============================================================================
/**
* @zh 初始化所有启用的插件
* @en Initialize all enabled plugins
*
* @param services - @zh 服务容器 @en Service container
*/
async initializeRuntime(services: ServiceContainer): Promise<void> {
if (this._bInitialized) {
if (this._initialized) {
logger.warn('Runtime already initialized');
return;
}
for (const [id, plugin] of this._plugins) {
if (!this._enabledPlugins.has(id)) continue;
const mod = plugin.runtimeModule;
const startTime = Date.now();
const sortedPlugins = this._topologicalSort();
// Phase 1: 注册组件 | Register components
for (const pluginId of sortedPlugins) {
const info = this._plugins.get(pluginId);
if (!info?.enabled) continue;
const mod = info.plugin.runtimeModule;
if (mod?.registerComponents) {
try {
info.state = 'initializing';
mod.registerComponents(GlobalComponentRegistry);
logger.debug(`Components registered for: ${pluginId}`);
} catch (e) {
console.error(`[PluginManager] Failed to register components for ${id}:`, e);
logger.error(`Failed to register components for ${pluginId}:`, e);
info.state = 'error';
info.error = e as Error;
}
}
}
for (const [id, plugin] of this._plugins) {
if (!this._enabledPlugins.has(id)) continue;
const mod = plugin.runtimeModule;
// Phase 2: 注册服务 | Register services
for (const pluginId of sortedPlugins) {
const info = this._plugins.get(pluginId);
if (!info?.enabled || info.state === 'error') continue;
const mod = info.plugin.runtimeModule;
if (mod?.registerServices) {
try {
mod.registerServices(services);
logger.debug(`Services registered for: ${pluginId}`);
} catch (e) {
console.error(`[PluginManager] Failed to register services for ${id}:`, e);
logger.error(`Failed to register services for ${pluginId}:`, e);
info.state = 'error';
info.error = e as Error;
}
}
}
for (const [id, plugin] of this._plugins) {
if (!this._enabledPlugins.has(id)) continue;
const mod = plugin.runtimeModule;
// Phase 3: 初始化回调 | Initialize callbacks
for (const pluginId of sortedPlugins) {
const info = this._plugins.get(pluginId);
if (!info?.enabled || info.state === 'error') continue;
const mod = info.plugin.runtimeModule;
if (mod?.onInitialize) {
try {
await mod.onInitialize();
info.state = 'active';
info.activatedAt = Date.now();
logger.debug(`Initialized: ${pluginId}`);
} catch (e) {
console.error(`[PluginManager] Failed to initialize ${id}:`, e);
logger.error(`Failed to initialize ${pluginId}:`, e);
info.state = 'error';
info.error = e as Error;
}
} else {
info.state = 'active';
info.activatedAt = Date.now();
}
}
this._bInitialized = true;
this._initialized = true;
const duration = Date.now() - startTime;
const activeCount = Array.from(this._plugins.values())
.filter(p => p.state === 'active').length;
logger.info(`Runtime initialized | 运行时初始化完成`, {
active: activeCount,
total: this._plugins.size,
duration: `${duration}ms`
});
}
/**
* @zh 为场景创建系统
* @en Create systems for scene
*
* @param scene - @zh 场景 @en Scene
* @param context - @zh 系统上下文 @en System context
*/
createSystemsForScene(scene: IScene, context: SystemContext): void {
// Phase 1: 创建系统
for (const [id, plugin] of this._plugins) {
if (!this._enabledPlugins.has(id)) continue;
const mod = plugin.runtimeModule;
this._currentScene = scene;
this._currentContext = context;
const sortedPlugins = this._topologicalSort();
// Phase 1: 创建系统 | Create systems
for (const pluginId of sortedPlugins) {
const info = this._plugins.get(pluginId);
if (!info?.enabled || info.state === 'error') continue;
const mod = info.plugin.runtimeModule;
if (mod?.createSystems) {
try {
const systemsBefore = scene.systems.length;
mod.createSystems(scene, context);
// 跟踪创建的系统 | Track created systems
const systemsAfter = scene.systems;
info.systemInstances = [];
for (let i = systemsBefore; i < systemsAfter.length; i++) {
info.systemInstances.push(systemsAfter[i]);
}
logger.debug(`Systems created for: ${pluginId}`, {
count: info.systemInstances.length
});
} catch (e) {
console.error(`[PluginManager] Failed to create systems for ${id}:`, e);
logger.error(`Failed to create systems for ${pluginId}:`, e);
info.state = 'error';
info.error = e as Error;
}
}
}
// Phase 2: 连接跨插件依赖
for (const [id, plugin] of this._plugins) {
if (!this._enabledPlugins.has(id)) continue;
const mod = plugin.runtimeModule;
// Phase 2: 系统创建后回调 | Post-creation callbacks
for (const pluginId of sortedPlugins) {
const info = this._plugins.get(pluginId);
if (!info?.enabled || info.state === 'error') continue;
const mod = info.plugin.runtimeModule;
if (mod?.onSystemsCreated) {
try {
mod.onSystemsCreated(scene, context);
logger.debug(`Systems wired for: ${pluginId}`);
} catch (e) {
console.error(`[PluginManager] Failed to wire dependencies for ${id}:`, e);
logger.error(`Failed to wire systems for ${pluginId}:`, e);
}
}
}
logger.info('Systems created for scene | 场景系统创建完成');
}
getPlugins(): IRuntimePlugin[] {
return Array.from(this._plugins.values());
}
// ============================================================================
// 查询 | Query
// ============================================================================
/**
* @zh 获取插件
* @en Get plugin
*/
getPlugin(id: string): IRuntimePlugin | undefined {
return this._plugins.get(id)?.plugin;
}
/**
* @zh 获取插件信息
* @en Get plugin info
*/
getPluginInfo(id: string): RegisteredPluginInfo | undefined {
return this._plugins.get(id);
}
/**
* @zh 获取所有插件
* @en Get all plugins
*/
getPlugins(): IRuntimePlugin[] {
return Array.from(this._plugins.values()).map(p => p.plugin);
}
/**
* @zh 获取所有启用的插件
* @en Get all enabled plugins
*/
getEnabledPlugins(): IRuntimePlugin[] {
return Array.from(this._plugins.values())
.filter(p => p.enabled)
.map(p => p.plugin);
}
/**
* @zh 获取插件状态
* @en Get plugin state
*/
getState(pluginId: string): PluginState | undefined {
return this._plugins.get(pluginId)?.state;
}
/**
* @zh 获取失败的插件
* @en Get failed plugins
*/
getFailedPlugins(): Array<{ id: string; error: Error }> {
const failed: Array<{ id: string; error: Error }> = [];
for (const [id, info] of this._plugins) {
if (info.state === 'error' && info.error) {
failed.push({ id, error: info.error });
}
}
return failed;
}
/**
* @zh 是否已初始化
* @en Whether initialized
*/
get initialized(): boolean {
return this._initialized;
}
// ============================================================================
// 生命周期 | Lifecycle
// ============================================================================
/**
* @zh 清理场景系统
* @en Clear scene systems
*/
clearSceneSystems(): void {
for (const [pluginId, info] of this._plugins) {
if (!info.enabled) continue;
const mod = info.plugin.runtimeModule;
if (mod?.onDestroy) {
try {
mod.onDestroy();
} catch (e) {
logger.error(`Error in ${pluginId}.onDestroy:`, e);
}
}
info.systemInstances = [];
}
this._currentScene = null;
this._currentContext = null;
logger.debug('Scene systems cleared');
}
/**
* @zh 重置管理器
* @en Reset manager
*/
reset(): void {
this.clearSceneSystems();
this._plugins.clear();
this._enabledPlugins.clear();
this._bInitialized = false;
this._initialized = false;
logger.info('PluginManager reset');
}
// ============================================================================
// 私有方法 | Private Methods
// ============================================================================
/**
* @zh 拓扑排序(使用统一的 DependencyUtils
* @en Topological sort (using unified DependencyUtils)
*/
private _topologicalSort(): string[] {
// 转换为 IDependable 格式
const items: IDependable[] = Array.from(this._plugins.entries()).map(
([id, info]) => ({
id,
dependencies: info.plugin.manifest.dependencies
})
);
const result = topologicalSort(items, {
algorithm: 'dfs',
resolveId: resolveDependencyId
});
if (result.hasCycles) {
logger.warn(`Circular dependencies detected: ${result.cycleIds?.join(', ')}`);
}
return result.sorted.map(item => item.id);
}
/**
* @zh 获取反向依赖(使用统一的 DependencyUtils
* @en Get reverse dependencies (using unified DependencyUtils)
*/
private _getReverseDependencies(pluginId: string): Set<string> {
const items: IDependable[] = Array.from(this._plugins.entries()).map(
([id, info]) => ({
id,
dependencies: info.plugin.manifest.dependencies
})
);
return getReverseDependencies(pluginId, items, {
resolveId: resolveDependencyId
});
}
}
/**
* @zh 全局运行时插件管理器实例
* @en Global runtime plugin manager instance
*/
export const runtimePluginManager = new RuntimePluginManager();