Files
esengine/packages/core/src/ECS/Scene.ts
yhh 8f9a7d8581 feat(core): 添加持久化实体支持跨场景迁移
实现实体生命周期策略,允许标记实体为持久化,在场景切换时自动迁移到新场景。

主要变更:
- 新增 EEntityLifecyclePolicy 枚举(SceneLocal/Persistent)
- Entity 添加 setPersistent()、setSceneLocal()、isPersistent API
- Scene 添加 findPersistentEntities()、extractPersistentEntities()、receiveMigratedEntities()
- SceneManager.setScene() 自动处理持久化实体迁移
- 添加完整的中英文文档和 21 个测试用例
2025-12-05 22:46:53 +08:00

1440 lines
46 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Entity } from './Entity';
import { EntityList } from './Utils/EntityList';
import { IdentifierPool } from './Utils/IdentifierPool';
import { EntitySystem } from './Systems/EntitySystem';
import { ComponentStorageManager, ComponentRegistry, ComponentType } from './Core/ComponentStorage';
import { QuerySystem } from './Core/QuerySystem';
import { TypeSafeEventSystem } from './Core/EventSystem';
import { ReferenceTracker } from './Core/ReferenceTracker';
import { IScene, ISceneConfig } from './IScene';
import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from './Decorators';
import { TypedQueryBuilder } from './Core/Query/TypedQuery';
import {
SceneSerializer,
SceneSerializationOptions,
SceneDeserializationOptions
} from './Serialization/SceneSerializer';
import {
IncrementalSerializer,
IncrementalSnapshot,
IncrementalSerializationOptions
} from './Serialization/IncrementalSerializer';
import { ComponentPoolManager } from './Core/ComponentPool';
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
import { ProfilerSDK } from '../Utils/Profiler/ProfilerSDK';
import { ProfileCategory } from '../Utils/Profiler/ProfilerTypes';
import { AutoProfiler } from '../Utils/Profiler/AutoProfiler';
import { ServiceContainer, type ServiceType, type IService } from '../Core/ServiceContainer';
import { createInstance, isInjectable, injectProperties } from '../Core/DI';
import { createLogger } from '../Utils/Logger';
/**
* 游戏场景默认实现类
*
* 实现IScene接口提供场景的基础功能。
* 推荐使用组合而非继承的方式来构建自定义场景。
*/
export class Scene implements IScene {
/**
* 场景名称
*
* 用于标识和调试的友好名称。
*/
public name: string = '';
/**
* 场景自定义数据
*
* 用于存储场景级别的配置和状态数据。
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public readonly sceneData: Map<string, any> = new Map();
/**
* 场景中的实体集合
*
* 管理场景内所有实体的生命周期。
*/
public readonly entities: EntityList;
/**
* 实体ID池
*
* 用于分配和回收实体的唯一标识符。
*/
public readonly identifierPool: IdentifierPool;
/**
* 组件存储管理器
*
* 高性能的组件存储和查询系统。
*/
public readonly componentStorageManager: ComponentStorageManager;
/**
* 查询系统
*
* 基于位掩码的高性能实体查询系统。
*/
public readonly querySystem: QuerySystem;
/**
* 事件系统
*
* 类型安全的事件系统。
*/
public readonly eventSystem: TypeSafeEventSystem;
/**
* 引用追踪器
*
* 追踪Component中对Entity的引用当Entity销毁时自动清理引用。
*/
public readonly referenceTracker: ReferenceTracker;
/**
* 服务容器
*
* 场景级别的依赖注入容器用于管理EntitySystem和其他服务的生命周期。
* 每个Scene拥有独立的服务容器实现场景间的隔离。
*/
private readonly _services: ServiceContainer;
/**
* 日志记录器
*/
private readonly logger: ReturnType<typeof createLogger>;
/**
* 性能监控器缓存
*
* 用于监控场景和系统的性能。从 ServiceContainer 获取。
*/
private _performanceMonitor: PerformanceMonitor | null = null;
/**
* 场景是否已开始运行
*/
private _didSceneBegin: boolean = false;
/**
* 编辑器模式标志
*
* 当为 true 时,组件的生命周期回调(如 onAddedToEntity会被延迟
* 直到调用 begin() 开始运行场景时才会触发。
*
* Editor mode flag.
* When true, component lifecycle callbacks (like onAddedToEntity) are deferred
* until begin() is called to start running the scene.
*/
public isEditorMode: boolean = false;
/**
* 延迟的组件生命周期回调队列
*
* 在编辑器模式下,组件的 onAddedToEntity 回调会被加入此队列,
* 等到 begin() 调用时统一执行。
*
* Deferred component lifecycle callback queue.
* In editor mode, component's onAddedToEntity callbacks are queued here,
* and will be executed when begin() is called.
*/
private _deferredComponentCallbacks: Array<() => void> = [];
/**
* 系统列表缓存
*/
private _cachedSystems: EntitySystem[] | null = null;
/**
* 系统顺序脏标记
*
* 当系统增删或 updateOrder 改变时标记为 true下次访问 systems 时重新构建缓存
*/
private _systemsOrderDirty: boolean = true;
/**
* 系统错误计数器
*
* 跟踪每个系统的错误次数,用于自动禁用频繁出错的系统
*/
private _systemErrorCount: Map<EntitySystem, number> = new Map();
/**
* 最大允许错误次数
*
* 系统错误次数超过此阈值后将被自动禁用
*/
private _maxErrorCount: number = 10;
/**
* 系统添加计数器
*
* 用于为每个添加的系统分配唯一的添加顺序,保证排序稳定性
* Counter for assigning unique add order to each system for stable sorting
*/
private _systemAddCounter: number = 0;
/**
* 组件ID到系统的索引映射
*
* 用于快速查找关心特定组件的系统,避免遍历所有系统。
* 使用组件ID数字而非ComponentType作为key避免类引用问题。
*
* Component ID to systems index map.
* Used for fast lookup of systems that care about specific components.
* Uses component ID (number) instead of ComponentType as key to avoid class reference issues.
*/
private _componentIdToSystems: Map<number, Set<EntitySystem>> = new Map();
/**
* 需要接收所有组件变化通知的系统集合
*
* 包括使用 none 条件、tag/name 查询、或空匹配器的系统。
* 这些系统无法通过组件ID索引优化需要在每次组件变化时都检查。
*
* Systems that need to receive all component change notifications.
* Includes systems using none conditions, tag/name queries, or empty matchers.
* These systems cannot be optimized via component ID indexing.
*/
private _globalNotifySystems: Set<EntitySystem> = new Set();
/**
* 获取场景中所有已注册的EntitySystem
*
* 按updateOrder排序。使用缓存机制仅在系统变化时重新排序。
*
* @returns 系统列表
*/
public get systems(): EntitySystem[] {
if (!this._systemsOrderDirty && this._cachedSystems) {
return this._cachedSystems;
}
this._cachedSystems = this._rebuildSystemsCache();
this._systemsOrderDirty = false;
return this._cachedSystems;
}
/**
* 重新构建系统缓存
*
* 从服务容器中提取所有EntitySystem并排序
*/
private _rebuildSystemsCache(): EntitySystem[] {
const allServices = this._services.getAll();
const systems = this._filterEntitySystems(allServices);
return this._sortSystemsByUpdateOrder(systems);
}
/**
* 从服务列表中过滤出EntitySystem实例
*/
private _filterEntitySystems(services: IService[]): EntitySystem[] {
return services.filter((service): service is EntitySystem => service instanceof EntitySystem);
}
/**
* 按 updateOrder 排序系统,相同时按 addOrder 保证稳定性
* Sort systems by updateOrder, use addOrder as secondary key for stability
*/
private _sortSystemsByUpdateOrder(systems: EntitySystem[]): EntitySystem[] {
return systems.sort((a, b) => {
const orderDiff = a.updateOrder - b.updateOrder;
if (orderDiff !== 0) return orderDiff;
return a.addOrder - b.addOrder;
});
}
/**
* 通过类型获取System实例
*
* @param systemType System类型
* @returns System实例如果未找到则返回null
*
* @example
* ```typescript
* const physics = scene.getSystem(PhysicsSystem);
* if (physics) {
* physics.doSomething();
* }
* ```
*/
public getSystem<T extends EntitySystem>(systemType: ServiceType<T>): T | null {
return this._services.tryResolve(systemType) as T | null;
}
/**
* 标记系统顺序为脏
*
* 当系统列表或顺序发生变化时调用,使缓存失效
*/
public markSystemsOrderDirty(): void {
this._systemsOrderDirty = true;
}
/**
* 获取场景的服务容器
*
* 用于注册和解析场景级别的服务如EntitySystem
*
* @example
* ```typescript
* // 注册服务
* scene.services.registerSingleton(PhysicsSystem);
*
* // 解析服务
* const physics = scene.services.resolve(PhysicsSystem);
* ```
*/
public get services(): ServiceContainer {
return this._services;
}
/**
* 创建场景实例
*/
constructor(config?: ISceneConfig) {
this.entities = new EntityList(this);
this.identifierPool = new IdentifierPool();
this.componentStorageManager = new ComponentStorageManager();
this.querySystem = new QuerySystem();
this.eventSystem = new TypeSafeEventSystem();
this.referenceTracker = new ReferenceTracker();
this._services = new ServiceContainer();
this.logger = createLogger('Scene');
if (config?.name) {
this.name = config.name;
}
}
/**
* 获取性能监控器
*
* 从 ServiceContainer 获取,如果未注册则创建默认实例(向后兼容)
*/
public get performanceMonitor(): PerformanceMonitor {
if (!this._performanceMonitor) {
this._performanceMonitor = this._services.tryResolve(PerformanceMonitor) ?? new PerformanceMonitor();
}
return this._performanceMonitor;
}
/**
* 初始化场景
*
* 在场景创建时调用,子类可以重写此方法来设置初始实体和组件。
*/
public initialize(): void {}
/**
* 场景开始运行时的回调
*
* 在场景开始运行时调用,可以在此方法中执行场景启动逻辑。
*/
public onStart(): void {}
/**
* 场景卸载时的回调
*
* 在场景被销毁时调用,可以在此方法中执行清理工作。
*/
public unload(): void {}
/**
* 添加延迟的组件生命周期回调
*
* 在编辑器模式下,组件的 onAddedToEntity 回调会通过此方法加入队列。
*
* Queue a deferred component lifecycle callback.
* In editor mode, component's onAddedToEntity callbacks are queued via this method.
*
* @param callback 要延迟执行的回调 | The callback to defer
*/
public queueDeferredComponentCallback(callback: () => void): void {
this._deferredComponentCallbacks.push(callback);
}
/**
* 开始场景,启动实体处理器等
*
* 这个方法会启动场景。它将启动实体处理器等并调用onStart方法。
* 在编辑器模式下,此方法还会执行所有延迟的组件生命周期回调。
*
* This method starts the scene. It will start entity processors and call onStart.
* In editor mode, this method also executes all deferred component lifecycle callbacks.
*/
public begin() {
// 标记场景已开始运行
this._didSceneBegin = true;
// 执行所有延迟的组件生命周期回调 | Execute all deferred component lifecycle callbacks
if (this._deferredComponentCallbacks.length > 0) {
for (const callback of this._deferredComponentCallbacks) {
try {
callback();
} catch (error) {
this.logger.error('Error executing deferred component callback:', error);
}
}
// 清空队列 | Clear the queue
this._deferredComponentCallbacks = [];
}
// 调用onStart方法
this.onStart();
}
/**
* 结束场景,清除实体、实体处理器等
*
* 这个方法会结束场景。它将移除所有实体结束实体处理器等并调用unload方法。
*
* 执行顺序:
* 1. 调用 unload() - 用户可以在此访问实体和系统进行清理
* 2. 清理所有实体
* 3. 清空服务容器,触发所有系统的 onDestroy()
*
* 注意:
* - onRemoved 回调不会在 Scene.end() 时触发,因为这是批量销毁场景
* - 用户清理:在 Scene.unload() 中处理(可访问实体和系统)
* - 系统清理:在 System.onDestroy() 中处理(实体已被清理)
*/
public end() {
// 标记场景已结束运行
this._didSceneBegin = false;
// 先调用用户的卸载方法,此时用户可以访问实体和系统进行清理
this.unload();
// 移除所有实体
this.entities.removeAllEntities();
// 清理查询系统中的实体引用和缓存
this.querySystem.setEntities([]);
// 清空组件存储
this.componentStorageManager.clear();
// 清空服务容器会调用所有服务的dispose方法包括所有EntitySystem
// 系统的 onDestroy 回调会在这里被触发
this._services.clear();
// 清空系统缓存
this._cachedSystems = null;
this._systemsOrderDirty = true;
// 清空组件索引 | Clear component indices
this._componentIdToSystems.clear();
this._globalNotifySystems.clear();
}
/**
* 更新场景
*/
public update() {
// 开始性能采样帧
ProfilerSDK.beginFrame();
const frameHandle = ProfilerSDK.beginSample('Scene.update', ProfileCategory.ECS);
try {
ComponentPoolManager.getInstance().update();
this.entities.updateLists();
const systems = this.systems;
// Update 阶段
const updateHandle = ProfilerSDK.beginSample('Systems.update', ProfileCategory.ECS);
try {
for (const system of systems) {
if (system.enabled) {
const systemHandle = ProfilerSDK.beginSample(system.systemName, ProfileCategory.ECS);
try {
system.update();
} catch (error) {
this._handleSystemError(system, 'update', error);
} finally {
ProfilerSDK.endSample(systemHandle);
}
}
}
} finally {
ProfilerSDK.endSample(updateHandle);
}
// LateUpdate 阶段
const lateUpdateHandle = ProfilerSDK.beginSample('Systems.lateUpdate', ProfileCategory.ECS);
try {
for (const system of systems) {
if (system.enabled) {
const systemHandle = ProfilerSDK.beginSample(`${system.systemName}.late`, ProfileCategory.ECS);
try {
system.lateUpdate();
} catch (error) {
this._handleSystemError(system, 'lateUpdate', error);
} finally {
ProfilerSDK.endSample(systemHandle);
}
}
}
} finally {
ProfilerSDK.endSample(lateUpdateHandle);
}
// 执行所有系统的延迟命令
// Flush all systems' deferred commands
this.flushCommandBuffers(systems);
} finally {
ProfilerSDK.endSample(frameHandle);
// 结束性能采样帧
ProfilerSDK.endFrame();
}
}
/**
* 执行所有系统的延迟命令
* Flush all systems' deferred commands
*
* 在帧末统一执行所有通过 CommandBuffer 提交的延迟操作。
* Execute all deferred operations submitted via CommandBuffer at end of frame.
*/
private flushCommandBuffers(systems: readonly EntitySystem[]): void {
const flushHandle = ProfilerSDK.beginSample('Scene.flushCommandBuffers', ProfileCategory.ECS);
try {
for (const system of systems) {
try {
system.flushCommands();
} catch (error) {
this.logger.error(`Error flushing commands for system ${system.systemName}:`, error);
}
}
} finally {
ProfilerSDK.endSample(flushHandle);
}
}
/**
* 处理系统执行错误
*
* 记录错误信息并跟踪错误次数。当系统错误次数超过阈值时自动禁用该系统。
*
* @param system 出错的系统
* @param phase 错误发生的阶段update 或 lateUpdate
* @param error 错误对象
*/
private _handleSystemError(system: EntitySystem, phase: 'update' | 'lateUpdate', error: unknown): void {
const errorCount = (this._systemErrorCount.get(system) || 0) + 1;
this._systemErrorCount.set(system, errorCount);
this.logger.error(
`Error in system ${system.constructor.name}.${phase}() [${errorCount}/${this._maxErrorCount}]:`,
error
);
if (errorCount >= this._maxErrorCount) {
system.enabled = false;
this.logger.error(
`System ${system.constructor.name} has been disabled due to excessive errors (${errorCount} errors)`
);
}
}
/**
* 将实体添加到此场景,并返回它
* @param name 实体名称
*/
public createEntity(name: string) {
const entity = new Entity(name, this.identifierPool.checkOut());
this.eventSystem.emitSync('entity:created', { entityName: name, entity, scene: this });
return this.addEntity(entity);
}
/**
* 清除所有EntitySystem的实体缓存
* 当实体或组件发生变化时调用
*/
public clearSystemEntityCaches(): void {
for (const system of this.systems) {
system.clearEntityCache();
}
}
/**
* 通知相关系统实体的组件发生了变化
*
* 这是事件驱动设计的核心:当组件被添加或移除时,立即通知相关系统检查该实体是否匹配,
* 并触发 onAdded/onRemoved 回调。通过组件ID索引优化只通知关心该组件的系统。
*
* This is the core of event-driven design: when a component is added or removed,
* immediately notify relevant systems to check if the entity matches and trigger
* onAdded/onRemoved callbacks. Optimized via component ID indexing to only notify
* systems that care about the changed component.
*
* @param entity 组件发生变化的实体 | The entity whose components changed
* @param changedComponentType 变化的组件类型(可选) | The changed component type (optional)
*/
public notifyEntityComponentChanged(entity: Entity, changedComponentType?: ComponentType): void {
// 已通知的系统集合,避免重复通知 | Set of notified systems to avoid duplicates
const notifiedSystems = new Set<EntitySystem>();
// 如果提供了组件类型,使用索引优化 | If component type provided, use index optimization
if (changedComponentType && ComponentRegistry.isRegistered(changedComponentType)) {
const componentId = ComponentRegistry.getBitIndex(changedComponentType);
const interestedSystems = this._componentIdToSystems.get(componentId);
if (interestedSystems) {
for (const system of interestedSystems) {
system.handleEntityComponentChanged(entity);
notifiedSystems.add(system);
}
}
}
// 通知全局监听系统none条件、tag/name查询等 | Notify global listener systems
for (const system of this._globalNotifySystems) {
if (!notifiedSystems.has(system)) {
system.handleEntityComponentChanged(entity);
notifiedSystems.add(system);
}
}
// 如果没有提供组件类型,回退到遍历所有系统 | Fallback to all systems if no component type
if (!changedComponentType) {
for (const system of this.systems) {
if (!notifiedSystems.has(system)) {
system.handleEntityComponentChanged(entity);
}
}
}
}
/**
* 将系统添加到组件索引
*
* 根据系统的 Matcher 条件将系统注册到相应的组件ID索引中。
*
* Index a system by its interested component types.
* Registers the system to component ID indices based on its Matcher conditions.
*
* @param system 要索引的系统 | The system to index
*/
private indexSystemByComponents(system: EntitySystem): void {
const matcher = system.matcher;
if (!matcher) {
return;
}
// nothing 匹配器不需要索引 | Nothing matcher doesn't need indexing
if (matcher.isNothing()) {
return;
}
const condition = matcher.getCondition();
// 有 none/tag/name 条件的系统加入全局通知 | Systems with none/tag/name go to global
if (condition.none.length > 0 || condition.tag !== undefined || condition.name !== undefined) {
this._globalNotifySystems.add(system);
}
// 空匹配器(匹配所有实体)加入全局通知 | Empty matcher (matches all) goes to global
if (matcher.isEmpty()) {
this._globalNotifySystems.add(system);
return;
}
// 索引 all 条件中的组件 | Index components in all condition
for (const componentType of condition.all) {
this.addSystemToComponentIndex(componentType, system);
}
// 索引 any 条件中的组件 | Index components in any condition
for (const componentType of condition.any) {
this.addSystemToComponentIndex(componentType, system);
}
// 索引单组件查询 | Index single component query
if (condition.component) {
this.addSystemToComponentIndex(condition.component, system);
}
}
/**
* 将系统添加到指定组件的索引
*
* Add system to the index for a specific component type.
*
* @param componentType 组件类型 | Component type
* @param system 系统 | System
*/
private addSystemToComponentIndex(componentType: ComponentType, system: EntitySystem): void {
if (!ComponentRegistry.isRegistered(componentType)) {
ComponentRegistry.register(componentType);
}
const componentId = ComponentRegistry.getBitIndex(componentType);
let systems = this._componentIdToSystems.get(componentId);
if (!systems) {
systems = new Set();
this._componentIdToSystems.set(componentId, systems);
}
systems.add(system);
}
/**
* 从组件索引中移除系统
*
* Remove a system from all component indices.
*
* @param system 要移除的系统 | The system to remove
*/
private removeSystemFromIndex(system: EntitySystem): void {
// 从全局通知列表移除 | Remove from global notify list
this._globalNotifySystems.delete(system);
// 从所有组件索引中移除 | Remove from all component indices
for (const systems of this._componentIdToSystems.values()) {
systems.delete(system);
}
}
/**
* 在场景的实体列表中添加一个实体
* @param entity 要添加的实体
* @param deferCacheClear 是否延迟缓存清理(用于批量操作)
*/
public addEntity(entity: Entity, deferCacheClear: boolean = false) {
this.entities.add(entity);
entity.scene = this;
// 将实体添加到查询系统(可延迟缓存清理)
this.querySystem.addEntity(entity, deferCacheClear);
// 清除系统缓存以确保系统能及时发现新实体
if (!deferCacheClear) {
this.clearSystemEntityCaches();
}
// 触发实体添加事件
this.eventSystem.emitSync('entity:added', { entity, scene: this });
return entity;
}
/**
* 批量创建实体(高性能版本)
* @param count 要创建的实体数量
* @param namePrefix 实体名称前缀
* @returns 创建的实体列表
*/
public createEntities(count: number, namePrefix: string = 'Entity'): Entity[] {
const entities: Entity[] = [];
// 批量创建实体对象,不立即添加到系统
for (let i = 0; i < count; i++) {
const entity = new Entity(`${namePrefix}_${i}`, this.identifierPool.checkOut());
entity.scene = this;
entities.push(entity);
}
// 批量添加到实体列表
for (const entity of entities) {
this.entities.add(entity);
}
// 批量添加到查询系统(无重复检查,性能最优)
this.querySystem.addEntitiesUnchecked(entities);
// 批量触发事件(可选,减少事件开销)
this.eventSystem.emitSync('entities:batch_added', { entities, scene: this, count });
return entities;
}
/**
* 批量销毁实体
*/
public destroyEntities(entities: Entity[]): void {
if (entities.length === 0) return;
for (const entity of entities) {
entity.setDestroyedState(true);
}
for (const entity of entities) {
entity.removeAllComponents();
}
for (const entity of entities) {
this.entities.remove(entity);
this.querySystem.removeEntity(entity);
}
this.querySystem.clearCache();
this.clearSystemEntityCaches();
}
/**
* 从场景中删除所有实体
*/
public destroyAllEntities() {
this.entities.removeAllEntities();
this.querySystem.setEntities([]);
}
/**
* 搜索并返回第一个具有名称的实体
* @param name 实体名称
*/
public findEntity(name: string): Entity | null {
return this.entities.findEntity(name);
}
/**
* 根据ID查找实体
* @param id 实体ID
*/
public findEntityById(id: number): Entity | null {
return this.entities.findEntityById(id);
}
/**
* 根据标签查找实体
* @param tag 实体标签
*/
public findEntitiesByTag(tag: number): Entity[] {
const result: Entity[] = [];
for (const entity of this.entities.buffer) {
if (entity.tag === tag) {
result.push(entity);
}
}
return result;
}
/**
* 查找所有持久化实体
*
* Find all persistent entities in this scene.
*
* @returns 持久化实体数组 | Array of persistent entities
*/
public findPersistentEntities(): Entity[] {
return this.entities.buffer.filter(entity => entity.isPersistent);
}
/**
* 提取持久化实体(从场景中分离但不销毁)
*
* 用于场景切换时收集需要迁移的实体。
*
* Extract persistent entities (detach from scene without destroying).
* Used during scene transitions to collect entities for migration.
*
* @returns 被提取的持久化实体数组 | Array of extracted persistent entities
*
* @internal
*/
public extractPersistentEntities(): Entity[] {
const persistentEntities = this.findPersistentEntities();
for (const entity of persistentEntities) {
// 从实体列表移除
this.entities.remove(entity);
// 从查询系统移除
this.querySystem.removeEntity(entity);
// 清除场景引用(但保留组件数据)
entity.scene = null;
}
return persistentEntities;
}
/**
* 接收迁移的实体
*
* 将从其他场景迁移来的实体添加到当前场景。
*
* Receive migrated entities from another scene.
*
* @param entities 要接收的实体数组 | Entities to receive
*
* @internal
*/
public receiveMigratedEntities(entities: Entity[]): void {
for (const entity of entities) {
// 设置新场景引用
entity.scene = this;
// 添加到实体列表
this.entities.add(entity);
// 添加到查询系统
this.querySystem.addEntity(entity);
// 重新注册组件到新场景的存储
for (const component of entity.components) {
this.componentStorageManager.addComponent(entity.id, component);
this.referenceTracker?.registerEntityScene(entity.id, this);
}
}
// 清除系统缓存
if (entities.length > 0) {
this.clearSystemEntityCaches();
}
}
/**
* 根据名称查找实体(别名方法)
*
* @param name 实体名称
* @deprecated 请使用 findEntity() 代替此方法
*/
public getEntityByName(name: string): Entity | null {
return this.findEntity(name);
}
/**
* 根据标签查找实体(别名方法)
*
* @param tag 实体标签
* @deprecated 请使用 findEntitiesByTag() 代替此方法
*/
public getEntitiesByTag(tag: number): Entity[] {
return this.findEntitiesByTag(tag);
}
/**
* 查询拥有所有指定组件的实体
*
* @param componentTypes - 组件类型数组
* @returns 查询结果
*
* @example
* ```typescript
* const result = scene.queryAll(Position, Velocity);
* for (const entity of result.entities) {
* const pos = entity.getComponent(Position);
* const vel = entity.getComponent(Velocity);
* }
* ```
*/
public queryAll(...componentTypes: ComponentType[]): { entities: readonly Entity[] } {
return this.querySystem.queryAll(...componentTypes);
}
/**
* 查询拥有任意一个指定组件的实体
*
* @param componentTypes - 组件类型数组
* @returns 查询结果
*/
public queryAny(...componentTypes: ComponentType[]): { entities: readonly Entity[] } {
return this.querySystem.queryAny(...componentTypes);
}
/**
* 查询不包含指定组件的实体
*
* @param componentTypes - 组件类型数组
* @returns 查询结果
*/
public queryNone(...componentTypes: ComponentType[]): { entities: readonly Entity[] } {
return this.querySystem.queryNone(...componentTypes);
}
/**
* 创建类型安全的查询构建器
*
* @returns 查询构建器,支持链式调用
*
* @example
* ```typescript
* // 使用查询构建器
* const matcher = scene.query()
* .withAll(Position, Velocity)
* .withNone(Disabled)
* .buildMatcher();
*
* // 在System中使用
* class MovementSystem extends EntitySystem {
* constructor() {
* super(matcher);
* }
* }
* ```
*/
public query(): TypedQueryBuilder {
return new TypedQueryBuilder();
}
/**
* 在场景中添加一个EntitySystem处理器
*
* 支持两种使用方式:
* 1. 传入类型推荐自动使用DI创建实例支持@Injectable和@InjectProperty装饰器
* 2. 传入实例:直接使用提供的实例
*
* @param systemTypeOrInstance 系统类型或系统实例
* @returns 添加的处理器实例
*
* @example
* ```typescript
* // 方式1传入类型自动DI推荐
* @Injectable()
* class PhysicsSystem extends EntitySystem {
* @InjectProperty(CollisionSystem)
* private collision!: CollisionSystem;
*
* constructor() {
* super(Matcher.empty().all(Transform));
* }
* }
* scene.addEntityProcessor(PhysicsSystem);
*
* // 方式2传入实例
* const system = new MySystem();
* scene.addEntityProcessor(system);
* ```
*/
public addEntityProcessor<T extends EntitySystem>(systemTypeOrInstance: ServiceType<T> | T): T {
let system: T;
let constructor: ServiceType<T>;
if (typeof systemTypeOrInstance === 'function') {
constructor = systemTypeOrInstance;
if (this._services.isRegistered(constructor)) {
const existingSystem = this._services.resolve(constructor) as T;
this.logger.debug(`System ${constructor.name} already registered, returning existing instance`);
return existingSystem;
}
if (isInjectable(constructor)) {
system = createInstance(constructor, this._services) as T;
} else {
system = new constructor() as T;
}
} else {
system = systemTypeOrInstance;
constructor = system.constructor as ServiceType<T>;
if (this._services.isRegistered(constructor)) {
const existingSystem = this._services.resolve(constructor);
if (existingSystem === system) {
this.logger.debug(`System ${constructor.name} instance already registered, returning it`);
return system;
} else {
this.logger.warn(
`Attempting to register a different instance of ${constructor.name}, ` +
'but type is already registered. Returning existing instance.'
);
return existingSystem as T;
}
}
}
system.scene = this;
// 分配添加顺序,用于稳定排序 | Assign add order for stable sorting
system.addOrder = this._systemAddCounter++;
system.setPerformanceMonitor(this.performanceMonitor);
const metadata = getSystemMetadata(constructor);
if (metadata?.updateOrder !== undefined) {
system.setUpdateOrder(metadata.updateOrder);
}
if (metadata?.enabled !== undefined) {
system.enabled = metadata.enabled;
}
this._services.registerInstance(constructor, system);
// 标记系统列表已变化
this.markSystemsOrderDirty();
// 建立组件类型到系统的索引 | Build component type to system index
this.indexSystemByComponents(system);
injectProperties(system, this._services);
// 调试模式下自动包装系统方法以收集性能数据ProfilerSDK 启用时表示调试模式)
if (ProfilerSDK.isEnabled()) {
AutoProfiler.wrapInstance(system, system.systemName, ProfileCategory.ECS);
}
system.initialize();
this.logger.debug(`System ${constructor.name} registered and initialized`);
return system;
}
/**
* 批量注册EntitySystem到场景使用DI
*
* 自动按照依赖顺序注册多个System。
* 所有System必须使用@Injectable装饰器标记。
*
* @param systemTypes System类型数组
* @returns 注册的System实例数组
*
* @example
* ```typescript
* @Injectable()
* @ECSSystem('Collision', { updateOrder: 5 })
* class CollisionSystem extends EntitySystem implements IService {
* constructor() { super(Matcher.empty().all(Collider)); }
* dispose() {}
* }
*
* @Injectable()
* @ECSSystem('Physics', { updateOrder: 10 })
* class PhysicsSystem extends EntitySystem implements IService {
* @InjectProperty(CollisionSystem)
* private collision!: CollisionSystem;
*
* constructor() {
* super(Matcher.empty().all(Transform, RigidBody));
* }
* dispose() {}
* }
*
* // 批量注册(自动解析依赖顺序)
* scene.registerSystems([
* CollisionSystem,
* PhysicsSystem, // 自动注入CollisionSystem
* RenderSystem
* ]);
* ```
*/
public registerSystems(systemTypes: Array<ServiceType<EntitySystem>>): EntitySystem[] {
const registeredSystems: EntitySystem[] = [];
for (const systemType of systemTypes) {
const system = this.addEntityProcessor(systemType);
registeredSystems.push(system);
}
return registeredSystems;
}
/**
* 添加系统到场景addEntityProcessor的别名
* @param system 系统
*/
public addSystem(system: EntitySystem) {
return this.addEntityProcessor(system);
}
/**
* 从场景中删除EntitySystem处理器
* @param processor 要删除的处理器
*/
public removeEntityProcessor(processor: EntitySystem): void {
const constructor = processor.constructor as ServiceType<EntitySystem>;
// 从ServiceContainer移除
this._services.unregister(constructor);
// 标记系统列表已变化
this.markSystemsOrderDirty();
// 从组件类型索引中移除 | Remove from component type index
this.removeSystemFromIndex(processor);
// 重置System状态
processor.reset();
}
/**
* 从场景中删除系统removeEntityProcessor的别名
* @param system 系统
*/
public removeSystem(system: EntitySystem) {
this.removeEntityProcessor(system);
}
/**
* 获取指定类型的EntitySystem处理器
*
* @deprecated 推荐使用依赖注入代替此方法。使用 `scene.services.resolve(SystemType)` 或使用 `@InjectProperty(SystemType)` 装饰器。
*
* @param type 处理器类型
* @returns 处理器实例如果未找到则返回null
*
* @example
* ```typescript
* @Injectable()
* class MySystem extends EntitySystem {
* @InjectProperty(PhysicsSystem)
* private physics!: PhysicsSystem;
*
* constructor() {
* super(Matcher.empty());
* }
* }
* ```
*/
public getEntityProcessor<T extends EntitySystem>(type: new (...args: unknown[]) => T): T | null {
return this._services.tryResolve(type as ServiceType<T>) as T | null;
}
/**
* 获取场景统计信息
*/
public getStats(): {
entityCount: number;
processorCount: number;
componentStorageStats: Map<string, { totalSlots: number; usedSlots: number; freeSlots: number; fragmentation: number }>;
} {
return {
entityCount: this.entities.count,
processorCount: this.systems.length,
componentStorageStats: this.componentStorageManager.getAllStats()
};
}
/**
* 获取场景的调试信息
*/
public getDebugInfo(): {
name: string;
entityCount: number;
processorCount: number;
isRunning: boolean;
entities: Array<{
name: string;
id: number;
componentCount: number;
componentTypes: string[];
}>;
processors: Array<{
name: string;
updateOrder: number;
entityCount: number;
}>;
componentStats: Map<string, { totalSlots: number; usedSlots: number; freeSlots: number; fragmentation: number }>;
} {
const systems = this.systems;
return {
name: this.name || this.constructor.name,
entityCount: this.entities.count,
processorCount: systems.length,
isRunning: this._didSceneBegin,
entities: this.entities.buffer.map((entity) => ({
name: entity.name,
id: entity.id,
componentCount: entity.components.length,
componentTypes: entity.components.map((c) => getComponentInstanceTypeName(c))
})),
processors: systems.map((processor) => ({
name: getSystemInstanceTypeName(processor),
updateOrder: processor.updateOrder,
entityCount: processor.entities.length
})),
componentStats: this.componentStorageManager.getAllStats()
};
}
/**
* 序列化场景
*
* 将场景及其所有实体、组件序列化为JSON字符串或二进制Uint8Array
*
* @param options 序列化选项
* @returns 序列化后的数据JSON字符串或二进制Uint8Array
*
* @example
* ```typescript
* // JSON格式
* const jsonData = scene.serialize({
* format: 'json',
* pretty: true
* });
*
* // 二进制格式(更小、更快)
* const binaryData = scene.serialize({
* format: 'binary'
* });
* ```
*/
public serialize(options?: SceneSerializationOptions): string | Uint8Array {
return SceneSerializer.serialize(this, options);
}
/**
* 反序列化场景
*
* 从序列化数据恢复场景状态
*
* @param saveData 序列化的数据JSON字符串或二进制Uint8Array
* @param options 反序列化选项
*
* @example
* ```typescript
* // 从JSON恢复自动从ComponentRegistry获取组件类型
* scene.deserialize(jsonData, {
* strategy: 'replace'
* });
*
* // 从二进制恢复
* scene.deserialize(binaryData, {
* strategy: 'replace'
* });
* ```
*/
public deserialize(saveData: string | Uint8Array, options?: SceneDeserializationOptions): void {
SceneSerializer.deserialize(this, saveData, options);
}
/** 增量序列化的基础快照 */
private _incrementalBaseSnapshot?: unknown;
/**
* 创建增量序列化的基础快照
*
* 在需要进行增量序列化前,先调用此方法创建基础快照
*
* @param options 序列化选项
*
* @example
* ```typescript
* // 创建基础快照
* scene.createIncrementalSnapshot();
*
* // 进行一些修改...
* entity.addComponent(new PositionComponent(100, 200));
*
* // 计算增量变更
* const incremental = scene.serializeIncremental();
* ```
*/
public createIncrementalSnapshot(options?: IncrementalSerializationOptions): void {
this._incrementalBaseSnapshot = IncrementalSerializer.createSnapshot(this, options);
}
/**
* 增量序列化场景
*
* 只序列化相对于基础快照的变更部分
*
* @param options 序列化选项
* @returns 增量快照对象
*
* @example
* ```typescript
* // 创建基础快照
* scene.createIncrementalSnapshot();
*
* // 修改场景
* const entity = scene.createEntity('NewEntity');
* entity.addComponent(new PositionComponent(50, 100));
*
* // 获取增量变更
* const incremental = scene.serializeIncremental();
* console.log(`变更数量: ${incremental.entityChanges.length}`);
*
* // 序列化为JSON
* const json = IncrementalSerializer.serializeIncremental(incremental);
* ```
*/
public serializeIncremental(options?: IncrementalSerializationOptions): IncrementalSnapshot {
if (!this._incrementalBaseSnapshot) {
throw new Error('必须先调用 createIncrementalSnapshot() 创建基础快照');
}
return IncrementalSerializer.computeIncremental(this, this._incrementalBaseSnapshot as Parameters<typeof IncrementalSerializer.computeIncremental>[1], options);
}
/**
* 应用增量变更到场景
*
* @param incremental 增量快照数据IncrementalSnapshot对象、JSON字符串或二进制Uint8Array
* @param componentRegistry 组件类型注册表(可选,默认使用全局注册表)
*
* @example
* ```typescript
* // 应用增量变更对象
* scene.applyIncremental(incrementalSnapshot);
*
* // 从JSON字符串应用
* const jsonData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'json' });
* scene.applyIncremental(jsonData);
*
* // 从二进制Uint8Array应用
* const binaryData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'binary' });
* scene.applyIncremental(binaryData);
* ```
*/
public applyIncremental(
incremental: IncrementalSnapshot | string | Uint8Array,
componentRegistry?: Map<string, ComponentType>
): void {
const isSerializedData = typeof incremental === 'string' || incremental instanceof Uint8Array;
const snapshot = isSerializedData
? IncrementalSerializer.deserializeIncremental(incremental as string | Uint8Array)
: (incremental as IncrementalSnapshot);
const registry = componentRegistry || (ComponentRegistry.getAllComponentNames() as Map<string, ComponentType>);
IncrementalSerializer.applyIncremental(this, snapshot, registry);
}
/**
* 更新增量快照基准
*
* 将当前场景状态设为新的增量序列化基准
*
* @param options 序列化选项
*
* @example
* ```typescript
* // 创建初始快照
* scene.createIncrementalSnapshot();
*
* // 进行一些修改并序列化
* const incremental1 = scene.serializeIncremental();
*
* // 更新基准,之后的增量将基于当前状态
* scene.updateIncrementalSnapshot();
*
* // 继续修改
* const incremental2 = scene.serializeIncremental();
* ```
*/
public updateIncrementalSnapshot(options?: IncrementalSerializationOptions): void {
this.createIncrementalSnapshot(options);
}
/**
* 清除增量快照
*
* 释放快照占用的内存
*/
public clearIncrementalSnapshot(): void {
this._incrementalBaseSnapshot = undefined;
}
/**
* 检查是否有增量快照
*
* @returns 如果已创建增量快照返回true
*/
public hasIncrementalSnapshot(): boolean {
return this._incrementalBaseSnapshot !== undefined;
}
}