import type { IComponentRegistry, IScene } from '@esengine/ecs-framework'; import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core'; import { TransformTypeToken, CanvasElementToken } from '@esengine/engine-core'; import { AssetManagerToken } from '@esengine/asset-system'; import { RenderSystemToken, EngineIntegrationToken, TextureServiceToken, CoordinateServiceToken } from '@esengine/ecs-engine-bindgen'; import { Physics2DQueryToken } from '@esengine/physics-rapier2d'; import { ParticleSystemComponent } from './ParticleSystemComponent'; import { ClickFxComponent } from './ClickFxComponent'; import { ParticleUpdateSystem } from './systems/ParticleSystem'; import { ClickFxSystem } from './systems/ClickFxSystem'; import { ParticleLoader, ParticleAssetType } from './loaders/ParticleLoader'; import { ParticleUpdateSystemToken } from './tokens'; export type { SystemContext, ModuleManifest, IRuntimeModule, IRuntimePlugin }; // 重新导出 tokens | Re-export tokens export { ParticleUpdateSystemToken } from './tokens'; class ParticleRuntimeModule implements IRuntimeModule { private _updateSystem: ParticleUpdateSystem | null = null; private _loaderRegistered = false; registerComponents(registry: IComponentRegistry): void { registry.register(ParticleSystemComponent); registry.register(ClickFxComponent); } createSystems(scene: IScene, context: SystemContext): void { // 从服务注册表获取依赖 | Get dependencies from service registry const assetManager = context.services.get(AssetManagerToken); const transformType = context.services.get(TransformTypeToken); const engineIntegration = context.services.get(EngineIntegrationToken); const textureService = context.services.get(TextureServiceToken); const coordinateService = context.services.get(CoordinateServiceToken); const physics2DQuery = context.services.get(Physics2DQueryToken); const renderSystem = context.services.get(RenderSystemToken); // 注册粒子资产加载器到上下文的 assetManager // Register particle asset loader to context assetManager if (!this._loaderRegistered && assetManager) { const loader = new ParticleLoader(); assetManager.registerLoader(ParticleAssetType, loader); this._loaderRegistered = true; console.log('[ParticleRuntimeModule] Registered ParticleLoader to context assetManager'); } this._updateSystem = new ParticleUpdateSystem(); // 设置资产管理器 | Set asset manager if (assetManager) { this._updateSystem.setAssetManager(assetManager); } // 设置 Transform 组件类型 | Set Transform component type if (transformType) { this._updateSystem.setTransformType(transformType); } // 设置引擎集成(用于加载纹理)| Set engine integration (for loading textures) if (engineIntegration) { this._updateSystem.setEngineIntegration(engineIntegration); } // 设置纹理服务(用于加载默认纹理)| Set texture service (for loading default texture) if (textureService) { this._updateSystem.setTextureService(textureService); } // 设置 2D 物理查询(用于粒子与场景碰撞)| Set 2D physics query (for particle-scene collision) if (physics2DQuery) { this._updateSystem.setPhysics2DQuery(physics2DQuery); } scene.addSystem(this._updateSystem); // 添加点击特效系统 | Add click FX system // ClickFxSystem 不再需要 AssetManager,资产由 ParticleUpdateSystem 统一加载 // ClickFxSystem no longer needs AssetManager, assets are loaded by ParticleUpdateSystem const clickFxSystem = new ClickFxSystem(); // 设置坐标服务(用于屏幕坐标转世界坐标) // Set coordinate service (for screen to world coordinate conversion) if (coordinateService) { clickFxSystem.setCoordinateService(coordinateService); } // 从服务注册表获取 Canvas 元素(用于计算相对坐标) // Get canvas element from service registry (for calculating relative coordinates) const canvas = context.services.get(CanvasElementToken); if (canvas) { clickFxSystem.setCanvas(canvas); } scene.addSystem(clickFxSystem); // 注册粒子更新系统到服务注册表 | Register particle update system to service registry context.services.register(ParticleUpdateSystemToken, this._updateSystem); // 注册渲染数据提供者 | Register render data provider if (renderSystem) { const renderDataProvider = this._updateSystem.getRenderDataProvider(); renderSystem.addRenderDataProvider(renderDataProvider); } } /** * 获取粒子更新系统 * Get particle update system */ get updateSystem(): ParticleUpdateSystem | null { return this._updateSystem; } } const manifest: ModuleManifest = { id: 'particle', name: '@esengine/particle', displayName: 'Particle System', version: '1.0.0', description: 'Particle system for 2D effects', category: 'Rendering', icon: 'Sparkles', isCore: false, defaultEnabled: true, isEngineModule: true, canContainContent: true, dependencies: ['core', 'math', 'sprite'], exports: { components: ['ParticleSystemComponent', 'ClickFxComponent'] }, editorPackage: '@esengine/particle-editor', requiresWasm: false }; export const ParticlePlugin: IRuntimePlugin = { manifest, runtimeModule: new ParticleRuntimeModule() }; export { ParticleRuntimeModule };