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

View File

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

View File

@@ -4,18 +4,18 @@
*/
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';
@ECSSystem('Camera', { updateOrder: -100 })
export class CameraSystem extends EntitySystem {
private bridge: IEngineBridge;
private renderConfig: IRenderConfigService;
private lastAppliedCameraId: number | null = null;
constructor(bridge: IEngineBridge) {
constructor(renderConfig: IRenderConfigService) {
// Match entities with CameraComponent
super(Matcher.empty().all(CameraComponent));
this.bridge = bridge;
this.renderConfig = renderConfig;
}
protected override onBegin(): void {
@@ -47,6 +47,6 @@ export class CameraSystem extends EntitySystem {
const r = parseInt(bgColor.slice(1, 3), 16) / 255;
const g = parseInt(bgColor.slice(3, 5), 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
*
* 注意:构造函数参数使用 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;
/**
@@ -61,6 +65,51 @@ export interface ComponentEditorOptions {
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 装饰器
* Check if component has @ECSComponent decorator
@@ -69,7 +118,8 @@ export interface ComponentEditorOptions {
* @returns 是否有装饰器
*/
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 {
// 优先使用装饰器指定的名称
// Prefer decorator-specified name
const decoratorName = (componentType as any)[COMPONENT_TYPE_NAME];
const metadata = getComponentTypeMetadata(componentType);
const decoratorName = metadata[COMPONENT_TYPE_NAME];
if (decoratorName) {
return decoratorName;
}
@@ -111,7 +162,8 @@ export function getComponentInstanceTypeName(component: Component): string {
* @returns 依赖的组件名称列表
*/
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 编辑器选项
*/
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_DEPENDENCIES,
COMPONENT_EDITOR_OPTIONS,
type ComponentEditorOptions
getWritableComponentTypeMetadata,
type ComponentEditorOptions,
type ComponentType
} from '../Core/ComponentStorage/ComponentTypeUtils';
/**
@@ -24,6 +26,50 @@ import {
*/
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
@@ -67,25 +113,29 @@ export interface 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') {
throw new Error('ECSComponent装饰器必须提供有效的类型名称');
}
// 获取可写的元数据对象
// Get writable metadata object
const metadata = getWritableComponentTypeMetadata(target);
// 在构造函数上存储类型名称
// Store type name on constructor
(target as any)[COMPONENT_TYPE_NAME] = typeName;
metadata[COMPONENT_TYPE_NAME] = typeName;
// 存储依赖关系
// Store dependencies
if (options?.requires) {
(target as any)[COMPONENT_DEPENDENCIES] = options.requires;
metadata[COMPONENT_DEPENDENCIES] = options.requires;
}
// 存储编辑器选项
// Store editor options
if (options?.editor) {
(target as any)[COMPONENT_EDITOR_OPTIONS] = options.editor;
metadata[COMPONENT_EDITOR_OPTIONS] = options.editor;
}
// 自动注册到全局 ComponentRegistry使组件可以通过名称查找
@@ -154,19 +204,23 @@ export interface 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') {
throw new Error('ECSSystem装饰器必须提供有效的类型名称');
}
// 获取可写的元数据对象
// Get writable metadata object
const meta = getWritableSystemTypeMetadata(target);
// 在构造函数上存储类型名称
// Store type name on constructor
(target as any)[SYSTEM_TYPE_NAME] = typeName;
meta[SYSTEM_TYPE_NAME] = typeName;
// 存储元数据
// Store metadata
if (metadata) {
(target as any).__systemMetadata__ = metadata;
meta.__systemMetadata__ = metadata;
}
return target;
@@ -177,8 +231,9 @@ export function ECSSystem(typeName: string, metadata?: SystemMetadata) {
* 获取 System 的元数据
* Get System metadata
*/
export function getSystemMetadata(systemType: new (...args: any[]) => EntitySystem): SystemMetadata | undefined {
return (systemType as any).__systemMetadata__;
export function getSystemMetadata(systemType: SystemConstructor): SystemMetadata | undefined {
const meta = getSystemTypeMetadata(systemType);
return meta.__systemMetadata__;
}
/**
@@ -189,7 +244,7 @@ export function getSystemMetadata(systemType: new (...args: any[]) => EntitySyst
* @returns 系统元数据 | System metadata
*/
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
*/
export function getSystemTypeName<T extends EntitySystem>(
systemType: new (...args: any[]) => T
systemType: SystemConstructor<T>
): string {
const decoratorName = (systemType as any)[SYSTEM_TYPE_NAME];
const meta = getSystemTypeMetadata(systemType);
const decoratorName = meta[SYSTEM_TYPE_NAME];
if (decoratorName) {
return decoratorName;
}
@@ -217,5 +273,5 @@ export function getSystemTypeName<T extends EntitySystem>(
* @returns 系统类型名称 | System type name
*/
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 { ITextureEngineBridge } from '@esengine/asset-system';
import type { GameEngine } from '../wasm/es_engine';
import type {
ITextureService,
IDynamicAtlasService,
ICoordinateService,
IRenderConfigService
} from '@esengine/engine-core';
/**
* Engine bridge configuration.
@@ -43,7 +49,7 @@ export interface EngineBridgeConfig {
* bridge.render();
* ```
*/
export class EngineBridge implements ITextureEngineBridge {
export class EngineBridge implements ITextureEngineBridge, ITextureService, IDynamicAtlasService, ICoordinateService, IRenderConfigService {
private engine: GameEngine | null = null;
private config: Required<EngineBridgeConfig>;
private initialized = false;

View File

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

View File

@@ -4,12 +4,31 @@
*/
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';
// 从 engine-core 重新导出 | Re-export from engine-core
export { CoreEngineBridgeToken as EngineBridgeToken };
export type { CoreIEngineBridge as IEngineBridge };
export {
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken
};
export type {
ITextureService,
IDynamicAtlasService,
ICoordinateService,
IRenderConfigService
};
export type IRenderDataProvider = InternalIRenderDataProvider;

View File

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

View File

@@ -7,7 +7,7 @@ import {
IMessageHub,
SerializerRegistry,
EntityStoreService,
ComponentRegistry,
EditorComponentRegistry,
ProjectService,
ComponentDiscoveryService,
PropertyMetadataService,
@@ -90,7 +90,7 @@ export interface EditorServices {
messageHub: MessageHub;
serializerRegistry: SerializerRegistry;
entityStore: EntityStoreService;
componentRegistry: ComponentRegistry;
componentRegistry: EditorComponentRegistry;
projectService: ProjectService;
componentDiscovery: ComponentDiscoveryService;
propertyMetadata: PropertyMetadataService;
@@ -121,7 +121,7 @@ export class ServiceRegistry {
const messageHub = new MessageHub();
const serializerRegistry = new SerializerRegistry();
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)
@@ -168,7 +168,7 @@ export class ServiceRegistry {
Core.services.registerInstance(IMessageHub, messageHub); // Symbol 注册用于跨包插件访问
Core.services.registerInstance(SerializerRegistry, serializerRegistry);
Core.services.registerInstance(EntityStoreService, entityStore);
Core.services.registerInstance(ComponentRegistry, componentRegistry);
Core.services.registerInstance(EditorComponentRegistry, componentRegistry);
Core.services.registerInstance(ProjectService, projectService);
Core.services.registerInstance(ComponentDiscoveryService, componentDiscovery);
Core.services.registerInstance(PropertyMetadataService, propertyMetadata);

View File

@@ -1,5 +1,5 @@
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 { BaseCommand } from '../BaseCommand';
@@ -55,7 +55,7 @@ export class AddComponentCommand extends BaseCommand {
return;
}
const componentRegistry = Core.services.tryResolve(ComponentRegistry) as ComponentRegistry | null;
const componentRegistry = Core.services.tryResolve(EditorComponentRegistry) as EditorComponentRegistry | null;
if (!componentRegistry) {
return;
}

View File

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

View File

@@ -1,7 +1,7 @@
import { useState, useRef, useEffect, useMemo, useCallback } from '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 { 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 { NotificationService } from '../../../services/NotificationService';
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';
// 从 ComponentRegistry category 到 CategoryFilter 的映射
// 从 EditorComponentRegistry category 到 CategoryFilter 的映射
const categoryKeyMap: Record<string, CategoryFilter> = {
'components.category.core': 'general',
'components.category.rendering': 'rendering',
@@ -84,7 +84,7 @@ export function EntityInspector({
const addButtonRef = useRef<HTMLButtonElement>(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 componentInspectorRegistry = Core.services.resolve(ComponentInspectorRegistry);
const prefabService = Core.services.tryResolve(PrefabService) as PrefabService | null;

View File

@@ -8,7 +8,7 @@
import type { ServiceContainer } 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';
const logger = createLogger('AssetMetaPlugin');
@@ -65,7 +65,7 @@ const manifest: ModuleManifest = {
exports: {}
};
export const AssetMetaPlugin: IPlugin = {
export const AssetMetaPlugin: IEditorPlugin = {
manifest,
editorModule: new AssetMetaEditorModule()
};

View File

@@ -5,7 +5,7 @@
import type { ServiceContainer } 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 { SettingsService } from '../../services/SettingsService';
@@ -146,7 +146,7 @@ const manifest: ModuleManifest = {
exports: {}
};
export const EditorAppearancePlugin: IPlugin = {
export const EditorAppearancePlugin: IEditorPlugin = {
manifest,
editorModule: new EditorAppearanceEditorModule()
};

View File

@@ -4,7 +4,7 @@
*/
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';
/**
@@ -42,7 +42,7 @@ const manifest: ModuleManifest = {
}
};
export const GizmoPlugin: IPlugin = {
export const GizmoPlugin: IEditorPlugin = {
manifest,
editorModule: new GizmoEditorModule()
};

View File

@@ -5,7 +5,7 @@
import type { ServiceContainer } 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';
const logger = createLogger('PluginConfigPlugin');
@@ -69,7 +69,7 @@ const manifest: ModuleManifest = {
exports: {}
};
export const PluginConfigPlugin: IPlugin = {
export const PluginConfigPlugin: IEditorPlugin = {
manifest,
editorModule: new PluginConfigEditorModule()
};

View File

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

View File

@@ -8,7 +8,7 @@
import type { ServiceContainer } 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 EngineService from '../../services/EngineService';
@@ -306,7 +306,7 @@ const manifest: ModuleManifest = {
exports: {}
};
export const ProjectSettingsPlugin: IPlugin = {
export const ProjectSettingsPlugin: IEditorPlugin = {
manifest,
editorModule: new ProjectSettingsEditorModule()
};

View File

@@ -6,7 +6,7 @@
import { Core, Entity } from '@esengine/ecs-framework';
import type { ServiceContainer } from '@esengine/ecs-framework';
import type {
IPlugin,
IEditorPlugin,
IEditorModuleLoader,
ModuleManifest,
PanelDescriptor,
@@ -191,7 +191,7 @@ const manifest: ModuleManifest = {
}
};
export const SceneInspectorPlugin: IPlugin = {
export const SceneInspectorPlugin: IEditorPlugin = {
manifest,
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 { 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 { SpriteComponent, SpriteAnimatorComponent, SpriteAnimatorSystemToken } from '@esengine/sprite';
import { ParticleSystemComponent } from '@esengine/particle';
@@ -252,7 +260,11 @@ export class EngineService {
// 创建服务注册表并注册核心服务
// Create service registry and register core services
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(AssetManagerToken, this._assetManager);
services.register(EngineIntegrationToken, this._engineIntegration);

View File

@@ -4,7 +4,7 @@
*/
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 { TauriAPI } from '../api/tauri';
import { PluginSDKRegistry } from './PluginSDKRegistry';
@@ -164,7 +164,7 @@ export class PluginLoader {
code: string,
pluginName: string,
_pluginDirName: string
): Promise<IPlugin | null> {
): Promise<IRuntimePlugin | null> {
const pluginKey = this.sanitizePluginKey(pluginName);
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 导出
if (module.default && this.isPluginLoader(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') {
return false;
}
// 新的 IPlugin 接口检查
// IRuntimePlugin 接口检查
if (obj.manifest && this.isModuleManifest(obj.manifest)) {
return true;
}
@@ -315,7 +315,7 @@ export class PluginLoader {
/**
* 同步插件语言设置
*/
private syncPluginLocale(plugin: IPlugin, pluginName: string): void {
private syncPluginLocale(plugin: IRuntimePlugin, pluginName: string): void {
try {
const localeService = Core.services.resolve(LocaleService);
const currentLocale = localeService.getCurrentLocale();

View File

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

View File

@@ -15,7 +15,7 @@ export type {
LoadingPhase,
SystemContext,
IRuntimeModule,
IPlugin,
IRuntimePlugin,
ModuleManifest,
ModuleCategory,
ModulePlatform,
@@ -309,17 +309,17 @@ export interface IEditorModuleLoader extends IEditorModuleBase {
// 编辑器插件类型 | Editor Plugin Type
// ============================================================================
import type { IPlugin } from './PluginDescriptor';
import type { IRuntimePlugin } from './PluginDescriptor';
/**
* 编辑器插件类型
* Editor plugin type
*
* 这是开发编辑器插件时应使用的类型。
* 它是 IPlugin 的特化版本editorModule 类型为 IEditorModuleLoader。
* 它是 IRuntimePlugin 的特化版本editorModule 类型为 IEditorModuleLoader。
*
* 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
* ```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.
*/
// 从 engine-core 导入类型
// Import types from engine-core
import type { IRuntimePlugin as IRuntimePluginBase } from '@esengine/engine-core';
// 从 engine-core 重新导出所有类型
// 包括 IEditorModuleBase原来在 plugin-types 中定义,现在统一从 engine-core 导出)
export type {
@@ -24,9 +20,6 @@ export type {
IEditorModuleBase
} from '@esengine/engine-core';
/** @deprecated Use IRuntimePlugin instead */
export type IPlugin<TEditorModule = unknown> = IRuntimePluginBase<TEditorModule>;
/**
* 插件状态
* 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 {
ModuleManifest,
IPlugin,
IRuntimePlugin,
ModuleCategory,
PluginState
} from './PluginDescriptor';
@@ -22,7 +22,7 @@ import { UIRegistry } from '../Services/UIRegistry';
import { MessageHub } from '../Services/MessageHub';
import { moduleRegistry } from '../Services/Module/ModuleRegistry';
import { SerializerRegistry } from '../Services/SerializerRegistry';
import { ComponentRegistry as EditorComponentRegistry } from '../Services/ComponentRegistry';
import { EditorComponentRegistry } from '../Services/ComponentRegistry';
const logger = createLogger('PluginManager');
@@ -64,7 +64,7 @@ export interface NormalizedManifest {
*/
export interface NormalizedPlugin {
manifest: NormalizedManifest;
runtimeModule?: IPlugin['runtimeModule'];
runtimeModule?: IRuntimePlugin['runtimeModule'];
editorModule?: IEditorModuleLoader;
}
@@ -196,7 +196,7 @@ export class PluginManager implements IService {
* 标准化模块清单,填充默认值
* Normalize module manifest, fill in defaults
*/
private normalizePlugin(input: IPlugin): NormalizedPlugin {
private normalizePlugin(input: IRuntimePlugin): NormalizedPlugin {
const m = input.manifest;
return {
manifest: {
@@ -229,10 +229,10 @@ export class PluginManager implements IService {
* 注册插件
* Register plugin
*
* 接受任何符合 IPlugin 接口的插件,内部会标准化所有字段。
* Accepts any plugin conforming to IPlugin interface, normalizes all fields internally.
* 接受任何符合 IRuntimePlugin 接口的插件,内部会标准化所有字段。
* Accepts any plugin conforming to IRuntimePlugin interface, normalizes all fields internally.
*/
register(plugin: IPlugin): void {
register(plugin: IRuntimePlugin): void {
if (!plugin) {
logger.error('Cannot register plugin: plugin is null or undefined');
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()
export class ComponentRegistry implements IService {
export class EditorComponentRegistry implements IService {
private components: Map<string, ComponentTypeInfo> = new Map();
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
// =============================================================================
export {
ComponentRegistry as EditorComponentRegistry,
EditorComponentRegistry,
} from '@esengine/editor-core';
export type {
@@ -229,7 +229,7 @@ export type {
ModuleCategory,
ModulePlatform,
ModuleExports,
IPlugin,
IRuntimePlugin,
IRuntimeModule,
SystemContext,
ComponentInspectorProviderDef,

View File

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

View File

@@ -21,20 +21,93 @@ import type { ModuleManifest } from './ModuleManifest';
import {
TransformTypeToken,
CanvasElementToken,
EngineBridgeToken,
type IEngineBridge
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
} from './PluginServiceRegistry';
// 导出 engine-core 特有的服务令牌 | Export engine-core specific service tokens
export {
TransformTypeToken,
CanvasElementToken,
EngineBridgeToken,
type IEngineBridge
TextureServiceToken,
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
@@ -155,7 +228,7 @@ export interface IRuntimeModule {
* @example
* ```typescript
* // 纯运行时插件 | Pure runtime plugin
* const MyPlugin: IPlugin = {
* const MyPlugin: IRuntimePlugin = {
* manifest,
* runtimeModule: new MyRuntimeModule()
* };
@@ -184,9 +257,6 @@ export interface IRuntimePlugin<TEditorModule = unknown> {
readonly editorModule?: TEditorModule;
}
/** @deprecated Use IRuntimePlugin instead */
export type IPlugin<TEditorModule = unknown> = IRuntimePlugin<TEditorModule>;
// ============================================================================
// Engine Core 插件 | Engine Core Plugin
// ============================================================================
@@ -215,7 +285,7 @@ const manifest: ModuleManifest = {
}
};
export const EnginePlugin: IPlugin = {
export const EnginePlugin: IRuntimePlugin = {
manifest,
runtimeModule: new EngineRuntimeModule()
};

View File

@@ -34,115 +34,46 @@ export const TransformTypeToken = createServiceToken<new (...args: any[]) => any
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 */
loadTexture(id: number, url: string): Promise<void>;
/**
* 屏幕坐标转世界坐标
* Screen to world coordinate conversion
*/
screenToWorld(screenX: number, screenY: number): { x: number; y: number };
/** 获取纹理加载状态 | Get texture loading state */
getTextureState(id: number): string;
/**
* 世界坐标转屏幕坐标
* World to screen coordinate conversion
*/
worldToScreen(worldX: number, worldY: number): { x: number; y: number };
/** 检查纹理是否就绪 | Check if texture is ready */
isTextureReady(id: number): boolean;
/**
* 设置清除颜色
* Set clear color
*/
setClearColor(r: number, g: number, b: number, a: number): void;
/** 获取正在加载的纹理数量 | Get loading texture count */
getTextureLoadingCount(): number;
// ===== Texture State API (Optional) =====
// ===== 纹理状态 API可选=====
/** 异步加载纹理(等待完成)| Load texture async (wait for completion) */
loadTextureAsync(id: number, url: string): 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;
/** 等待所有加载中的纹理完成 | Wait for all textures to load */
waitForAllTextures(timeout?: number): Promise<void>;
}
/**
* 检查纹理是否就绪
* Check if texture is ready for rendering
*
* @param id 纹理 ID | Texture ID
* @returns 纹理数据已加载则返回 true | true if texture data is loaded
*/
isTextureReady?(id: number): boolean;
/**
* 动态图集服务接口
* Dynamic atlas service interface
*/
export interface IDynamicAtlasService {
/** 创建空白纹理 | Create blank texture */
createBlankTexture(width: number, height: number): number;
/**
* 获取正在加载的纹理数量
* 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?(
/** 更新纹理区域 | Update texture region */
updateTextureRegion(
id: number,
x: 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
TransformTypeToken,
CanvasElementToken,
EngineBridgeToken,
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
// Types
type IEditorModuleBase,
type IEngineBridge
type ITextureService,
type IDynamicAtlasService,
type ICoordinateService,
type IRenderConfigService
} from './EnginePlugin';
// Module Manifest types (unified module/plugin configuration)

View File

@@ -22,7 +22,7 @@ import {
InspectorRegistry,
EntityStoreService,
MessageHub,
ComponentRegistry,
EditorComponentRegistry,
FileActionRegistry
} from '@esengine/editor-core';
import { TransformComponent } from '@esengine/engine-core';
@@ -56,7 +56,7 @@ export class ParticleEditorModule implements IEditorModuleLoader {
}
// 注册组件到编辑器组件注册表 | Register to editor component registry
const componentRegistry = services.resolve(ComponentRegistry);
const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) {
componentRegistry.register({
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 { TransformTypeToken, CanvasElementToken } from '@esengine/engine-core';
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 { ParticleSystemComponent } from './ParticleSystemComponent';
import { ClickFxComponent } from './ClickFxComponent';
@@ -30,7 +30,8 @@ class ParticleRuntimeModule implements IRuntimeModule {
const assetManager = context.services.get(AssetManagerToken);
const transformType = context.services.get(TransformTypeToken);
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 renderSystem = context.services.get(RenderSystemToken);
@@ -60,9 +61,9 @@ class ParticleRuntimeModule implements IRuntimeModule {
this._updateSystem.setEngineIntegration(engineIntegration);
}
// 设置引擎桥接(用于加载默认纹理)| Set engine bridge (for loading default texture)
if (engineBridge) {
this._updateSystem.setEngineBridge(engineBridge);
// 设置纹理服务(用于加载默认纹理)| Set texture service (for loading default texture)
if (textureService) {
this._updateSystem.setTextureService(textureService);
}
// 设置 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
const clickFxSystem = new ClickFxSystem();
// 设置 EngineBridge(用于屏幕坐标转世界坐标)
// Set EngineBridge (for screen to world coordinate conversion)
if (engineBridge) {
clickFxSystem.setEngineBridge(engineBridge);
// 设置坐标服务(用于屏幕坐标转世界坐标)
// Set coordinate service (for screen to world coordinate conversion)
if (coordinateService) {
clickFxSystem.setCoordinateService(coordinateService);
}
// 从服务注册表获取 Canvas 元素(用于计算相对坐标)

View File

@@ -11,23 +11,11 @@ import { Input, MouseButton, TransformComponent, SortingLayers } from '@esengine
import { ClickFxComponent, ClickFxTriggerMode } from '../ClickFxComponent';
import { ParticleSystemComponent, RenderSpace } from '../ParticleSystemComponent';
import { CoordinateServiceToken, type ICoordinateService } from '@esengine/ecs-engine-bindgen';
// ============================================================================
// 本地服务令牌定义 | 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 尺寸)
@@ -37,10 +25,6 @@ interface IEngineRenderSystem {
getUICanvasSize(): { width: number; height: number };
}
// EngineBridge 令牌(与 engine-core 中的一致)
// EngineBridge token (consistent with engine-core)
const EngineBridgeToken = createServiceToken<IEngineBridge>('engineBridge');
// RenderSystem 令牌(与 ecs-engine-bindgen 中的一致)
// RenderSystem token (consistent with ecs-engine-bindgen)
const RenderSystemToken = createServiceToken<IEngineRenderSystem>('renderSystem');
@@ -62,7 +46,7 @@ const RenderSystemToken = createServiceToken<IEngineRenderSystem>('renderSystem'
*/
@ECSSystem('ClickFx', { updateOrder: 100 })
export class ClickFxSystem extends EntitySystem {
private _engineBridge: IEngineBridge | null = null;
private _coordinateService: ICoordinateService | null = null;
private _renderSystem: IEngineRenderSystem | null = null;
private _entitiesToDestroy: Entity[] = [];
private _canvas: HTMLCanvasElement | null = null;
@@ -72,20 +56,20 @@ export class ClickFxSystem extends EntitySystem {
}
/**
* 设置服务注册表(用于获取 EngineBridge 和 RenderSystem
* Set service registry (for getting EngineBridge and RenderSystem)
* 设置服务注册表(用于获取 CoordinateService 和 RenderSystem
* Set service registry (for getting CoordinateService and RenderSystem)
*/
setServiceRegistry(services: PluginServiceRegistry): void {
this._engineBridge = services.get(EngineBridgeToken) ?? null;
this._coordinateService = services.get(CoordinateServiceToken) ?? null;
this._renderSystem = services.get(RenderSystemToken) ?? null;
}
/**
* 设置 EngineBridge(直接注入)
* Set EngineBridge (direct injection)
* 设置坐标服务(直接注入)
* Set coordinate service (direct injection)
*/
setEngineBridge(bridge: IEngineBridge): void {
this._engineBridge = bridge;
setCoordinateService(coordinateService: ICoordinateService): void {
this._coordinateService = coordinateService;
}
/**

View File

@@ -1,5 +1,5 @@
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 { ParticleSystemComponent } from '../ParticleSystemComponent';
import { ParticleRenderDataProvider } from '../rendering/ParticleRenderDataProvider';
@@ -78,7 +78,7 @@ export class ParticleUpdateSystem extends EntitySystem {
private _transformType: ComponentType<Component & ITransformComponent> | null = null;
private _renderDataProvider: ParticleRenderDataProvider;
private _engineIntegration: IEngineIntegration | null = null;
private _engineBridge: IEngineBridge | null = null;
private _textureService: ITextureService | null = null;
private _physics2DQuery: IPhysics2DQuery | null = null;
private _assetManager: IAssetManager | null = null;
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 {
this._engineBridge = bridge;
setTextureService(textureService: ITextureService): void {
this._textureService = textureService;
}
/**
@@ -487,8 +487,8 @@ export class ParticleUpdateSystem extends EntitySystem {
}
// 没有引擎桥接,无法加载 | No engine bridge, cannot load
if (!this._engineBridge) {
console.warn('[ParticleUpdateSystem] EngineBridge not set, cannot load default texture');
if (!this._textureService) {
console.warn('[ParticleUpdateSystem] TextureService not set, cannot load default texture');
return false;
}
@@ -496,15 +496,9 @@ export class ParticleUpdateSystem extends EntitySystem {
try {
const dataUrl = generateDefaultParticleTextureDataURL();
if (dataUrl) {
// 优先使用 loadTextureAsync等待纹理就绪
// Prefer loadTextureAsync (waits for texture ready)
if (this._engineBridge.loadTextureAsync) {
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);
}
// 使用 loadTextureAsync等待纹理就绪
// Use loadTextureAsync (waits for texture ready)
await this._textureService.loadTextureAsync(DEFAULT_PARTICLE_TEXTURE_ID, dataUrl);
this._defaultTextureLoaded = true;
}
} catch (error) {

View File

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

View File

@@ -18,7 +18,7 @@ import {
BrowserFileSystemService,
RuntimeSceneManager,
RuntimeSceneManagerToken,
type IPlugin,
type IRuntimePlugin,
type IRuntimeSceneManager
} from '@esengine/runtime-core';
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.
*/
registerPlugin(plugin: IPlugin): void {
registerPlugin(plugin: IRuntimePlugin): void {
if (plugin) {
runtimePluginManager.register(plugin);
runtimePluginManager.enable(plugin.manifest.id);
@@ -87,7 +87,7 @@ export class BrowserRuntime {
* Register multiple plugins
* 注册多个插件
*/
registerPlugins(plugins: IPlugin[]): void {
registerPlugins(plugins: IRuntimePlugin[]): void {
for (const plugin of plugins) {
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 {
EngineBridge,
EngineRenderSystem,
EngineBridgeToken,
RenderSystemToken,
EngineIntegrationToken,
TextureServiceToken,
DynamicAtlasServiceToken,
CoordinateServiceToken,
RenderConfigServiceToken,
type IUIRenderDataProvider
} from '@esengine/ecs-engine-bindgen';
import {
@@ -360,7 +363,11 @@ export class GameRuntime {
const services = new PluginServiceRegistry();
// 注册核心服务 | 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(EngineIntegrationToken, this._engineIntegration);
services.register(AssetManagerToken, this._assetManager);

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ import type {
import {
EntityStoreService,
MessageHub,
ComponentRegistry,
EditorComponentRegistry,
ComponentInspectorRegistry
} from '@esengine/editor-core';
@@ -47,7 +47,7 @@ export { registerUITransformGizmo, unregisterUITransformGizmo } from './gizmos';
export class UIEditorModule implements IEditorModuleLoader {
async install(services: ServiceContainer): Promise<void> {
// 注册 UI 组件到编辑器组件注册表 | Register UI components to editor component registry
const componentRegistry = services.resolve(ComponentRegistry);
const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) {
const uiComponents = [
{ 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 { 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 { initializeDynamicAtlasService, registerTexturePathMapping, AtlasExpansionStrategy, type IAtlasEngineBridge } from './atlas';
@@ -77,7 +82,8 @@ class UIRuntimeModule implements IRuntimeModule {
createSystems(scene: IScene, context: SystemContext): void {
// 从服务注册表获取依赖 | 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)
// 滑块填充控制系统(在布局之前运行以修改锚点)
@@ -133,34 +139,30 @@ class UIRuntimeModule implements IRuntimeModule {
const textRenderSystem = new UITextRenderSystem();
scene.addSystem(textRenderSystem);
if (engineBridge) {
if (textureService) {
// 设置文本渲染系统的纹理回调
// Set texture callback for text render system
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
if (engineBridge.isTextureReady) {
textRenderSystem.setTextureReadyChecker((id: number) => {
return engineBridge.isTextureReady!(id);
});
}
textRenderSystem.setTextureReadyChecker((id: number) => {
return textureService.isTextureReady(id);
});
// 设置输入框渲染系统的纹理回调
// Set texture callback for input field render system
inputFieldRenderSystem.setTextureCallback((id: number, dataUrl: string) => {
engineBridge.loadTexture(id, dataUrl);
textureService.loadTexture(id, dataUrl);
});
// 设置输入框渲染系统的纹理就绪检查回调
// Set texture ready checker callback for input field render system
if (engineBridge.isTextureReady) {
inputFieldRenderSystem.setTextureReadyChecker((id: number) => {
return engineBridge.isTextureReady!(id);
});
}
inputFieldRenderSystem.setTextureReadyChecker((id: number) => {
return textureService.isTextureReady(id);
});
}
const uiRenderProvider = new UIRenderDataProvider();
@@ -175,17 +177,15 @@ class UIRuntimeModule implements IRuntimeModule {
context.services.register(UITextRenderSystemToken, textRenderSystem);
// 初始化动态图集服务 | Initialize dynamic atlas service
// 需要 engineBridge 支持 createBlankTexture 和 updateTextureRegion
// Requires engineBridge to support createBlankTexture and updateTextureRegion
console.log('[UIRuntimeModule] engineBridge available:', !!engineBridge);
console.log('[UIRuntimeModule] createBlankTexture:', !!engineBridge?.createBlankTexture);
console.log('[UIRuntimeModule] updateTextureRegion:', !!engineBridge?.updateTextureRegion);
if (engineBridge?.createBlankTexture && engineBridge?.updateTextureRegion) {
// 创建适配器将 EngineBridge 适配为 IAtlasEngineBridge
// Create adapter to adapt EngineBridge to IAtlasEngineBridge
// 需要 dynamicAtlasService 支持 createBlankTexture 和 updateTextureRegion
// Requires dynamicAtlasService to support createBlankTexture and updateTextureRegion
console.log('[UIRuntimeModule] dynamicAtlasService available:', !!dynamicAtlasService);
if (dynamicAtlasService) {
// 创建适配器将 IDynamicAtlasService 适配为 IAtlasEngineBridge
// Create adapter to adapt IDynamicAtlasService to IAtlasEngineBridge
const atlasBridge: IAtlasEngineBridge = {
createBlankTexture: (width: number, height: number) => {
return engineBridge.createBlankTexture!(width, height);
return dynamicAtlasService.createBlankTexture(width, height);
},
updateTextureRegion: (
id: number,
@@ -195,7 +195,7 @@ class UIRuntimeModule implements IRuntimeModule {
height: number,
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);
});
} 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,
EntityStoreService,
MessageHub,
ComponentRegistry
EditorComponentRegistry
} from '@esengine/editor-core';
import { TransformComponent } from '@esengine/engine-core';
import {
@@ -47,7 +47,7 @@ export class WorldStreamingEditorModule implements IEditorModuleLoader {
inspectorRegistry.register(new StreamingAnchorInspectorProvider());
}
const componentRegistry = services.resolve(ComponentRegistry);
const componentRegistry = services.resolve(EditorComponentRegistry);
if (componentRegistry) {
componentRegistry.register({
name: 'ChunkLoader',