Files
esengine/packages/engine-core/src/PluginServiceRegistry.ts
YHH ed8f6e283b feat: 纹理路径稳定 ID 与架构改进 (#305)
* feat(asset-system): 实现路径稳定 ID 生成器

使用 FNV-1a hash 算法为纹理生成稳定的运行时 ID:
- 新增 _pathIdCache 静态缓存,跨 Play/Stop 循环保持稳定
- 新增 getStableIdForPath() 方法,相同路径永远返回相同 ID
- 修改 loadTextureForComponent/loadTextureByGuid 使用稳定 ID
- clearTextureMappings() 不再清除 _pathIdCache

这解决了 Play/Stop 后纹理 ID 失效的根本问题。

* fix(runtime-core): 移除 Play/Stop 循环中的 clearTextureMappings 调用

使用路径稳定 ID 后,不再需要在快照保存/恢复时清除纹理缓存:
- saveSceneSnapshot() 移除 clearTextureMappings() 调用
- restoreSceneSnapshot() 移除 clearTextureMappings() 调用
- 组件保存的 textureId 在 Play/Stop 后仍然有效

* fix(editor-core): 修复场景切换时的资源泄漏

在 openScene() 加载新场景前先卸载旧场景资源:
- 调用 sceneResourceManager.unloadSceneResources() 释放旧资源
- 使用引用计数机制,仅卸载不再被引用的资源
- 路径稳定 ID 缓存不受影响,保持 ID 稳定性

* fix(runtime-core): 修复 PluginManager 组件注册类型错误

将 ComponentRegistry 类改为 GlobalComponentRegistry 实例:
- registerComponents() 期望 IComponentRegistry 接口实例
- GlobalComponentRegistry 是 ComponentRegistry 的全局实例

* refactor(core): 提取 IComponentRegistry 接口

将组件注册表抽象为接口,支持场景级组件注册:
- 新增 IComponentRegistry 接口定义
- Scene 持有独立的 componentRegistry 实例
- 支持从 GlobalComponentRegistry 克隆
- 各系统支持传入自定义注册表

* refactor(engine-core): 改进插件服务注册机制

- 更新 IComponentRegistry 类型引用
- 优化 PluginServiceRegistry 服务管理

* refactor(modules): 适配新的组件注册接口

更新各模块 RuntimeModule 使用 IComponentRegistry 接口:
- audio, behavior-tree, camera
- sprite, tilemap, world-streaming

* fix(physics-rapier2d): 修复物理插件组件注册

- PhysicsEditorPlugin 添加 runtimeModule 引用
- 适配 IComponentRegistry 接口
- 修复物理组件在场景加载时未注册的问题

* feat(editor-core): 添加 UserCodeService 就绪信号机制

- 新增 waitForReady()/signalReady() API
- 支持等待用户脚本编译完成
- 解决场景加载时组件未注册的时序问题

* fix(editor-app): 在编译完成后调用 signalReady()

确保用户脚本编译完成后发出就绪信号:
- 编译成功后调用 userCodeService.signalReady()
- 编译失败也要发出信号,避免阻塞场景加载

* feat(editor-core): 改进编辑器核心服务

- EntityStoreService 添加调试日志
- AssetRegistryService 优化资产注册
- PluginManager 改进插件管理
- IFileAPI 添加 getFileMtime 接口

* feat(engine): 改进 Rust 纹理管理器

- 支持任意 ID 的纹理加载(非递增)
- 添加纹理状态追踪 API
- 优化纹理缓存清理机制
- 更新 TypeScript 绑定

* feat(ui): 添加场景切换和文本闪烁组件

新增组件:
- SceneLoadTriggerComponent: 场景切换触发器
- TextBlinkComponent: 文本闪烁效果

新增系统:
- SceneLoadTriggerSystem: 处理场景切换逻辑
- TextBlinkSystem: 处理文本闪烁动画

其他改进:
- UIRuntimeModule 适配新组件注册接口
- UI 渲染系统优化

* feat(editor-app): 添加外部文件修改检测

- 新增 ExternalModificationDialog 组件
- TauriFileAPI 支持 getFileMtime
- 场景文件被外部修改时提示用户

* feat(editor-app): 添加渲染调试面板

- 新增 RenderDebugService 和调试面板 UI
- App/ContentBrowser 添加调试日志
- TitleBar/Viewport 优化
- DialogManager 改进

* refactor(editor-app): 编辑器服务和组件优化

- EngineService 改进引擎集成
- EditorEngineSync 同步优化
- AssetFileInspector 改进
- VectorFieldEditors 优化
- InstantiatePrefabCommand 改进

* feat(i18n): 更新国际化翻译

- 添加新功能相关翻译
- 更新中文、英文、西班牙文

* feat(tauri): 添加文件修改时间查询命令

- 新增 get_file_mtime 命令
- 支持检测文件外部修改

* refactor(particle): 粒子系统改进

- 适配新的组件注册接口
- ParticleSystem 优化
- 添加单元测试

* refactor(platform): 平台适配层优化

- BrowserRuntime 改进
- 新增 RuntimeSceneManager 服务
- 导出优化

* refactor(asset-system-editor): 资产元数据改进

- AssetMetaFile 优化
- 导出调整

* fix(asset-system): 移除未使用的 TextureLoader 导入

* fix(tests): 更新测试以使用 GlobalComponentRegistry 实例

修复多个测试文件以适配 ComponentRegistry 从静态类变为实例类的变更:
- ComponentStorage.test.ts: 使用 GlobalComponentRegistry.reset()
- EntitySerializer.test.ts: 使用 GlobalComponentRegistry 实例
- IncrementalSerialization.test.ts: 使用 GlobalComponentRegistry 实例
- SceneSerializer.test.ts: 使用 GlobalComponentRegistry 实例
- ComponentRegistry.extended.test.ts: 使用 GlobalComponentRegistry,同时注册到 scene.componentRegistry
- SystemTypes.test.ts: 在 Scene 创建前注册组件
- QuerySystem.test.ts: mockScene 添加 componentRegistry
2025-12-16 12:46:14 +08:00

127 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 插件服务令牌engine-core 特定)
* Plugin Service Tokens (engine-core specific)
*
* 核心类型 (PluginServiceRegistry, createServiceToken, ServiceToken) 从 @esengine/ecs-framework 导入。
* 这里只定义 engine-core 特有的服务令牌。
*
* Core types (PluginServiceRegistry, createServiceToken, ServiceToken) are imported from @esengine/ecs-framework.
* This file only defines engine-core specific service tokens.
*/
import { createServiceToken } from '@esengine/ecs-framework';
// Re-export from ecs-framework for backwards compatibility
export { PluginServiceRegistry, createServiceToken, type ServiceToken } from '@esengine/ecs-framework';
// ============================================================================
// engine-core 内部 Token | engine-core Internal Tokens
// ============================================================================
/**
* Transform 组件类型 | Transform component type
*
* 使用 any 类型以允许各模块使用自己的 ITransformComponent 接口定义。
* Using any type to allow modules to use their own ITransformComponent interface definition.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const TransformTypeToken = createServiceToken<new (...args: any[]) => any>('transformType');
/**
* Canvas 元素的服务令牌
* Service token for the canvas element
*/
export const CanvasElementToken = createServiceToken<HTMLCanvasElement>('canvasElement');
// ============================================================================
// 引擎桥接接口 | Engine Bridge Interface
// ============================================================================
/**
* 引擎桥接接口
* Engine bridge interface
*
* 定义 WASM 引擎桥接的核心契约,供各模块使用。
* Defines the core contract of WASM engine bridge for modules to use.
*/
export interface IEngineBridge {
/** 加载纹理 | Load texture */
loadTexture(id: number, url: string): Promise<void>;
/**
* 屏幕坐标转世界坐标
* Screen to world coordinate conversion
*/
screenToWorld(screenX: number, screenY: number): { x: number; y: number };
/**
* 世界坐标转屏幕坐标
* World to screen coordinate conversion
*/
worldToScreen(worldX: number, worldY: number): { x: number; y: number };
/**
* 设置清除颜色
* Set clear color
*/
setClearColor(r: number, g: number, b: number, a: number): void;
// ===== Texture State API (Optional) =====
// ===== 纹理状态 API可选=====
/**
* 获取纹理加载状态
* Get texture loading state
*
* @param id 纹理 ID | Texture ID
* @returns 状态字符串: 'loading', 'ready', 或 'failed:reason'
* State string: 'loading', 'ready', or 'failed:reason'
*/
getTextureState?(id: number): string;
/**
* 检查纹理是否就绪
* Check if texture is ready for rendering
*
* @param id 纹理 ID | Texture ID
* @returns 纹理数据已加载则返回 true | true if texture data is loaded
*/
isTextureReady?(id: number): boolean;
/**
* 获取正在加载的纹理数量
* Get count of textures currently loading
*
* @returns 处于加载状态的纹理数量 | Number of textures in loading state
*/
getTextureLoadingCount?(): number;
/**
* 异步加载纹理(等待完成)
* Load texture asynchronously (wait for completion)
*
* 与 loadTexture 不同,此方法会等待纹理实际加载完成。
* Unlike loadTexture, this method waits until texture is actually loaded.
*
* @param id 纹理 ID | Texture ID
* @param url 图片 URL | Image URL
* @returns 纹理就绪时解析的 Promise | Promise that resolves when texture is ready
*/
loadTextureAsync?(id: number, url: string): Promise<void>;
/**
* 等待所有加载中的纹理完成
* Wait for all loading textures to complete
*
* @param timeout 最大等待时间毫秒默认30000| Max wait time in ms (default 30000)
* @returns 所有纹理加载完成时解析 | Resolves when all textures are loaded
*/
waitForAllTextures?(timeout?: number): Promise<void>;
}
/**
* 引擎桥接服务令牌
* Engine bridge service token
*/
export const EngineBridgeToken = createServiceToken<IEngineBridge>('engineBridge');