refactor: 类型安全与接口清理 (#311)

* refactor: 分解 IEngineBridge 为单一职责接口

- 新增 ITextureService, IDynamicAtlasService, ICoordinateService, IRenderConfigService
- 移除 EngineBridgeToken,改用具体服务 Token
- 更新 camera, ui, particle 等模块使用新接口
- 优化装饰器类型安全,使用 Symbol-based metadata 访问模式

* refactor: 删除 plugin-types 包,统一 createServiceToken 实现

- 移动 IEditorModuleBase 接口到 engine-core
- 移除 engine-core 和 editor-core 对 plugin-types 的依赖
- 删除冗余的 plugin-types 包
- 统一使用 core 中基于 Symbol.for() 的 createServiceToken

* refactor: 统一 IPlugin 接口,移除 deprecated 别名

- 移除 engine-core、editor-core、runtime-core 中的 IPlugin 别名
- 模块插件统一使用 IRuntimePlugin(运行时)或 IEditorPlugin(编辑器)
- 保留 core 包中的 IPlugin 作为 ECS 核心插件接口(不同概念)
- 更新所有消费方使用正确的类型

* refactor: 重命名 editor-core ComponentRegistry 为 EditorComponentRegistry

- 消除与 core 包 ComponentRegistry(ECS 位掩码管理)的命名歧义
- editor-core 的 EditorComponentRegistry 专用于编辑器组件元数据
- 更新所有编辑器包使用新名称
This commit is contained in:
YHH
2025-12-19 17:48:18 +08:00
committed by GitHub
parent ecdb8f2021
commit e24c850568
51 changed files with 492 additions and 623 deletions

View File

@@ -15,13 +15,13 @@ import type {
import { import {
EntityStoreService, EntityStoreService,
MessageHub, MessageHub,
ComponentRegistry EditorComponentRegistry
} from '@esengine/editor-core'; } from '@esengine/editor-core';
import { CameraComponent } from '@esengine/camera'; import { CameraComponent } from '@esengine/camera';
export class CameraEditorModule implements IEditorModuleLoader { export class CameraEditorModule implements IEditorModuleLoader {
async install(services: ServiceContainer): Promise<void> { async install(services: ServiceContainer): Promise<void> {
const componentRegistry = services.resolve(ComponentRegistry); const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) { if (componentRegistry) {
componentRegistry.register({ componentRegistry.register({
name: 'Camera', name: 'Camera',

View File

@@ -1,6 +1,6 @@
import type { IComponentRegistry, IScene } from '@esengine/ecs-framework'; import type { IComponentRegistry, IScene } from '@esengine/ecs-framework';
import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core'; import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core';
import { EngineBridgeToken } from '@esengine/engine-core'; import { RenderConfigServiceToken } from '@esengine/engine-core';
import { CameraComponent } from './CameraComponent'; import { CameraComponent } from './CameraComponent';
import { CameraSystem } from './CameraSystem'; import { CameraSystem } from './CameraSystem';
@@ -10,15 +10,15 @@ class CameraRuntimeModule implements IRuntimeModule {
} }
createSystems(scene: IScene, context: SystemContext): void { createSystems(scene: IScene, context: SystemContext): void {
// 从服务注册表获取 EngineBridge | Get EngineBridge from service registry // 从服务注册表获取渲染配置服务 | Get render config service from registry
const bridge = context.services.get(EngineBridgeToken); const renderConfig = context.services.get(RenderConfigServiceToken);
if (!bridge) { if (!renderConfig) {
console.warn('[CameraPlugin] EngineBridge not found, CameraSystem will not be created'); console.warn('[CameraPlugin] RenderConfigService not found, CameraSystem will not be created');
return; return;
} }
// 创建并添加 CameraSystem | Create and add CameraSystem // 创建并添加 CameraSystem | Create and add CameraSystem
const cameraSystem = new CameraSystem(bridge); const cameraSystem = new CameraSystem(renderConfig);
scene.addSystem(cameraSystem); scene.addSystem(cameraSystem);
} }
} }

View File

@@ -4,18 +4,18 @@
*/ */
import { EntitySystem, Matcher, Entity, ECSSystem } from '@esengine/ecs-framework'; import { EntitySystem, Matcher, Entity, ECSSystem } from '@esengine/ecs-framework';
import type { IEngineBridge } from '@esengine/engine-core'; import type { IRenderConfigService } from '@esengine/engine-core';
import { CameraComponent } from './CameraComponent'; import { CameraComponent } from './CameraComponent';
@ECSSystem('Camera', { updateOrder: -100 }) @ECSSystem('Camera', { updateOrder: -100 })
export class CameraSystem extends EntitySystem { export class CameraSystem extends EntitySystem {
private bridge: IEngineBridge; private renderConfig: IRenderConfigService;
private lastAppliedCameraId: number | null = null; private lastAppliedCameraId: number | null = null;
constructor(bridge: IEngineBridge) { constructor(renderConfig: IRenderConfigService) {
// Match entities with CameraComponent // Match entities with CameraComponent
super(Matcher.empty().all(CameraComponent)); super(Matcher.empty().all(CameraComponent));
this.bridge = bridge; this.renderConfig = renderConfig;
} }
protected override onBegin(): void { protected override onBegin(): void {
@@ -47,6 +47,6 @@ export class CameraSystem extends EntitySystem {
const r = parseInt(bgColor.slice(1, 3), 16) / 255; const r = parseInt(bgColor.slice(1, 3), 16) / 255;
const g = parseInt(bgColor.slice(3, 5), 16) / 255; const g = parseInt(bgColor.slice(3, 5), 16) / 255;
const b = parseInt(bgColor.slice(5, 7), 16) / 255; const b = parseInt(bgColor.slice(5, 7), 16) / 255;
this.bridge.setClearColor(r, g, b, 1.0); this.renderConfig.setClearColor(r, g, b, 1.0);
} }
} }

View File

@@ -14,7 +14,11 @@ import type { Component } from '../../Component';
/** /**
* 组件类型定义 * 组件类型定义
* Component type definition * Component type definition
*
* 注意:构造函数参数使用 any[] 是必要的,因为组件可以有各种不同签名的构造函数
* Note: Constructor args use any[] because components can have various constructor signatures
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ComponentType<T extends Component = Component> = new (...args: any[]) => T; export type ComponentType<T extends Component = Component> = new (...args: any[]) => T;
/** /**
@@ -61,6 +65,51 @@ export interface ComponentEditorOptions {
icon?: string; icon?: string;
} }
/**
* 组件构造函数上的元数据接口
* Metadata interface stored on component constructors
*
* 使用 Symbol 索引签名来类型安全地访问装饰器存储的元数据
* Uses Symbol index signature to safely access decorator-stored metadata
*/
export interface ComponentTypeMetadata {
readonly [COMPONENT_TYPE_NAME]?: string;
readonly [COMPONENT_DEPENDENCIES]?: string[];
readonly [COMPONENT_EDITOR_OPTIONS]?: ComponentEditorOptions;
}
/**
* 可写的组件类型元数据(用于装饰器设置)
* Writable component type metadata (for decorator setting)
*/
export interface WritableComponentTypeMetadata {
[COMPONENT_TYPE_NAME]?: string;
[COMPONENT_DEPENDENCIES]?: string[];
[COMPONENT_EDITOR_OPTIONS]?: ComponentEditorOptions;
}
/**
* 获取组件构造函数的元数据
* Get metadata from component constructor
*
* @param componentType 组件构造函数
* @returns 元数据对象
*/
export function getComponentTypeMetadata(componentType: ComponentType): ComponentTypeMetadata {
return componentType as unknown as ComponentTypeMetadata;
}
/**
* 获取可写的组件构造函数元数据(用于装饰器)
* Get writable metadata from component constructor (for decorators)
*
* @param componentType 组件构造函数
* @returns 可写的元数据对象
*/
export function getWritableComponentTypeMetadata(componentType: ComponentType): WritableComponentTypeMetadata {
return componentType as unknown as WritableComponentTypeMetadata;
}
/** /**
* 检查组件是否使用了 @ECSComponent 装饰器 * 检查组件是否使用了 @ECSComponent 装饰器
* Check if component has @ECSComponent decorator * Check if component has @ECSComponent decorator
@@ -69,7 +118,8 @@ export interface ComponentEditorOptions {
* @returns 是否有装饰器 * @returns 是否有装饰器
*/ */
export function hasECSComponentDecorator(componentType: ComponentType): boolean { export function hasECSComponentDecorator(componentType: ComponentType): boolean {
return !!(componentType as any)[COMPONENT_TYPE_NAME]; const metadata = getComponentTypeMetadata(componentType);
return metadata[COMPONENT_TYPE_NAME] !== undefined;
} }
/** /**
@@ -82,7 +132,8 @@ export function hasECSComponentDecorator(componentType: ComponentType): boolean
export function getComponentTypeName(componentType: ComponentType): string { export function getComponentTypeName(componentType: ComponentType): string {
// 优先使用装饰器指定的名称 // 优先使用装饰器指定的名称
// Prefer decorator-specified name // Prefer decorator-specified name
const decoratorName = (componentType as any)[COMPONENT_TYPE_NAME]; const metadata = getComponentTypeMetadata(componentType);
const decoratorName = metadata[COMPONENT_TYPE_NAME];
if (decoratorName) { if (decoratorName) {
return decoratorName; return decoratorName;
} }
@@ -111,7 +162,8 @@ export function getComponentInstanceTypeName(component: Component): string {
* @returns 依赖的组件名称列表 * @returns 依赖的组件名称列表
*/ */
export function getComponentDependencies(componentType: ComponentType): string[] | undefined { export function getComponentDependencies(componentType: ComponentType): string[] | undefined {
return (componentType as any)[COMPONENT_DEPENDENCIES]; const metadata = getComponentTypeMetadata(componentType);
return metadata[COMPONENT_DEPENDENCIES];
} }
/** /**
@@ -122,7 +174,8 @@ export function getComponentDependencies(componentType: ComponentType): string[]
* @returns 编辑器选项 * @returns 编辑器选项
*/ */
export function getComponentEditorOptions(componentType: ComponentType): ComponentEditorOptions | undefined { export function getComponentEditorOptions(componentType: ComponentType): ComponentEditorOptions | undefined {
return (componentType as any)[COMPONENT_EDITOR_OPTIONS]; const metadata = getComponentTypeMetadata(componentType);
return metadata[COMPONENT_EDITOR_OPTIONS];
} }
/** /**

View File

@@ -15,7 +15,9 @@ import {
COMPONENT_TYPE_NAME, COMPONENT_TYPE_NAME,
COMPONENT_DEPENDENCIES, COMPONENT_DEPENDENCIES,
COMPONENT_EDITOR_OPTIONS, COMPONENT_EDITOR_OPTIONS,
type ComponentEditorOptions getWritableComponentTypeMetadata,
type ComponentEditorOptions,
type ComponentType
} from '../Core/ComponentStorage/ComponentTypeUtils'; } from '../Core/ComponentStorage/ComponentTypeUtils';
/** /**
@@ -24,6 +26,50 @@ import {
*/ */
export const SYSTEM_TYPE_NAME = Symbol('SystemTypeName'); export const SYSTEM_TYPE_NAME = Symbol('SystemTypeName');
/**
* 系统类型元数据接口
* System type metadata interface
*/
export interface SystemTypeMetadata {
readonly [SYSTEM_TYPE_NAME]?: string;
readonly __systemMetadata__?: SystemMetadata;
}
/**
* 可写的系统类型元数据
* Writable system type metadata
*/
interface WritableSystemTypeMetadata {
[SYSTEM_TYPE_NAME]?: string;
__systemMetadata__?: SystemMetadata;
}
/**
* 获取系统类型元数据
* Get system type metadata
*/
function getSystemTypeMetadata(systemType: SystemConstructor): SystemTypeMetadata {
return systemType as unknown as SystemTypeMetadata;
}
/**
* 获取可写的系统类型元数据
* Get writable system type metadata
*/
function getWritableSystemTypeMetadata(systemType: SystemConstructor): WritableSystemTypeMetadata {
return systemType as unknown as WritableSystemTypeMetadata;
}
/**
* 系统构造函数类型
* System constructor type
*
* 注意:构造函数参数使用 any[] 是必要的,因为系统可以有各种不同签名的构造函数
* Note: Constructor args use any[] because systems can have various constructor signatures
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type SystemConstructor<T extends EntitySystem = EntitySystem> = new (...args: any[]) => T;
/** /**
* 组件装饰器配置选项 * 组件装饰器配置选项
* Component decorator options * Component decorator options
@@ -67,25 +113,29 @@ export interface ComponentOptions {
* ``` * ```
*/ */
export function ECSComponent(typeName: string, options?: ComponentOptions) { export function ECSComponent(typeName: string, options?: ComponentOptions) {
return function <T extends new (...args: any[]) => Component>(target: T): T { return function <T extends ComponentType<Component>>(target: T): T {
if (!typeName || typeof typeName !== 'string') { if (!typeName || typeof typeName !== 'string') {
throw new Error('ECSComponent装饰器必须提供有效的类型名称'); throw new Error('ECSComponent装饰器必须提供有效的类型名称');
} }
// 获取可写的元数据对象
// Get writable metadata object
const metadata = getWritableComponentTypeMetadata(target);
// 在构造函数上存储类型名称 // 在构造函数上存储类型名称
// Store type name on constructor // Store type name on constructor
(target as any)[COMPONENT_TYPE_NAME] = typeName; metadata[COMPONENT_TYPE_NAME] = typeName;
// 存储依赖关系 // 存储依赖关系
// Store dependencies // Store dependencies
if (options?.requires) { if (options?.requires) {
(target as any)[COMPONENT_DEPENDENCIES] = options.requires; metadata[COMPONENT_DEPENDENCIES] = options.requires;
} }
// 存储编辑器选项 // 存储编辑器选项
// Store editor options // Store editor options
if (options?.editor) { if (options?.editor) {
(target as any)[COMPONENT_EDITOR_OPTIONS] = options.editor; metadata[COMPONENT_EDITOR_OPTIONS] = options.editor;
} }
// 自动注册到全局 ComponentRegistry使组件可以通过名称查找 // 自动注册到全局 ComponentRegistry使组件可以通过名称查找
@@ -154,19 +204,23 @@ export interface SystemMetadata {
* ``` * ```
*/ */
export function ECSSystem(typeName: string, metadata?: SystemMetadata) { export function ECSSystem(typeName: string, metadata?: SystemMetadata) {
return function <T extends new (...args: any[]) => EntitySystem>(target: T): T { return function <T extends SystemConstructor>(target: T): T {
if (!typeName || typeof typeName !== 'string') { if (!typeName || typeof typeName !== 'string') {
throw new Error('ECSSystem装饰器必须提供有效的类型名称'); throw new Error('ECSSystem装饰器必须提供有效的类型名称');
} }
// 获取可写的元数据对象
// Get writable metadata object
const meta = getWritableSystemTypeMetadata(target);
// 在构造函数上存储类型名称 // 在构造函数上存储类型名称
// Store type name on constructor // Store type name on constructor
(target as any)[SYSTEM_TYPE_NAME] = typeName; meta[SYSTEM_TYPE_NAME] = typeName;
// 存储元数据 // 存储元数据
// Store metadata // Store metadata
if (metadata) { if (metadata) {
(target as any).__systemMetadata__ = metadata; meta.__systemMetadata__ = metadata;
} }
return target; return target;
@@ -177,8 +231,9 @@ export function ECSSystem(typeName: string, metadata?: SystemMetadata) {
* 获取 System 的元数据 * 获取 System 的元数据
* Get System metadata * Get System metadata
*/ */
export function getSystemMetadata(systemType: new (...args: any[]) => EntitySystem): SystemMetadata | undefined { export function getSystemMetadata(systemType: SystemConstructor): SystemMetadata | undefined {
return (systemType as any).__systemMetadata__; const meta = getSystemTypeMetadata(systemType);
return meta.__systemMetadata__;
} }
/** /**
@@ -189,7 +244,7 @@ export function getSystemMetadata(systemType: new (...args: any[]) => EntitySyst
* @returns 系统元数据 | System metadata * @returns 系统元数据 | System metadata
*/ */
export function getSystemInstanceMetadata(system: EntitySystem): SystemMetadata | undefined { export function getSystemInstanceMetadata(system: EntitySystem): SystemMetadata | undefined {
return getSystemMetadata(system.constructor as new (...args: any[]) => EntitySystem); return getSystemMetadata(system.constructor as SystemConstructor);
} }
/** /**
@@ -200,9 +255,10 @@ export function getSystemInstanceMetadata(system: EntitySystem): SystemMetadata
* @returns 系统类型名称 | System type name * @returns 系统类型名称 | System type name
*/ */
export function getSystemTypeName<T extends EntitySystem>( export function getSystemTypeName<T extends EntitySystem>(
systemType: new (...args: any[]) => T systemType: SystemConstructor<T>
): string { ): string {
const decoratorName = (systemType as any)[SYSTEM_TYPE_NAME]; const meta = getSystemTypeMetadata(systemType);
const decoratorName = meta[SYSTEM_TYPE_NAME];
if (decoratorName) { if (decoratorName) {
return decoratorName; return decoratorName;
} }
@@ -217,5 +273,5 @@ export function getSystemTypeName<T extends EntitySystem>(
* @returns 系统类型名称 | System type name * @returns 系统类型名称 | System type name
*/ */
export function getSystemInstanceTypeName(system: EntitySystem): string { export function getSystemInstanceTypeName(system: EntitySystem): string {
return getSystemTypeName(system.constructor as new (...args: any[]) => EntitySystem); return getSystemTypeName(system.constructor as SystemConstructor);
} }

View File

@@ -6,6 +6,12 @@
import type { SpriteRenderData, TextureLoadRequest, EngineStats, CameraConfig } from '../types'; import type { SpriteRenderData, TextureLoadRequest, EngineStats, CameraConfig } from '../types';
import type { ITextureEngineBridge } from '@esengine/asset-system'; import type { ITextureEngineBridge } from '@esengine/asset-system';
import type { GameEngine } from '../wasm/es_engine'; import type { GameEngine } from '../wasm/es_engine';
import type {
ITextureService,
IDynamicAtlasService,
ICoordinateService,
IRenderConfigService
} from '@esengine/engine-core';
/** /**
* Engine bridge configuration. * Engine bridge configuration.
@@ -43,7 +49,7 @@ export interface EngineBridgeConfig {
* bridge.render(); * bridge.render();
* ``` * ```
*/ */
export class EngineBridge implements ITextureEngineBridge { export class EngineBridge implements ITextureEngineBridge, ITextureService, IDynamicAtlasService, ICoordinateService, IRenderConfigService {
private engine: GameEngine | null = null; private engine: GameEngine | null = null;
private config: Required<EngineBridgeConfig>; private config: Required<EngineBridgeConfig>;
private initialized = false; private initialized = false;

View File

@@ -8,12 +8,20 @@
// Service tokens and interfaces (谁定义接口,谁导出 Token) // Service tokens and interfaces (谁定义接口,谁导出 Token)
export { export {
RenderSystemToken, RenderSystemToken,
EngineBridgeToken,
EngineIntegrationToken, EngineIntegrationToken,
// 新的单一职责服务令牌 | New single-responsibility service tokens
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
// 接口类型 | Interface types
type IRenderSystem, type IRenderSystem,
type IEngineBridge,
type IEngineIntegration, type IEngineIntegration,
type IRenderDataProvider type IRenderDataProvider,
type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
} from './tokens'; } from './tokens';
export { EngineBridge } from './core/EngineBridge'; export { EngineBridge } from './core/EngineBridge';

View File

@@ -4,12 +4,31 @@
*/ */
import { createServiceToken } from '@esengine/ecs-framework'; import { createServiceToken } from '@esengine/ecs-framework';
import { EngineBridgeToken as CoreEngineBridgeToken, type IEngineBridge as CoreIEngineBridge } from '@esengine/engine-core'; import {
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
} from '@esengine/engine-core';
import type { IRenderDataProvider as InternalIRenderDataProvider } from './systems/EngineRenderSystem'; import type { IRenderDataProvider as InternalIRenderDataProvider } from './systems/EngineRenderSystem';
// 从 engine-core 重新导出 | Re-export from engine-core // 从 engine-core 重新导出 | Re-export from engine-core
export { CoreEngineBridgeToken as EngineBridgeToken }; export {
export type { CoreIEngineBridge as IEngineBridge }; TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken
};
export type {
ITextureService,
IDynamicAtlasService,
ICoordinateService,
IRenderConfigService
};
export type IRenderDataProvider = InternalIRenderDataProvider; export type IRenderDataProvider = InternalIRenderDataProvider;

View File

@@ -15,7 +15,7 @@ import {
UIRegistry, UIRegistry,
MessageHub, MessageHub,
EntityStoreService, EntityStoreService,
ComponentRegistry, EditorComponentRegistry,
LocaleService, LocaleService,
LogService, LogService,
SettingsRegistry, SettingsRegistry,
@@ -394,7 +394,7 @@ function App() {
setStatus(t('header.status.remoteConnected')); setStatus(t('header.status.remoteConnected'));
} else { } else {
if (projectLoaded) { if (projectLoaded) {
const componentRegistry = Core.services.resolve(ComponentRegistry); const componentRegistry = Core.services.resolve(EditorComponentRegistry);
const componentCount = componentRegistry?.getAllComponents().length || 0; const componentCount = componentRegistry?.getAllComponents().length || 0;
setStatus(t('header.status.projectOpened') + (componentCount > 0 ? ` (${componentCount} components registered)` : '')); setStatus(t('header.status.projectOpened') + (componentCount > 0 ? ` (${componentCount} components registered)` : ''));
} else { } else {

View File

@@ -7,7 +7,7 @@ import {
IMessageHub, IMessageHub,
SerializerRegistry, SerializerRegistry,
EntityStoreService, EntityStoreService,
ComponentRegistry, EditorComponentRegistry,
ProjectService, ProjectService,
ComponentDiscoveryService, ComponentDiscoveryService,
PropertyMetadataService, PropertyMetadataService,
@@ -90,7 +90,7 @@ export interface EditorServices {
messageHub: MessageHub; messageHub: MessageHub;
serializerRegistry: SerializerRegistry; serializerRegistry: SerializerRegistry;
entityStore: EntityStoreService; entityStore: EntityStoreService;
componentRegistry: ComponentRegistry; componentRegistry: EditorComponentRegistry;
projectService: ProjectService; projectService: ProjectService;
componentDiscovery: ComponentDiscoveryService; componentDiscovery: ComponentDiscoveryService;
propertyMetadata: PropertyMetadataService; propertyMetadata: PropertyMetadataService;
@@ -121,7 +121,7 @@ export class ServiceRegistry {
const messageHub = new MessageHub(); const messageHub = new MessageHub();
const serializerRegistry = new SerializerRegistry(); const serializerRegistry = new SerializerRegistry();
const entityStore = new EntityStoreService(messageHub); const entityStore = new EntityStoreService(messageHub);
const componentRegistry = new ComponentRegistry(); const componentRegistry = new EditorComponentRegistry();
// 注册标准组件到编辑器和核心注册表 // 注册标准组件到编辑器和核心注册表
// Register to both editor registry (for UI) and core registry (for serialization) // Register to both editor registry (for UI) and core registry (for serialization)
@@ -168,7 +168,7 @@ export class ServiceRegistry {
Core.services.registerInstance(IMessageHub, messageHub); // Symbol 注册用于跨包插件访问 Core.services.registerInstance(IMessageHub, messageHub); // Symbol 注册用于跨包插件访问
Core.services.registerInstance(SerializerRegistry, serializerRegistry); Core.services.registerInstance(SerializerRegistry, serializerRegistry);
Core.services.registerInstance(EntityStoreService, entityStore); Core.services.registerInstance(EntityStoreService, entityStore);
Core.services.registerInstance(ComponentRegistry, componentRegistry); Core.services.registerInstance(EditorComponentRegistry, componentRegistry);
Core.services.registerInstance(ProjectService, projectService); Core.services.registerInstance(ProjectService, projectService);
Core.services.registerInstance(ComponentDiscoveryService, componentDiscovery); Core.services.registerInstance(ComponentDiscoveryService, componentDiscovery);
Core.services.registerInstance(PropertyMetadataService, propertyMetadata); Core.services.registerInstance(PropertyMetadataService, propertyMetadata);

View File

@@ -1,5 +1,5 @@
import { Entity, Component, getComponentDependencies, getComponentTypeName } from '@esengine/ecs-framework'; import { Entity, Component, getComponentDependencies, getComponentTypeName } from '@esengine/ecs-framework';
import { MessageHub, ComponentRegistry } from '@esengine/editor-core'; import { MessageHub, EditorComponentRegistry } from '@esengine/editor-core';
import { Core } from '@esengine/ecs-framework'; import { Core } from '@esengine/ecs-framework';
import { BaseCommand } from '../BaseCommand'; import { BaseCommand } from '../BaseCommand';
@@ -55,7 +55,7 @@ export class AddComponentCommand extends BaseCommand {
return; return;
} }
const componentRegistry = Core.services.tryResolve(ComponentRegistry) as ComponentRegistry | null; const componentRegistry = Core.services.tryResolve(EditorComponentRegistry) as EditorComponentRegistry | null;
if (!componentRegistry) { if (!componentRegistry) {
return; return;
} }

View File

@@ -32,7 +32,7 @@ import {
import { import {
MessageHub, MessageHub,
CommandManager, CommandManager,
ComponentRegistry, EditorComponentRegistry,
ComponentActionRegistry, ComponentActionRegistry,
ComponentInspectorRegistry, ComponentInspectorRegistry,
PrefabService, PrefabService,
@@ -147,7 +147,7 @@ export const EntityInspectorPanel: React.FC<EntityInspectorPanelProps> = ({
// ==================== 服务 | Services ==================== // ==================== 服务 | Services ====================
const componentRegistry = Core.services.resolve(ComponentRegistry); const componentRegistry = Core.services.resolve(EditorComponentRegistry);
const componentActionRegistry = Core.services.resolve(ComponentActionRegistry); const componentActionRegistry = Core.services.resolve(ComponentActionRegistry);
const componentInspectorRegistry = Core.services.resolve(ComponentInspectorRegistry); const componentInspectorRegistry = Core.services.resolve(ComponentInspectorRegistry);
const prefabService = Core.services.tryResolve(PrefabService) as PrefabService | null; const prefabService = Core.services.tryResolve(PrefabService) as PrefabService | null;

View File

@@ -1,7 +1,7 @@
import { useState, useRef, useEffect, useMemo, useCallback } from 'react'; import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
import { Settings, ChevronDown, ChevronRight, X, Plus, Box, Search, Lock, Unlock } from 'lucide-react'; import { Settings, ChevronDown, ChevronRight, X, Plus, Box, Search, Lock, Unlock } from 'lucide-react';
import { Entity, Component, Core, getComponentDependencies, getComponentTypeName, getComponentInstanceTypeName, isComponentInstanceHiddenInInspector, PrefabInstanceComponent } from '@esengine/ecs-framework'; import { Entity, Component, Core, getComponentDependencies, getComponentTypeName, getComponentInstanceTypeName, isComponentInstanceHiddenInInspector, PrefabInstanceComponent } from '@esengine/ecs-framework';
import { MessageHub, CommandManager, ComponentRegistry, ComponentActionRegistry, ComponentInspectorRegistry, PrefabService } from '@esengine/editor-core'; import { MessageHub, CommandManager, EditorComponentRegistry, ComponentActionRegistry, ComponentInspectorRegistry, PrefabService } from '@esengine/editor-core';
import { PropertyInspector } from '../../PropertyInspector'; import { PropertyInspector } from '../../PropertyInspector';
import { NotificationService } from '../../../services/NotificationService'; import { NotificationService } from '../../../services/NotificationService';
import { RemoveComponentCommand, UpdateComponentCommand, AddComponentCommand } from '../../../application/commands/component'; import { RemoveComponentCommand, UpdateComponentCommand, AddComponentCommand } from '../../../application/commands/component';
@@ -11,7 +11,7 @@ import * as LucideIcons from 'lucide-react';
type CategoryFilter = 'all' | 'general' | 'transform' | 'rendering' | 'physics' | 'audio' | 'other'; type CategoryFilter = 'all' | 'general' | 'transform' | 'rendering' | 'physics' | 'audio' | 'other';
// 从 ComponentRegistry category 到 CategoryFilter 的映射 // 从 EditorComponentRegistry category 到 CategoryFilter 的映射
const categoryKeyMap: Record<string, CategoryFilter> = { const categoryKeyMap: Record<string, CategoryFilter> = {
'components.category.core': 'general', 'components.category.core': 'general',
'components.category.rendering': 'rendering', 'components.category.rendering': 'rendering',
@@ -84,7 +84,7 @@ export function EntityInspector({
const addButtonRef = useRef<HTMLButtonElement>(null); const addButtonRef = useRef<HTMLButtonElement>(null);
const searchInputRef = useRef<HTMLInputElement>(null); const searchInputRef = useRef<HTMLInputElement>(null);
const componentRegistry = Core.services.resolve(ComponentRegistry); const componentRegistry = Core.services.resolve(EditorComponentRegistry);
const componentActionRegistry = Core.services.resolve(ComponentActionRegistry); const componentActionRegistry = Core.services.resolve(ComponentActionRegistry);
const componentInspectorRegistry = Core.services.resolve(ComponentInspectorRegistry); const componentInspectorRegistry = Core.services.resolve(ComponentInspectorRegistry);
const prefabService = Core.services.tryResolve(PrefabService) as PrefabService | null; const prefabService = Core.services.tryResolve(PrefabService) as PrefabService | null;

View File

@@ -8,7 +8,7 @@
import type { ServiceContainer } from '@esengine/ecs-framework'; import type { ServiceContainer } from '@esengine/ecs-framework';
import { createLogger } from '@esengine/ecs-framework'; import { createLogger } from '@esengine/ecs-framework';
import type { IPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core'; import type { IEditorPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core';
import { AssetRegistryService } from '@esengine/editor-core'; import { AssetRegistryService } from '@esengine/editor-core';
const logger = createLogger('AssetMetaPlugin'); const logger = createLogger('AssetMetaPlugin');
@@ -65,7 +65,7 @@ const manifest: ModuleManifest = {
exports: {} exports: {}
}; };
export const AssetMetaPlugin: IPlugin = { export const AssetMetaPlugin: IEditorPlugin = {
manifest, manifest,
editorModule: new AssetMetaEditorModule() editorModule: new AssetMetaEditorModule()
}; };

View File

@@ -5,7 +5,7 @@
import type { ServiceContainer } from '@esengine/ecs-framework'; import type { ServiceContainer } from '@esengine/ecs-framework';
import { createLogger } from '@esengine/ecs-framework'; import { createLogger } from '@esengine/ecs-framework';
import type { IPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core'; import type { IEditorPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core';
import { SettingsRegistry } from '@esengine/editor-core'; import { SettingsRegistry } from '@esengine/editor-core';
import { SettingsService } from '../../services/SettingsService'; import { SettingsService } from '../../services/SettingsService';
@@ -146,7 +146,7 @@ const manifest: ModuleManifest = {
exports: {} exports: {}
}; };
export const EditorAppearancePlugin: IPlugin = { export const EditorAppearancePlugin: IEditorPlugin = {
manifest, manifest,
editorModule: new EditorAppearanceEditorModule() editorModule: new EditorAppearanceEditorModule()
}; };

View File

@@ -4,7 +4,7 @@
*/ */
import type { ServiceContainer } from '@esengine/ecs-framework'; import type { ServiceContainer } from '@esengine/ecs-framework';
import type { IPlugin, IEditorModuleLoader, ModuleManifest, GizmoProviderRegistration } from '@esengine/editor-core'; import type { IEditorPlugin, IEditorModuleLoader, ModuleManifest, GizmoProviderRegistration } from '@esengine/editor-core';
import { registerSpriteGizmo } from '../../gizmos'; import { registerSpriteGizmo } from '../../gizmos';
/** /**
@@ -42,7 +42,7 @@ const manifest: ModuleManifest = {
} }
}; };
export const GizmoPlugin: IPlugin = { export const GizmoPlugin: IEditorPlugin = {
manifest, manifest,
editorModule: new GizmoEditorModule() editorModule: new GizmoEditorModule()
}; };

View File

@@ -5,7 +5,7 @@
import type { ServiceContainer } from '@esengine/ecs-framework'; import type { ServiceContainer } from '@esengine/ecs-framework';
import { createLogger } from '@esengine/ecs-framework'; import { createLogger } from '@esengine/ecs-framework';
import type { IPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core'; import type { IEditorPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core';
import { SettingsRegistry } from '@esengine/editor-core'; import { SettingsRegistry } from '@esengine/editor-core';
const logger = createLogger('PluginConfigPlugin'); const logger = createLogger('PluginConfigPlugin');
@@ -69,7 +69,7 @@ const manifest: ModuleManifest = {
exports: {} exports: {}
}; };
export const PluginConfigPlugin: IPlugin = { export const PluginConfigPlugin: IEditorPlugin = {
manifest, manifest,
editorModule: new PluginConfigEditorModule() editorModule: new PluginConfigEditorModule()
}; };

View File

@@ -6,7 +6,7 @@
import type { ServiceContainer } from '@esengine/ecs-framework'; import type { ServiceContainer } from '@esengine/ecs-framework';
import { Core } from '@esengine/ecs-framework'; import { Core } from '@esengine/ecs-framework';
import type { import type {
IPlugin, IEditorPlugin,
IEditorModuleLoader, IEditorModuleLoader,
ModuleManifest, ModuleManifest,
MenuItemDescriptor MenuItemDescriptor
@@ -140,7 +140,7 @@ const manifest: ModuleManifest = {
exports: {} exports: {}
}; };
export const ProfilerPlugin: IPlugin = { export const ProfilerPlugin: IEditorPlugin = {
manifest, manifest,
editorModule: new ProfilerEditorModule() editorModule: new ProfilerEditorModule()
}; };

View File

@@ -8,7 +8,7 @@
import type { ServiceContainer } from '@esengine/ecs-framework'; import type { ServiceContainer } from '@esengine/ecs-framework';
import { createLogger, Core } from '@esengine/ecs-framework'; import { createLogger, Core } from '@esengine/ecs-framework';
import type { IPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core'; import type { IEditorPlugin, IEditorModuleLoader, ModuleManifest } from '@esengine/editor-core';
import { SettingsRegistry, ProjectService, moduleRegistry } from '@esengine/editor-core'; import { SettingsRegistry, ProjectService, moduleRegistry } from '@esengine/editor-core';
import EngineService from '../../services/EngineService'; import EngineService from '../../services/EngineService';
@@ -306,7 +306,7 @@ const manifest: ModuleManifest = {
exports: {} exports: {}
}; };
export const ProjectSettingsPlugin: IPlugin = { export const ProjectSettingsPlugin: IEditorPlugin = {
manifest, manifest,
editorModule: new ProjectSettingsEditorModule() editorModule: new ProjectSettingsEditorModule()
}; };

View File

@@ -6,7 +6,7 @@
import { Core, Entity } from '@esengine/ecs-framework'; import { Core, Entity } from '@esengine/ecs-framework';
import type { ServiceContainer } from '@esengine/ecs-framework'; import type { ServiceContainer } from '@esengine/ecs-framework';
import type { import type {
IPlugin, IEditorPlugin,
IEditorModuleLoader, IEditorModuleLoader,
ModuleManifest, ModuleManifest,
PanelDescriptor, PanelDescriptor,
@@ -191,7 +191,7 @@ const manifest: ModuleManifest = {
} }
}; };
export const SceneInspectorPlugin: IPlugin = { export const SceneInspectorPlugin: IEditorPlugin = {
manifest, manifest,
editorModule: new SceneInspectorEditorModule() editorModule: new SceneInspectorEditorModule()
}; };

View File

@@ -8,7 +8,15 @@
import { GizmoRegistry, EntityStoreService, MessageHub, SceneManagerService, ProjectService, PluginManager, IPluginManager, AssetRegistryService, GizmoInteractionService, GizmoInteractionServiceToken, type SystemContext } from '@esengine/editor-core'; import { GizmoRegistry, EntityStoreService, MessageHub, SceneManagerService, ProjectService, PluginManager, IPluginManager, AssetRegistryService, GizmoInteractionService, GizmoInteractionServiceToken, type SystemContext } from '@esengine/editor-core';
import { Core, Scene, Entity, SceneSerializer, ProfilerSDK, createLogger, PluginServiceRegistry } from '@esengine/ecs-framework'; import { Core, Scene, Entity, SceneSerializer, ProfilerSDK, createLogger, PluginServiceRegistry } from '@esengine/ecs-framework';
import { CameraConfig, EngineBridgeToken, RenderSystemToken, EngineIntegrationToken } from '@esengine/ecs-engine-bindgen'; import {
CameraConfig,
RenderSystemToken,
EngineIntegrationToken,
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken
} from '@esengine/ecs-engine-bindgen';
import { TransformComponent, TransformTypeToken, CanvasElementToken } from '@esengine/engine-core'; import { TransformComponent, TransformTypeToken, CanvasElementToken } from '@esengine/engine-core';
import { SpriteComponent, SpriteAnimatorComponent, SpriteAnimatorSystemToken } from '@esengine/sprite'; import { SpriteComponent, SpriteAnimatorComponent, SpriteAnimatorSystemToken } from '@esengine/sprite';
import { ParticleSystemComponent } from '@esengine/particle'; import { ParticleSystemComponent } from '@esengine/particle';
@@ -252,7 +260,11 @@ export class EngineService {
// 创建服务注册表并注册核心服务 // 创建服务注册表并注册核心服务
// Create service registry and register core services // Create service registry and register core services
const services = new PluginServiceRegistry(); const services = new PluginServiceRegistry();
services.register(EngineBridgeToken, this._runtime.bridge); // 使用单一职责接口注册 EngineBridge | Register EngineBridge with single-responsibility interfaces
services.register(TextureServiceToken, this._runtime.bridge);
services.register(DynamicAtlasServiceToken, this._runtime.bridge);
services.register(CoordinateServiceToken, this._runtime.bridge);
services.register(RenderConfigServiceToken, this._runtime.bridge);
services.register(RenderSystemToken, this._runtime.renderSystem); services.register(RenderSystemToken, this._runtime.renderSystem);
services.register(AssetManagerToken, this._assetManager); services.register(AssetManagerToken, this._assetManager);
services.register(EngineIntegrationToken, this._engineIntegration); services.register(EngineIntegrationToken, this._engineIntegration);

View File

@@ -4,7 +4,7 @@
*/ */
import { PluginManager, LocaleService, MessageHub, EditorConfig, getPluginsPath } from '@esengine/editor-core'; import { PluginManager, LocaleService, MessageHub, EditorConfig, getPluginsPath } from '@esengine/editor-core';
import type { IPlugin, ModuleManifest } from '@esengine/editor-core'; import type { IRuntimePlugin, ModuleManifest } from '@esengine/editor-core';
import { Core } from '@esengine/ecs-framework'; import { Core } from '@esengine/ecs-framework';
import { TauriAPI } from '../api/tauri'; import { TauriAPI } from '../api/tauri';
import { PluginSDKRegistry } from './PluginSDKRegistry'; import { PluginSDKRegistry } from './PluginSDKRegistry';
@@ -164,7 +164,7 @@ export class PluginLoader {
code: string, code: string,
pluginName: string, pluginName: string,
_pluginDirName: string _pluginDirName: string
): Promise<IPlugin | null> { ): Promise<IRuntimePlugin | null> {
const pluginKey = this.sanitizePluginKey(pluginName); const pluginKey = this.sanitizePluginKey(pluginName);
const pluginsContainer = (window as any)[PLUGINS_GLOBAL_NAME] as Record<string, any>; const pluginsContainer = (window as any)[PLUGINS_GLOBAL_NAME] as Record<string, any>;
@@ -267,7 +267,7 @@ export class PluginLoader {
/** /**
* 查找模块中的插件 * 查找模块中的插件
*/ */
private findPluginLoader(module: any): IPlugin | null { private findPluginLoader(module: any): IRuntimePlugin | null {
// 优先检查 default 导出 // 优先检查 default 导出
if (module.default && this.isPluginLoader(module.default)) { if (module.default && this.isPluginLoader(module.default)) {
return module.default; return module.default;
@@ -287,12 +287,12 @@ export class PluginLoader {
/** /**
* 验证对象是否为有效的插件 * 验证对象是否为有效的插件
*/ */
private isPluginLoader(obj: any): obj is IPlugin { private isPluginLoader(obj: any): obj is IRuntimePlugin {
if (!obj || typeof obj !== 'object') { if (!obj || typeof obj !== 'object') {
return false; return false;
} }
// 新的 IPlugin 接口检查 // IRuntimePlugin 接口检查
if (obj.manifest && this.isModuleManifest(obj.manifest)) { if (obj.manifest && this.isModuleManifest(obj.manifest)) {
return true; return true;
} }
@@ -315,7 +315,7 @@ export class PluginLoader {
/** /**
* 同步插件语言设置 * 同步插件语言设置
*/ */
private syncPluginLocale(plugin: IPlugin, pluginName: string): void { private syncPluginLocale(plugin: IRuntimePlugin, pluginName: string): void {
try { try {
const localeService = Core.services.resolve(LocaleService); const localeService = Core.services.resolve(LocaleService);
const currentLocale = localeService.getCurrentLocale(); const currentLocale = localeService.getCurrentLocale();

View File

@@ -43,7 +43,6 @@
"@esengine/asset-system": "workspace:*", "@esengine/asset-system": "workspace:*",
"@esengine/asset-system-editor": "workspace:*", "@esengine/asset-system-editor": "workspace:*",
"@esengine/engine-core": "workspace:*", "@esengine/engine-core": "workspace:*",
"@esengine/plugin-types": "workspace:*",
"@tauri-apps/api": "^2.2.0", "@tauri-apps/api": "^2.2.0",
"@babel/core": "^7.28.3", "@babel/core": "^7.28.3",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1",

View File

@@ -15,7 +15,7 @@ export type {
LoadingPhase, LoadingPhase,
SystemContext, SystemContext,
IRuntimeModule, IRuntimeModule,
IPlugin, IRuntimePlugin,
ModuleManifest, ModuleManifest,
ModuleCategory, ModuleCategory,
ModulePlatform, ModulePlatform,
@@ -309,17 +309,17 @@ export interface IEditorModuleLoader extends IEditorModuleBase {
// 编辑器插件类型 | Editor Plugin Type // 编辑器插件类型 | Editor Plugin Type
// ============================================================================ // ============================================================================
import type { IPlugin } from './PluginDescriptor'; import type { IRuntimePlugin } from './PluginDescriptor';
/** /**
* 编辑器插件类型 * 编辑器插件类型
* Editor plugin type * Editor plugin type
* *
* 这是开发编辑器插件时应使用的类型。 * 这是开发编辑器插件时应使用的类型。
* 它是 IPlugin 的特化版本editorModule 类型为 IEditorModuleLoader。 * 它是 IRuntimePlugin 的特化版本editorModule 类型为 IEditorModuleLoader。
* *
* This is the type to use when developing editor plugins. * This is the type to use when developing editor plugins.
* It's a specialized version of IPlugin with editorModule typed as IEditorModuleLoader. * It's a specialized version of IRuntimePlugin with editorModule typed as IEditorModuleLoader.
* *
* @example * @example
* ```typescript * ```typescript
@@ -337,4 +337,4 @@ import type { IPlugin } from './PluginDescriptor';
* }; * };
* ``` * ```
*/ */
export type IEditorPlugin = IPlugin<IEditorModuleLoader>; export type IEditorPlugin = IRuntimePlugin<IEditorModuleLoader>;

View File

@@ -6,10 +6,6 @@
* Re-export base types from @esengine/engine-core. * Re-export base types from @esengine/engine-core.
*/ */
// 从 engine-core 导入类型
// Import types from engine-core
import type { IRuntimePlugin as IRuntimePluginBase } from '@esengine/engine-core';
// 从 engine-core 重新导出所有类型 // 从 engine-core 重新导出所有类型
// 包括 IEditorModuleBase原来在 plugin-types 中定义,现在统一从 engine-core 导出) // 包括 IEditorModuleBase原来在 plugin-types 中定义,现在统一从 engine-core 导出)
export type { export type {
@@ -24,9 +20,6 @@ export type {
IEditorModuleBase IEditorModuleBase
} from '@esengine/engine-core'; } from '@esengine/engine-core';
/** @deprecated Use IRuntimePlugin instead */
export type IPlugin<TEditorModule = unknown> = IRuntimePluginBase<TEditorModule>;
/** /**
* 插件状态 * 插件状态
* Plugin state * Plugin state

View File

@@ -7,7 +7,7 @@ import { createLogger, GlobalComponentRegistry } from '@esengine/ecs-framework';
import type { IScene, ServiceContainer, IService } from '@esengine/ecs-framework'; import type { IScene, ServiceContainer, IService } from '@esengine/ecs-framework';
import type { import type {
ModuleManifest, ModuleManifest,
IPlugin, IRuntimePlugin,
ModuleCategory, ModuleCategory,
PluginState PluginState
} from './PluginDescriptor'; } from './PluginDescriptor';
@@ -22,7 +22,7 @@ import { UIRegistry } from '../Services/UIRegistry';
import { MessageHub } from '../Services/MessageHub'; import { MessageHub } from '../Services/MessageHub';
import { moduleRegistry } from '../Services/Module/ModuleRegistry'; import { moduleRegistry } from '../Services/Module/ModuleRegistry';
import { SerializerRegistry } from '../Services/SerializerRegistry'; import { SerializerRegistry } from '../Services/SerializerRegistry';
import { ComponentRegistry as EditorComponentRegistry } from '../Services/ComponentRegistry'; import { EditorComponentRegistry } from '../Services/ComponentRegistry';
const logger = createLogger('PluginManager'); const logger = createLogger('PluginManager');
@@ -64,7 +64,7 @@ export interface NormalizedManifest {
*/ */
export interface NormalizedPlugin { export interface NormalizedPlugin {
manifest: NormalizedManifest; manifest: NormalizedManifest;
runtimeModule?: IPlugin['runtimeModule']; runtimeModule?: IRuntimePlugin['runtimeModule'];
editorModule?: IEditorModuleLoader; editorModule?: IEditorModuleLoader;
} }
@@ -196,7 +196,7 @@ export class PluginManager implements IService {
* 标准化模块清单,填充默认值 * 标准化模块清单,填充默认值
* Normalize module manifest, fill in defaults * Normalize module manifest, fill in defaults
*/ */
private normalizePlugin(input: IPlugin): NormalizedPlugin { private normalizePlugin(input: IRuntimePlugin): NormalizedPlugin {
const m = input.manifest; const m = input.manifest;
return { return {
manifest: { manifest: {
@@ -229,10 +229,10 @@ export class PluginManager implements IService {
* 注册插件 * 注册插件
* Register plugin * Register plugin
* *
* 接受任何符合 IPlugin 接口的插件,内部会标准化所有字段。 * 接受任何符合 IRuntimePlugin 接口的插件,内部会标准化所有字段。
* Accepts any plugin conforming to IPlugin interface, normalizes all fields internally. * Accepts any plugin conforming to IRuntimePlugin interface, normalizes all fields internally.
*/ */
register(plugin: IPlugin): void { register(plugin: IRuntimePlugin): void {
if (!plugin) { if (!plugin) {
logger.error('Cannot register plugin: plugin is null or undefined'); logger.error('Cannot register plugin: plugin is null or undefined');
return; return;

View File

@@ -14,10 +14,17 @@ export interface ComponentTypeInfo {
} }
/** /**
* 管理编辑器中可用的组件类型 * 编辑器组件注册表
* Editor Component Registry
*
* 管理编辑器中可用的组件类型元数据(名称、分类、图标等)。
* 与 ECS 核心的 ComponentRegistry管理组件位掩码不同。
*
* Manages component type metadata (name, category, icon, etc.) for the editor.
* Different from the ECS core ComponentRegistry (which manages component bitmasks).
*/ */
@Injectable() @Injectable()
export class ComponentRegistry implements IService { export class EditorComponentRegistry implements IService {
private components: Map<string, ComponentTypeInfo> = new Map(); private components: Map<string, ComponentTypeInfo> = new Map();
public dispose(): void { public dispose(): void {

View File

@@ -108,7 +108,7 @@ export type { IVector2, IVector3 } from '@esengine/ecs-framework-math';
// Rename conflicting exports to avoid collision with ecs-framework // Rename conflicting exports to avoid collision with ecs-framework
// ============================================================================= // =============================================================================
export { export {
ComponentRegistry as EditorComponentRegistry, EditorComponentRegistry,
} from '@esengine/editor-core'; } from '@esengine/editor-core';
export type { export type {
@@ -229,7 +229,7 @@ export type {
ModuleCategory, ModuleCategory,
ModulePlatform, ModulePlatform,
ModuleExports, ModuleExports,
IPlugin, IRuntimePlugin,
IRuntimeModule, IRuntimeModule,
SystemContext, SystemContext,
ComponentInspectorProviderDef, ComponentInspectorProviderDef,

View File

@@ -30,8 +30,7 @@
"dependencies": { "dependencies": {
"@esengine/ecs-framework": "workspace:*", "@esengine/ecs-framework": "workspace:*",
"@esengine/ecs-framework-math": "workspace:*", "@esengine/ecs-framework-math": "workspace:*",
"@esengine/platform-common": "workspace:*", "@esengine/platform-common": "workspace:*"
"@esengine/plugin-types": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@esengine/build-config": "workspace:*", "@esengine/build-config": "workspace:*",

View File

@@ -21,20 +21,93 @@ import type { ModuleManifest } from './ModuleManifest';
import { import {
TransformTypeToken, TransformTypeToken,
CanvasElementToken, CanvasElementToken,
EngineBridgeToken, TextureServiceToken,
type IEngineBridge DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
} from './PluginServiceRegistry'; } from './PluginServiceRegistry';
// 导出 engine-core 特有的服务令牌 | Export engine-core specific service tokens // 导出 engine-core 特有的服务令牌 | Export engine-core specific service tokens
export { export {
TransformTypeToken, TransformTypeToken,
CanvasElementToken, CanvasElementToken,
EngineBridgeToken, TextureServiceToken,
type IEngineBridge DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
}; };
// 重新导出 IEditorModuleBase供编辑器插件使用| Re-export for editor plugins // ============================================================================
export type { IEditorModuleBase } from '@esengine/plugin-types'; // 编辑器模块基础接口 | Editor Module Base Interface
// ============================================================================
/**
* 编辑器模块基础接口
* Base editor module interface
*
* 定义编辑器模块的核心生命周期方法。
* 完整的 IEditorModuleLoader 接口在 editor-core 中扩展此接口。
*
* Defines core lifecycle methods for editor modules.
* Full IEditorModuleLoader interface extends this in editor-core.
*/
export interface IEditorModuleBase {
/**
* 安装编辑器模块
* Install editor module
*/
install(services: ServiceContainer): Promise<void>;
/**
* 卸载编辑器模块
* Uninstall editor module
*/
uninstall?(): Promise<void>;
/**
* 编辑器就绪回调
* Editor ready callback
*/
onEditorReady?(): void | Promise<void>;
/**
* 项目打开回调
* Project open callback
*/
onProjectOpen?(projectPath: string): void | Promise<void>;
/**
* 项目关闭回调
* Project close callback
*/
onProjectClose?(): void | Promise<void>;
/**
* 场景加载回调
* Scene loaded callback
*/
onSceneLoaded?(scenePath: string): void;
/**
* 场景保存前回调
* Before scene save callback
*/
onSceneSaving?(scenePath: string): boolean | void;
/**
* 设置语言
* Set locale
*/
setLocale?(locale: string): void;
}
// ============================================================================ // ============================================================================
// 加载阶段 | Loading Phase // 加载阶段 | Loading Phase
@@ -155,7 +228,7 @@ export interface IRuntimeModule {
* @example * @example
* ```typescript * ```typescript
* // 纯运行时插件 | Pure runtime plugin * // 纯运行时插件 | Pure runtime plugin
* const MyPlugin: IPlugin = { * const MyPlugin: IRuntimePlugin = {
* manifest, * manifest,
* runtimeModule: new MyRuntimeModule() * runtimeModule: new MyRuntimeModule()
* }; * };
@@ -184,9 +257,6 @@ export interface IRuntimePlugin<TEditorModule = unknown> {
readonly editorModule?: TEditorModule; readonly editorModule?: TEditorModule;
} }
/** @deprecated Use IRuntimePlugin instead */
export type IPlugin<TEditorModule = unknown> = IRuntimePlugin<TEditorModule>;
// ============================================================================ // ============================================================================
// Engine Core 插件 | Engine Core Plugin // Engine Core 插件 | Engine Core Plugin
// ============================================================================ // ============================================================================
@@ -215,7 +285,7 @@ const manifest: ModuleManifest = {
} }
}; };
export const EnginePlugin: IPlugin = { export const EnginePlugin: IRuntimePlugin = {
manifest, manifest,
runtimeModule: new EngineRuntimeModule() runtimeModule: new EngineRuntimeModule()
}; };

View File

@@ -34,115 +34,46 @@ export const TransformTypeToken = createServiceToken<new (...args: any[]) => any
export const CanvasElementToken = createServiceToken<HTMLCanvasElement>('canvasElement'); export const CanvasElementToken = createServiceToken<HTMLCanvasElement>('canvasElement');
// ============================================================================ // ============================================================================
// 引擎桥接接口 | Engine Bridge Interface // 渲染服务接口 | Render Service Interfaces
// ============================================================================ // ============================================================================
/** /**
* 引擎桥接接口 * 纹理服务接口
* Engine bridge interface * Texture service interface
* *
* 定义 WASM 引擎桥接的核心契约,供各模块使用 * 负责纹理的加载、状态查询和管理
* Defines the core contract of WASM engine bridge for modules to use. * Responsible for texture loading, state querying, and management.
*/ */
export interface IEngineBridge { export interface ITextureService {
/** 加载纹理 | Load texture */ /** 加载纹理 | Load texture */
loadTexture(id: number, url: string): Promise<void>; loadTexture(id: number, url: string): Promise<void>;
/** /** 获取纹理加载状态 | Get texture loading state */
* 屏幕坐标转世界坐标 getTextureState(id: number): string;
* Screen to world coordinate conversion
*/
screenToWorld(screenX: number, screenY: number): { x: number; y: number };
/** /** 检查纹理是否就绪 | Check if texture is ready */
* 世界坐标转屏幕坐标 isTextureReady(id: number): boolean;
* World to screen coordinate conversion
*/
worldToScreen(worldX: number, worldY: number): { x: number; y: number };
/** /** 获取正在加载的纹理数量 | Get loading texture count */
* 设置清除颜色 getTextureLoadingCount(): number;
* Set clear color
*/
setClearColor(r: number, g: number, b: number, a: number): void;
// ===== Texture State API (Optional) ===== /** 异步加载纹理(等待完成)| Load texture async (wait for completion) */
// ===== 纹理状态 API可选===== loadTextureAsync(id: number, url: string): Promise<void>;
/** /** 等待所有加载中的纹理完成 | Wait for all textures to load */
* 获取纹理加载状态 waitForAllTextures(timeout?: number): Promise<void>;
* 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 * Dynamic atlas service interface
* */
* @param id 纹理 ID | Texture ID export interface IDynamicAtlasService {
* @returns 纹理数据已加载则返回 true | true if texture data is loaded /** 创建空白纹理 | Create blank texture */
*/ createBlankTexture(width: number, height: number): number;
isTextureReady?(id: number): boolean;
/** /** 更新纹理区域 | Update texture region */
* 获取正在加载的纹理数量 updateTextureRegion(
* 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>;
// ===== Dynamic Atlas API (Optional) =====
// ===== 动态图集 API可选=====
/**
* 创建空白纹理(用于动态图集)
* Create blank texture (for dynamic atlas)
*
* @param width 宽度 | Width
* @param height 高度 | Height
* @returns 纹理 ID | Texture ID
*/
createBlankTexture?(width: number, height: number): number;
/**
* 更新纹理区域
* Update texture region
*
* @param id 纹理 ID | Texture ID
* @param x X 坐标 | X coordinate
* @param y Y 坐标 | Y coordinate
* @param width 宽度 | Width
* @param height 高度 | Height
* @param pixels RGBA 像素数据 | RGBA pixel data
*/
updateTextureRegion?(
id: number, id: number,
x: number, x: number,
y: number, y: number,
@@ -153,7 +84,38 @@ export interface IEngineBridge {
} }
/** /**
* 引擎桥接服务令牌 * 坐标转换服务接口
* Engine bridge service token * Coordinate transform service interface
*/ */
export const EngineBridgeToken = createServiceToken<IEngineBridge>('engineBridge'); export interface ICoordinateService {
/** 屏幕坐标转世界坐标 | Screen to world */
screenToWorld(screenX: number, screenY: number): { x: number; y: number };
/** 世界坐标转屏幕坐标 | World to screen */
worldToScreen(worldX: number, worldY: number): { x: number; y: number };
}
/**
* 渲染配置服务接口
* Render config service interface
*/
export interface IRenderConfigService {
/** 设置清除颜色 | Set clear color */
setClearColor(r: number, g: number, b: number, a: number): void;
}
// ============================================================================
// 服务令牌 | Service Tokens
// ============================================================================
/** 纹理服务令牌 | Texture service token */
export const TextureServiceToken = createServiceToken<ITextureService>('textureService');
/** 动态图集服务令牌 | Dynamic atlas service token */
export const DynamicAtlasServiceToken = createServiceToken<IDynamicAtlasService>('dynamicAtlasService');
/** 坐标转换服务令牌 | Coordinate service token */
export const CoordinateServiceToken = createServiceToken<ICoordinateService>('coordinateService');
/** 渲染配置服务令牌 | Render config service token */
export const RenderConfigServiceToken = createServiceToken<IRenderConfigService>('renderConfigService');

View File

@@ -13,10 +13,16 @@ export {
// Engine-specific service tokens // Engine-specific service tokens
TransformTypeToken, TransformTypeToken,
CanvasElementToken, CanvasElementToken,
EngineBridgeToken, TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
// Types // Types
type IEditorModuleBase, type IEditorModuleBase,
type IEngineBridge type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
} from './EnginePlugin'; } from './EnginePlugin';
// Module Manifest types (unified module/plugin configuration) // Module Manifest types (unified module/plugin configuration)

View File

@@ -22,7 +22,7 @@ import {
InspectorRegistry, InspectorRegistry,
EntityStoreService, EntityStoreService,
MessageHub, MessageHub,
ComponentRegistry, EditorComponentRegistry,
FileActionRegistry FileActionRegistry
} from '@esengine/editor-core'; } from '@esengine/editor-core';
import { TransformComponent } from '@esengine/engine-core'; import { TransformComponent } from '@esengine/engine-core';
@@ -56,7 +56,7 @@ export class ParticleEditorModule implements IEditorModuleLoader {
} }
// 注册组件到编辑器组件注册表 | Register to editor component registry // 注册组件到编辑器组件注册表 | Register to editor component registry
const componentRegistry = services.resolve(ComponentRegistry); const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) { if (componentRegistry) {
componentRegistry.register({ componentRegistry.register({
name: 'ParticleSystem', name: 'ParticleSystem',

View File

@@ -2,7 +2,7 @@ import type { IComponentRegistry, IScene } from '@esengine/ecs-framework';
import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core'; import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core';
import { TransformTypeToken, CanvasElementToken } from '@esengine/engine-core'; import { TransformTypeToken, CanvasElementToken } from '@esengine/engine-core';
import { AssetManagerToken } from '@esengine/asset-system'; import { AssetManagerToken } from '@esengine/asset-system';
import { RenderSystemToken, EngineBridgeToken, EngineIntegrationToken } from '@esengine/ecs-engine-bindgen'; import { RenderSystemToken, EngineIntegrationToken, TextureServiceToken, CoordinateServiceToken } from '@esengine/ecs-engine-bindgen';
import { Physics2DQueryToken } from '@esengine/physics-rapier2d'; import { Physics2DQueryToken } from '@esengine/physics-rapier2d';
import { ParticleSystemComponent } from './ParticleSystemComponent'; import { ParticleSystemComponent } from './ParticleSystemComponent';
import { ClickFxComponent } from './ClickFxComponent'; import { ClickFxComponent } from './ClickFxComponent';
@@ -30,7 +30,8 @@ class ParticleRuntimeModule implements IRuntimeModule {
const assetManager = context.services.get(AssetManagerToken); const assetManager = context.services.get(AssetManagerToken);
const transformType = context.services.get(TransformTypeToken); const transformType = context.services.get(TransformTypeToken);
const engineIntegration = context.services.get(EngineIntegrationToken); const engineIntegration = context.services.get(EngineIntegrationToken);
const engineBridge = context.services.get(EngineBridgeToken); const textureService = context.services.get(TextureServiceToken);
const coordinateService = context.services.get(CoordinateServiceToken);
const physics2DQuery = context.services.get(Physics2DQueryToken); const physics2DQuery = context.services.get(Physics2DQueryToken);
const renderSystem = context.services.get(RenderSystemToken); const renderSystem = context.services.get(RenderSystemToken);
@@ -60,9 +61,9 @@ class ParticleRuntimeModule implements IRuntimeModule {
this._updateSystem.setEngineIntegration(engineIntegration); this._updateSystem.setEngineIntegration(engineIntegration);
} }
// 设置引擎桥接(用于加载默认纹理)| Set engine bridge (for loading default texture) // 设置纹理服务(用于加载默认纹理)| Set texture service (for loading default texture)
if (engineBridge) { if (textureService) {
this._updateSystem.setEngineBridge(engineBridge); this._updateSystem.setTextureService(textureService);
} }
// 设置 2D 物理查询(用于粒子与场景碰撞)| Set 2D physics query (for particle-scene collision) // 设置 2D 物理查询(用于粒子与场景碰撞)| Set 2D physics query (for particle-scene collision)
@@ -77,10 +78,10 @@ class ParticleRuntimeModule implements IRuntimeModule {
// ClickFxSystem no longer needs AssetManager, assets are loaded by ParticleUpdateSystem // ClickFxSystem no longer needs AssetManager, assets are loaded by ParticleUpdateSystem
const clickFxSystem = new ClickFxSystem(); const clickFxSystem = new ClickFxSystem();
// 设置 EngineBridge(用于屏幕坐标转世界坐标) // 设置坐标服务(用于屏幕坐标转世界坐标)
// Set EngineBridge (for screen to world coordinate conversion) // Set coordinate service (for screen to world coordinate conversion)
if (engineBridge) { if (coordinateService) {
clickFxSystem.setEngineBridge(engineBridge); clickFxSystem.setCoordinateService(coordinateService);
} }
// 从服务注册表获取 Canvas 元素(用于计算相对坐标) // 从服务注册表获取 Canvas 元素(用于计算相对坐标)

View File

@@ -11,23 +11,11 @@ import { Input, MouseButton, TransformComponent, SortingLayers } from '@esengine
import { ClickFxComponent, ClickFxTriggerMode } from '../ClickFxComponent'; import { ClickFxComponent, ClickFxTriggerMode } from '../ClickFxComponent';
import { ParticleSystemComponent, RenderSpace } from '../ParticleSystemComponent'; import { ParticleSystemComponent, RenderSpace } from '../ParticleSystemComponent';
import { CoordinateServiceToken, type ICoordinateService } from '@esengine/ecs-engine-bindgen';
// ============================================================================ // ============================================================================
// 本地服务令牌定义 | Local Service Token Definitions // 本地服务令牌定义 | Local Service Token Definitions
// ============================================================================ // ============================================================================
// 使用 createServiceToken() 本地定义(与 runtime-core 相同策略)
// createServiceToken() 使用 Symbol.for(),确保运行时与源模块令牌匹配
//
// Local token definitions using createServiceToken() (same strategy as runtime-core)
// createServiceToken() uses Symbol.for(), ensuring runtime match with source module tokens
// ============================================================================
/**
* EngineBridge 接口(最小定义,用于坐标转换)
* EngineBridge interface (minimal definition for coordinate conversion)
*/
interface IEngineBridge {
screenToWorld(screenX: number, screenY: number): { x: number; y: number };
}
/** /**
* EngineRenderSystem 接口(最小定义,用于获取 UI Canvas 尺寸) * EngineRenderSystem 接口(最小定义,用于获取 UI Canvas 尺寸)
@@ -37,10 +25,6 @@ interface IEngineRenderSystem {
getUICanvasSize(): { width: number; height: number }; getUICanvasSize(): { width: number; height: number };
} }
// EngineBridge 令牌(与 engine-core 中的一致)
// EngineBridge token (consistent with engine-core)
const EngineBridgeToken = createServiceToken<IEngineBridge>('engineBridge');
// RenderSystem 令牌(与 ecs-engine-bindgen 中的一致) // RenderSystem 令牌(与 ecs-engine-bindgen 中的一致)
// RenderSystem token (consistent with ecs-engine-bindgen) // RenderSystem token (consistent with ecs-engine-bindgen)
const RenderSystemToken = createServiceToken<IEngineRenderSystem>('renderSystem'); const RenderSystemToken = createServiceToken<IEngineRenderSystem>('renderSystem');
@@ -62,7 +46,7 @@ const RenderSystemToken = createServiceToken<IEngineRenderSystem>('renderSystem'
*/ */
@ECSSystem('ClickFx', { updateOrder: 100 }) @ECSSystem('ClickFx', { updateOrder: 100 })
export class ClickFxSystem extends EntitySystem { export class ClickFxSystem extends EntitySystem {
private _engineBridge: IEngineBridge | null = null; private _coordinateService: ICoordinateService | null = null;
private _renderSystem: IEngineRenderSystem | null = null; private _renderSystem: IEngineRenderSystem | null = null;
private _entitiesToDestroy: Entity[] = []; private _entitiesToDestroy: Entity[] = [];
private _canvas: HTMLCanvasElement | null = null; private _canvas: HTMLCanvasElement | null = null;
@@ -72,20 +56,20 @@ export class ClickFxSystem extends EntitySystem {
} }
/** /**
* 设置服务注册表(用于获取 EngineBridge 和 RenderSystem * 设置服务注册表(用于获取 CoordinateService 和 RenderSystem
* Set service registry (for getting EngineBridge and RenderSystem) * Set service registry (for getting CoordinateService and RenderSystem)
*/ */
setServiceRegistry(services: PluginServiceRegistry): void { setServiceRegistry(services: PluginServiceRegistry): void {
this._engineBridge = services.get(EngineBridgeToken) ?? null; this._coordinateService = services.get(CoordinateServiceToken) ?? null;
this._renderSystem = services.get(RenderSystemToken) ?? null; this._renderSystem = services.get(RenderSystemToken) ?? null;
} }
/** /**
* 设置 EngineBridge(直接注入) * 设置坐标服务(直接注入)
* Set EngineBridge (direct injection) * Set coordinate service (direct injection)
*/ */
setEngineBridge(bridge: IEngineBridge): void { setCoordinateService(coordinateService: ICoordinateService): void {
this._engineBridge = bridge; this._coordinateService = coordinateService;
} }
/** /**

View File

@@ -1,5 +1,5 @@
import { EntitySystem, Matcher, ECSSystem, Time, Entity, type Component, type ComponentType } from '@esengine/ecs-framework'; import { EntitySystem, Matcher, ECSSystem, Time, Entity, type Component, type ComponentType } from '@esengine/ecs-framework';
import type { IEngineIntegration, IEngineBridge } from '@esengine/ecs-engine-bindgen'; import type { IEngineIntegration, ITextureService } from '@esengine/ecs-engine-bindgen';
import type { IAssetManager } from '@esengine/asset-system'; import type { IAssetManager } from '@esengine/asset-system';
import { ParticleSystemComponent } from '../ParticleSystemComponent'; import { ParticleSystemComponent } from '../ParticleSystemComponent';
import { ParticleRenderDataProvider } from '../rendering/ParticleRenderDataProvider'; import { ParticleRenderDataProvider } from '../rendering/ParticleRenderDataProvider';
@@ -78,7 +78,7 @@ export class ParticleUpdateSystem extends EntitySystem {
private _transformType: ComponentType<Component & ITransformComponent> | null = null; private _transformType: ComponentType<Component & ITransformComponent> | null = null;
private _renderDataProvider: ParticleRenderDataProvider; private _renderDataProvider: ParticleRenderDataProvider;
private _engineIntegration: IEngineIntegration | null = null; private _engineIntegration: IEngineIntegration | null = null;
private _engineBridge: IEngineBridge | null = null; private _textureService: ITextureService | null = null;
private _physics2DQuery: IPhysics2DQuery | null = null; private _physics2DQuery: IPhysics2DQuery | null = null;
private _assetManager: IAssetManager | null = null; private _assetManager: IAssetManager | null = null;
private _defaultTextureLoaded: boolean = false; private _defaultTextureLoaded: boolean = false;
@@ -114,11 +114,11 @@ export class ParticleUpdateSystem extends EntitySystem {
} }
/** /**
* 设置引擎桥接(用于加载默认纹理) * 设置纹理服务(用于加载默认纹理)
* Set engine bridge (for loading default texture) * Set texture service (for loading default texture)
*/ */
setEngineBridge(bridge: IEngineBridge): void { setTextureService(textureService: ITextureService): void {
this._engineBridge = bridge; this._textureService = textureService;
} }
/** /**
@@ -487,8 +487,8 @@ export class ParticleUpdateSystem extends EntitySystem {
} }
// 没有引擎桥接,无法加载 | No engine bridge, cannot load // 没有引擎桥接,无法加载 | No engine bridge, cannot load
if (!this._engineBridge) { if (!this._textureService) {
console.warn('[ParticleUpdateSystem] EngineBridge not set, cannot load default texture'); console.warn('[ParticleUpdateSystem] TextureService not set, cannot load default texture');
return false; return false;
} }
@@ -496,15 +496,9 @@ export class ParticleUpdateSystem extends EntitySystem {
try { try {
const dataUrl = generateDefaultParticleTextureDataURL(); const dataUrl = generateDefaultParticleTextureDataURL();
if (dataUrl) { if (dataUrl) {
// 优先使用 loadTextureAsync等待纹理就绪 // 使用 loadTextureAsync等待纹理就绪
// Prefer loadTextureAsync (waits for texture ready) // Use loadTextureAsync (waits for texture ready)
if (this._engineBridge.loadTextureAsync) { await this._textureService.loadTextureAsync(DEFAULT_PARTICLE_TEXTURE_ID, dataUrl);
await this._engineBridge.loadTextureAsync(DEFAULT_PARTICLE_TEXTURE_ID, dataUrl);
} else {
// 回退到旧 API可能显示灰色占位符
// Fallback to old API (may show gray placeholder)
await this._engineBridge.loadTexture(DEFAULT_PARTICLE_TEXTURE_ID, dataUrl);
}
this._defaultTextureLoaded = true; this._defaultTextureLoaded = true;
} }
} catch (error) { } catch (error) {

View File

@@ -13,7 +13,7 @@ import type {
import { import {
EntityStoreService, EntityStoreService,
MessageHub, MessageHub,
ComponentRegistry, EditorComponentRegistry,
SettingsRegistry SettingsRegistry
} from '@esengine/editor-core'; } from '@esengine/editor-core';
import { TransformComponent } from '@esengine/engine-core'; import { TransformComponent } from '@esengine/engine-core';
@@ -48,7 +48,7 @@ export class Physics2DEditorModule implements IEditorModuleLoader {
this.setupSettingsListener(); this.setupSettingsListener();
// 注册组件到编辑器组件注册表 // 注册组件到编辑器组件注册表
const componentRegistry = services.resolve(ComponentRegistry); const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) { if (componentRegistry) {
componentRegistry.register({ componentRegistry.register({
name: 'Rigidbody2D', name: 'Rigidbody2D',

View File

@@ -18,7 +18,7 @@ import {
BrowserFileSystemService, BrowserFileSystemService,
RuntimeSceneManager, RuntimeSceneManager,
RuntimeSceneManagerToken, RuntimeSceneManagerToken,
type IPlugin, type IRuntimePlugin,
type IRuntimeSceneManager type IRuntimeSceneManager
} from '@esengine/runtime-core'; } from '@esengine/runtime-core';
import { isValidGUID, setGlobalAssetFileLoader, type IAssetManager, type IAssetFileLoader } from '@esengine/asset-system'; import { isValidGUID, setGlobalAssetFileLoader, type IAssetManager, type IAssetFileLoader } from '@esengine/asset-system';
@@ -75,7 +75,7 @@ export class BrowserRuntime {
* *
* Call this before initialize() to register plugins. * Call this before initialize() to register plugins.
*/ */
registerPlugin(plugin: IPlugin): void { registerPlugin(plugin: IRuntimePlugin): void {
if (plugin) { if (plugin) {
runtimePluginManager.register(plugin); runtimePluginManager.register(plugin);
runtimePluginManager.enable(plugin.manifest.id); runtimePluginManager.enable(plugin.manifest.id);
@@ -87,7 +87,7 @@ export class BrowserRuntime {
* Register multiple plugins * Register multiple plugins
* 注册多个插件 * 注册多个插件
*/ */
registerPlugins(plugins: IPlugin[]): void { registerPlugins(plugins: IRuntimePlugin[]): void {
for (const plugin of plugins) { for (const plugin of plugins) {
this.registerPlugin(plugin); this.registerPlugin(plugin);
} }

View File

@@ -1,47 +0,0 @@
{
"name": "@esengine/plugin-types",
"version": "1.0.0",
"description": "Plugin system type definitions for ES Engine",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsup",
"build:watch": "tsup --watch",
"clean": "rimraf dist",
"type-check": "tsc --noEmit"
},
"keywords": [
"ecs",
"plugin",
"types",
"typescript"
],
"author": "yhh",
"license": "MIT",
"devDependencies": {
"@esengine/ecs-framework": "workspace:*",
"@esengine/build-config": "workspace:*",
"rimraf": "^5.0.0",
"tsup": "^8.0.0",
"typescript": "^5.8.3"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/esengine/esengine.git",
"directory": "packages/plugin-types"
}
}

View File

@@ -1,202 +0,0 @@
/**
* 插件系统基础类型定义
* Plugin system base type definitions
*
* 这个包只提供用于打破循环依赖的基础接口。
* 完整的类型定义在 engine-core 中。
*
* This package only provides base interfaces to break circular dependencies.
* Complete type definitions are in engine-core.
*
* 导出内容 | Exports:
* - ServiceToken / createServiceToken / PluginServiceRegistry: 服务令牌系统
* - IEditorModuleBase: 编辑器模块基础接口(用于 IPlugin.editorModule 类型)
*
* 不导出(在 engine-core 中定义)| Not exported (defined in engine-core):
* - IPlugin, IRuntimeModule, SystemContext: 完整的插件类型
* - ModuleManifest: 完整的模块清单类型
* - LoadingPhase: 加载阶段类型
*/
import type { ServiceContainer } from '@esengine/ecs-framework';
// ============================================================================
// 服务令牌 | Service Token
// ============================================================================
/**
* 服务令牌接口
* Service token interface
*
* 用于类型安全的服务注册和获取。
* For type-safe service registration and retrieval.
*
* 注意__phantom 是必需属性(使用 declare 避免运行时开销),
* 这确保 TypeScript 在跨包类型解析时保留泛型类型信息。
*
* Note: __phantom is a required property (using declare to avoid runtime overhead),
* which ensures TypeScript preserves generic type information across packages.
*/
export interface ServiceToken<T> {
readonly id: symbol;
readonly name: string;
/**
* Phantom type 标记(强制类型推断)
* Phantom type marker (enforces type inference)
*
* 使用 declare 声明,不会在运行时占用内存。
* Declared with 'declare', no runtime memory overhead.
*/
readonly __phantom: T;
}
/**
* 创建服务令牌
* Create a service token
*
* @param name 令牌名称 | Token name
* @returns 服务令牌 | Service token
*/
export function createServiceToken<T>(name: string): ServiceToken<T> {
// __phantom 仅用于类型推断,不需要实际值
// __phantom is only for type inference, no actual value needed
return {
id: Symbol(name),
name
} as ServiceToken<T>;
}
// ============================================================================
// 插件服务注册表 | Plugin Service Registry
// ============================================================================
/**
* 插件服务注册表
* Plugin service registry
*
* 用于跨插件共享服务的类型安全注册表。
* Type-safe registry for sharing services between plugins.
*/
export class PluginServiceRegistry {
private _services = new Map<symbol, unknown>();
/**
* 注册服务
* Register a service
*/
register<T>(token: ServiceToken<T>, service: T): void {
this._services.set(token.id, service);
}
/**
* 获取服务(可选)
* Get a service (optional)
*/
get<T>(token: ServiceToken<T>): T | undefined {
return this._services.get(token.id) as T | undefined;
}
/**
* 获取服务(必需)
* Get a service (required)
*
* @throws 如果服务未注册 | If service is not registered
*/
require<T>(token: ServiceToken<T>): T {
const service = this._services.get(token.id);
if (service === undefined) {
throw new Error(`Service not found: ${token.name}`);
}
return service as T;
}
/**
* 检查服务是否已注册
* Check if a service is registered
*/
has<T>(token: ServiceToken<T>): boolean {
return this._services.has(token.id);
}
/**
* 注销服务
* Unregister a service
*/
unregister<T>(token: ServiceToken<T>): boolean {
return this._services.delete(token.id);
}
/**
* 清空所有服务
* Clear all services
*/
clear(): void {
this._services.clear();
}
}
// ============================================================================
// 编辑器模块基础接口 | Editor Module Base Interface
// ============================================================================
/**
* 编辑器模块基础接口
* Base editor module interface
*
* 定义编辑器模块的核心生命周期方法。
* 这个接口用于 IPlugin.editorModule 的类型定义,避免 engine-core 依赖 editor-core。
* 完整的 IEditorModuleLoader 接口在 editor-core 中扩展此接口。
*
* Defines core lifecycle methods for editor modules.
* This interface is used for IPlugin.editorModule type to avoid engine-core depending on editor-core.
* Full IEditorModuleLoader interface extends this in editor-core.
*/
export interface IEditorModuleBase {
/**
* 安装编辑器模块
* Install editor module
*/
install(services: ServiceContainer): Promise<void>;
/**
* 卸载编辑器模块
* Uninstall editor module
*/
uninstall?(): Promise<void>;
/**
* 编辑器就绪回调
* Editor ready callback
*/
onEditorReady?(): void | Promise<void>;
/**
* 项目打开回调
* Project open callback
*/
onProjectOpen?(projectPath: string): void | Promise<void>;
/**
* 项目关闭回调
* Project close callback
*/
onProjectClose?(): void | Promise<void>;
/**
* 场景加载回调
* Scene loaded callback
*/
onSceneLoaded?(scenePath: string): void;
/**
* 场景保存前回调
* Before scene save callback
*/
onSceneSaving?(scenePath: string): boolean | void;
/**
* 设置语言
* Set locale
*/
setLocale?(locale: string): void;
}

View File

@@ -1,8 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true,
"declarationMap": true
},
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
}

View File

@@ -1,17 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020", "DOM"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"declarationMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -1,14 +0,0 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
tsconfig: 'tsconfig.build.json',
external: [
'@esengine/ecs-framework'
]
});

View File

@@ -10,9 +10,12 @@ import { Core, Scene, SceneSerializer, HierarchySystem, PluginServiceRegistry, c
import { import {
EngineBridge, EngineBridge,
EngineRenderSystem, EngineRenderSystem,
EngineBridgeToken,
RenderSystemToken, RenderSystemToken,
EngineIntegrationToken, EngineIntegrationToken,
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
type IUIRenderDataProvider type IUIRenderDataProvider
} from '@esengine/ecs-engine-bindgen'; } from '@esengine/ecs-engine-bindgen';
import { import {
@@ -360,7 +363,11 @@ export class GameRuntime {
const services = new PluginServiceRegistry(); const services = new PluginServiceRegistry();
// 注册核心服务 | Register core services // 注册核心服务 | Register core services
services.register(EngineBridgeToken, this._bridge); // 使用单一职责接口注册 EngineBridge | Register EngineBridge with single-responsibility interfaces
services.register(TextureServiceToken, this._bridge);
services.register(DynamicAtlasServiceToken, this._bridge);
services.register(CoordinateServiceToken, this._bridge);
services.register(RenderConfigServiceToken, this._bridge);
services.register(RenderSystemToken, this._renderSystem); services.register(RenderSystemToken, this._renderSystem);
services.register(EngineIntegrationToken, this._engineIntegration); services.register(EngineIntegrationToken, this._engineIntegration);
services.register(AssetManagerToken, this._assetManager); services.register(AssetManagerToken, this._assetManager);

View File

@@ -7,9 +7,6 @@ export {
type IRuntimePlugin type IRuntimePlugin
} from './PluginManager'; } from './PluginManager';
/** @deprecated Use IRuntimePlugin instead */
export type { IRuntimePlugin as IPlugin } from './PluginManager';
export { export {
createPlugin, createPlugin,
registerPlugin, registerPlugin,
@@ -123,13 +120,21 @@ export { TransformTypeToken } from '@esengine/engine-core';
// Re-export service tokens from their respective modules // Re-export service tokens from their respective modules
export { export {
EngineBridgeToken,
RenderSystemToken, RenderSystemToken,
EngineIntegrationToken, EngineIntegrationToken,
type IEngineBridge, // 新的单一职责服务令牌 | New single-responsibility service tokens
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
// 类型 | Types
type IRenderSystem, type IRenderSystem,
type IRenderDataProvider, type IRenderDataProvider,
type IEngineIntegration type IEngineIntegration,
type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
} from '@esengine/ecs-engine-bindgen'; } from '@esengine/ecs-engine-bindgen';
export { export {

View File

@@ -16,7 +16,7 @@ import type {
import { import {
EntityStoreService, EntityStoreService,
MessageHub, MessageHub,
ComponentRegistry, EditorComponentRegistry,
ComponentInspectorRegistry ComponentInspectorRegistry
} from '@esengine/editor-core'; } from '@esengine/editor-core';
import { TransformComponent } from '@esengine/engine-core'; import { TransformComponent } from '@esengine/engine-core';
@@ -47,7 +47,7 @@ export class SpriteEditorModule implements IEditorModuleLoader {
} }
// 注册 Sprite 组件到编辑器组件注册表 | Register Sprite components to editor component registry // 注册 Sprite 组件到编辑器组件注册表 | Register Sprite components to editor component registry
const componentRegistry = services.resolve(ComponentRegistry); const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) { if (componentRegistry) {
const spriteComponents = [ const spriteComponents = [
{ {

View File

@@ -20,7 +20,7 @@ import {
InspectorRegistry, InspectorRegistry,
EntityStoreService, EntityStoreService,
MessageHub, MessageHub,
ComponentRegistry, EditorComponentRegistry,
IDialogService, IDialogService,
IFileSystemService, IFileSystemService,
FileActionRegistry FileActionRegistry
@@ -72,7 +72,7 @@ export class TilemapEditorModule implements IEditorModuleLoader {
} }
// 注册组件到编辑器组件注册表 | Register to editor component registry // 注册组件到编辑器组件注册表 | Register to editor component registry
const componentRegistry = services.resolve(ComponentRegistry); const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) { if (componentRegistry) {
componentRegistry.register({ componentRegistry.register({
name: 'Tilemap', name: 'Tilemap',

View File

@@ -14,7 +14,7 @@ import type {
import { import {
EntityStoreService, EntityStoreService,
MessageHub, MessageHub,
ComponentRegistry, EditorComponentRegistry,
ComponentInspectorRegistry ComponentInspectorRegistry
} from '@esengine/editor-core'; } from '@esengine/editor-core';
@@ -47,7 +47,7 @@ export { registerUITransformGizmo, unregisterUITransformGizmo } from './gizmos';
export class UIEditorModule implements IEditorModuleLoader { export class UIEditorModule implements IEditorModuleLoader {
async install(services: ServiceContainer): Promise<void> { async install(services: ServiceContainer): Promise<void> {
// 注册 UI 组件到编辑器组件注册表 | Register UI components to editor component registry // 注册 UI 组件到编辑器组件注册表 | Register UI components to editor component registry
const componentRegistry = services.resolve(ComponentRegistry); const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) { if (componentRegistry) {
const uiComponents = [ const uiComponents = [
{ name: 'UITransform', type: UITransformComponent, category: 'components.category.ui', description: 'UI element positioning and sizing', icon: 'Move' }, { name: 'UITransform', type: UITransformComponent, category: 'components.category.ui', description: 'UI element positioning and sizing', icon: 'Move' },

View File

@@ -1,6 +1,11 @@
import type { IScene, IComponentRegistry } from '@esengine/ecs-framework'; import type { IScene, IComponentRegistry } from '@esengine/ecs-framework';
import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core'; import type { IRuntimeModule, IRuntimePlugin, ModuleManifest, SystemContext } from '@esengine/engine-core';
import { EngineBridgeToken } from '@esengine/ecs-engine-bindgen'; import {
TextureServiceToken,
DynamicAtlasServiceToken,
type ITextureService,
type IDynamicAtlasService
} from '@esengine/ecs-engine-bindgen';
import { EngineIntegration } from '@esengine/asset-system'; import { EngineIntegration } from '@esengine/asset-system';
import { initializeDynamicAtlasService, registerTexturePathMapping, AtlasExpansionStrategy, type IAtlasEngineBridge } from './atlas'; import { initializeDynamicAtlasService, registerTexturePathMapping, AtlasExpansionStrategy, type IAtlasEngineBridge } from './atlas';
@@ -77,7 +82,8 @@ class UIRuntimeModule implements IRuntimeModule {
createSystems(scene: IScene, context: SystemContext): void { createSystems(scene: IScene, context: SystemContext): void {
// 从服务注册表获取依赖 | Get dependencies from service registry // 从服务注册表获取依赖 | Get dependencies from service registry
const engineBridge = context.services.get(EngineBridgeToken); const textureService = context.services.get(TextureServiceToken);
const dynamicAtlasService = context.services.get(DynamicAtlasServiceToken);
// Slider fill control system (runs before layout to modify anchors) // Slider fill control system (runs before layout to modify anchors)
// 滑块填充控制系统(在布局之前运行以修改锚点) // 滑块填充控制系统(在布局之前运行以修改锚点)
@@ -133,34 +139,30 @@ class UIRuntimeModule implements IRuntimeModule {
const textRenderSystem = new UITextRenderSystem(); const textRenderSystem = new UITextRenderSystem();
scene.addSystem(textRenderSystem); scene.addSystem(textRenderSystem);
if (engineBridge) { if (textureService) {
// 设置文本渲染系统的纹理回调 // 设置文本渲染系统的纹理回调
// Set texture callback for text render system // Set texture callback for text render system
textRenderSystem.setTextureCallback((id: number, dataUrl: string) => { textRenderSystem.setTextureCallback((id: number, dataUrl: string) => {
engineBridge.loadTexture(id, dataUrl); textureService.loadTexture(id, dataUrl);
}); });
// 设置纹理就绪检查回调,用于检测异步加载的纹理是否已就绪 // 设置纹理就绪检查回调,用于检测异步加载的纹理是否已就绪
// Set texture ready checker callback to detect if async-loaded texture is ready // Set texture ready checker callback to detect if async-loaded texture is ready
if (engineBridge.isTextureReady) { textRenderSystem.setTextureReadyChecker((id: number) => {
textRenderSystem.setTextureReadyChecker((id: number) => { return textureService.isTextureReady(id);
return engineBridge.isTextureReady!(id); });
});
}
// 设置输入框渲染系统的纹理回调 // 设置输入框渲染系统的纹理回调
// Set texture callback for input field render system // Set texture callback for input field render system
inputFieldRenderSystem.setTextureCallback((id: number, dataUrl: string) => { inputFieldRenderSystem.setTextureCallback((id: number, dataUrl: string) => {
engineBridge.loadTexture(id, dataUrl); textureService.loadTexture(id, dataUrl);
}); });
// 设置输入框渲染系统的纹理就绪检查回调 // 设置输入框渲染系统的纹理就绪检查回调
// Set texture ready checker callback for input field render system // Set texture ready checker callback for input field render system
if (engineBridge.isTextureReady) { inputFieldRenderSystem.setTextureReadyChecker((id: number) => {
inputFieldRenderSystem.setTextureReadyChecker((id: number) => { return textureService.isTextureReady(id);
return engineBridge.isTextureReady!(id); });
});
}
} }
const uiRenderProvider = new UIRenderDataProvider(); const uiRenderProvider = new UIRenderDataProvider();
@@ -175,17 +177,15 @@ class UIRuntimeModule implements IRuntimeModule {
context.services.register(UITextRenderSystemToken, textRenderSystem); context.services.register(UITextRenderSystemToken, textRenderSystem);
// 初始化动态图集服务 | Initialize dynamic atlas service // 初始化动态图集服务 | Initialize dynamic atlas service
// 需要 engineBridge 支持 createBlankTexture 和 updateTextureRegion // 需要 dynamicAtlasService 支持 createBlankTexture 和 updateTextureRegion
// Requires engineBridge to support createBlankTexture and updateTextureRegion // Requires dynamicAtlasService to support createBlankTexture and updateTextureRegion
console.log('[UIRuntimeModule] engineBridge available:', !!engineBridge); console.log('[UIRuntimeModule] dynamicAtlasService available:', !!dynamicAtlasService);
console.log('[UIRuntimeModule] createBlankTexture:', !!engineBridge?.createBlankTexture); if (dynamicAtlasService) {
console.log('[UIRuntimeModule] updateTextureRegion:', !!engineBridge?.updateTextureRegion); // 创建适配器将 IDynamicAtlasService 适配为 IAtlasEngineBridge
if (engineBridge?.createBlankTexture && engineBridge?.updateTextureRegion) { // Create adapter to adapt IDynamicAtlasService to IAtlasEngineBridge
// 创建适配器将 EngineBridge 适配为 IAtlasEngineBridge
// Create adapter to adapt EngineBridge to IAtlasEngineBridge
const atlasBridge: IAtlasEngineBridge = { const atlasBridge: IAtlasEngineBridge = {
createBlankTexture: (width: number, height: number) => { createBlankTexture: (width: number, height: number) => {
return engineBridge.createBlankTexture!(width, height); return dynamicAtlasService.createBlankTexture(width, height);
}, },
updateTextureRegion: ( updateTextureRegion: (
id: number, id: number,
@@ -195,7 +195,7 @@ class UIRuntimeModule implements IRuntimeModule {
height: number, height: number,
pixels: Uint8Array pixels: Uint8Array
) => { ) => {
engineBridge.updateTextureRegion!(id, x, y, width, height, pixels); dynamicAtlasService.updateTextureRegion(id, x, y, width, height, pixels);
} }
}; };
@@ -218,7 +218,7 @@ class UIRuntimeModule implements IRuntimeModule {
registerTexturePathMapping(guid, path); registerTexturePathMapping(guid, path);
}); });
} else { } else {
console.warn('[UIRuntimeModule] Cannot initialize dynamic atlas service: engineBridge missing createBlankTexture or updateTextureRegion'); console.warn('[UIRuntimeModule] Cannot initialize dynamic atlas service: dynamicAtlasService not available');
} }
} }
} }

View File

@@ -20,7 +20,7 @@ import {
InspectorRegistry, InspectorRegistry,
EntityStoreService, EntityStoreService,
MessageHub, MessageHub,
ComponentRegistry EditorComponentRegistry
} from '@esengine/editor-core'; } from '@esengine/editor-core';
import { TransformComponent } from '@esengine/engine-core'; import { TransformComponent } from '@esengine/engine-core';
import { import {
@@ -47,7 +47,7 @@ export class WorldStreamingEditorModule implements IEditorModuleLoader {
inspectorRegistry.register(new StreamingAnchorInspectorProvider()); inspectorRegistry.register(new StreamingAnchorInspectorProvider());
} }
const componentRegistry = services.resolve(ComponentRegistry); const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) { if (componentRegistry) {
componentRegistry.register({ componentRegistry.register({
name: 'ChunkLoader', name: 'ChunkLoader',

24
pnpm-lock.yaml generated
View File

@@ -777,9 +777,6 @@ importers:
'@esengine/engine-core': '@esengine/engine-core':
specifier: workspace:* specifier: workspace:*
version: link:../engine-core version: link:../engine-core
'@esengine/plugin-types':
specifier: workspace:*
version: link:../plugin-types
'@eslint/js': '@eslint/js':
specifier: ^9.37.0 specifier: ^9.37.0
version: 9.39.1 version: 9.39.1
@@ -925,9 +922,6 @@ importers:
'@esengine/platform-common': '@esengine/platform-common':
specifier: workspace:* specifier: workspace:*
version: link:../platform-common version: link:../platform-common
'@esengine/plugin-types':
specifier: workspace:*
version: link:../plugin-types
devDependencies: devDependencies:
'@esengine/build-config': '@esengine/build-config':
specifier: workspace:* specifier: workspace:*
@@ -1331,24 +1325,6 @@ importers:
specifier: ^5.8.3 specifier: ^5.8.3
version: 5.9.3 version: 5.9.3
packages/plugin-types:
devDependencies:
'@esengine/build-config':
specifier: workspace:*
version: link:../build-config
'@esengine/ecs-framework':
specifier: workspace:*
version: link:../core
rimraf:
specifier: ^5.0.0
version: 5.0.10
tsup:
specifier: ^8.0.0
version: 8.5.1(@microsoft/api-extractor@7.55.1(@types/node@20.19.25))(@swc/core@1.15.3)(jiti@2.6.1)(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.1)
typescript:
specifier: ^5.8.3
version: 5.9.3
packages/rapier2d: packages/rapier2d:
devDependencies: devDependencies:
rimraf: rimraf: