From e219fc47ba601110518e2a6b0705e08072792a3a Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Mon, 9 Jun 2025 13:24:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0ECS=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E6=A8=A1=E5=9D=97=20-=20EntityManager?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E7=AE=A1=E7=90=86=E5=99=A8=E3=80=81EventBus?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=80=BB=E7=BA=BF=E3=80=81=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/src/ECS/Core/ArchetypeSystem.ts | 261 ++++++++ source/src/ECS/Core/ComponentIndex.ts | 488 +++++++++++++++ source/src/ECS/Core/DirtyTrackingSystem.ts | 375 ++++++++++++ source/src/ECS/Core/EntityManager.ts | 674 +++++++++++++++++++++ source/src/ECS/Core/EventBus.ts | 497 +++++++++++++++ source/src/performance.ts | 1 + 6 files changed, 2296 insertions(+) create mode 100644 source/src/ECS/Core/ArchetypeSystem.ts create mode 100644 source/src/ECS/Core/ComponentIndex.ts create mode 100644 source/src/ECS/Core/DirtyTrackingSystem.ts create mode 100644 source/src/ECS/Core/EntityManager.ts create mode 100644 source/src/ECS/Core/EventBus.ts create mode 100644 source/src/performance.ts diff --git a/source/src/ECS/Core/ArchetypeSystem.ts b/source/src/ECS/Core/ArchetypeSystem.ts new file mode 100644 index 00000000..c1f889eb --- /dev/null +++ b/source/src/ECS/Core/ArchetypeSystem.ts @@ -0,0 +1,261 @@ +import { Entity } from '../Entity'; +import { ComponentType } from './ComponentStorage'; + +/** + * 原型标识符 + */ +export type ArchetypeId = string; + +/** + * 原型数据结构 + */ +export interface Archetype { + /** 原型唯一标识符 */ + id: ArchetypeId; + /** 包含的组件类型 */ + componentTypes: ComponentType[]; + /** 属于该原型的实体列表 */ + entities: Entity[]; + /** 原型创建时间 */ + createdAt: number; + /** 最后更新时间 */ + updatedAt: number; +} + +/** + * 原型查询结果 + */ +export interface ArchetypeQueryResult { + /** 匹配的原型列表 */ + archetypes: Archetype[]; + /** 所有匹配实体的总数 */ + totalEntities: number; + /** 查询执行时间(毫秒) */ + executionTime: number; + /** 是否使用了缓存 */ + fromCache: boolean; +} + +/** + * Archetype系统 + * + * 根据实体的组件组合将实体分组到不同的原型中,提供高效的查询性能。 + */ +export class ArchetypeSystem { + /** 所有原型的映射表 */ + private _archetypes = new Map(); + + /** 实体到原型的映射 */ + private _entityToArchetype = new Map(); + + /** 组件类型到原型的映射 */ + private _componentToArchetypes = new Map>(); + + /** 查询缓存 */ + private _queryCache = new Map(); + + private _cacheTimeout = 5000; + private _maxCacheSize = 100; + + /** + * 添加实体到原型系统 + */ + public addEntity(entity: Entity): void { + const componentTypes = this.getEntityComponentTypes(entity); + const archetypeId = this.generateArchetypeId(componentTypes); + + let archetype = this._archetypes.get(archetypeId); + if (!archetype) { + archetype = this.createArchetype(componentTypes); + } + + archetype.entities.push(entity); + archetype.updatedAt = Date.now(); + this._entityToArchetype.set(entity, archetype); + + this.updateComponentIndexes(archetype, componentTypes, true); + this.invalidateQueryCache(); + } + + /** + * 从原型系统中移除实体 + */ + public removeEntity(entity: Entity): void { + const archetype = this._entityToArchetype.get(entity); + if (!archetype) return; + + const index = archetype.entities.indexOf(entity); + if (index !== -1) { + archetype.entities.splice(index, 1); + archetype.updatedAt = Date.now(); + } + + this._entityToArchetype.delete(entity); + this.invalidateQueryCache(); + } + + /** + * 查询包含指定组件组合的原型 + */ + public queryArchetypes(componentTypes: ComponentType[], operation: 'AND' | 'OR' = 'AND'): ArchetypeQueryResult { + const startTime = performance.now(); + + const cacheKey = `${operation}:${componentTypes.map(t => t.name).sort().join(',')}`; + + // 检查缓存 + const cached = this._queryCache.get(cacheKey); + if (cached && (Date.now() - cached.timestamp < this._cacheTimeout)) { + return { + ...cached.result, + executionTime: performance.now() - startTime, + fromCache: true + }; + } + + const matchingArchetypes: Archetype[] = []; + let totalEntities = 0; + + if (operation === 'AND') { + for (const archetype of this._archetypes.values()) { + if (this.archetypeContainsAllComponents(archetype, componentTypes)) { + matchingArchetypes.push(archetype); + totalEntities += archetype.entities.length; + } + } + } else { + const foundArchetypes = new Set(); + + for (const componentType of componentTypes) { + const archetypes = this._componentToArchetypes.get(componentType); + if (archetypes) { + for (const archetype of archetypes) { + foundArchetypes.add(archetype); + } + } + } + + for (const archetype of foundArchetypes) { + matchingArchetypes.push(archetype); + totalEntities += archetype.entities.length; + } + } + + const result: ArchetypeQueryResult = { + archetypes: matchingArchetypes, + totalEntities, + executionTime: performance.now() - startTime, + fromCache: false + }; + + // 缓存结果 + this._queryCache.set(cacheKey, { + result, + timestamp: Date.now() + }); + + return result; + } + + /** + * 获取实体所属的原型 + */ + public getEntityArchetype(entity: Entity): Archetype | undefined { + return this._entityToArchetype.get(entity); + } + + /** + * 获取所有原型 + */ + public getAllArchetypes(): Archetype[] { + return Array.from(this._archetypes.values()); + } + + /** + * 清空所有数据 + */ + public clear(): void { + this._archetypes.clear(); + this._entityToArchetype.clear(); + this._componentToArchetypes.clear(); + this._queryCache.clear(); + } + + /** + * 获取实体的组件类型列表 + */ + private getEntityComponentTypes(entity: Entity): ComponentType[] { + return entity.components.map(component => component.constructor as ComponentType); + } + + /** + * 生成原型ID + */ + private generateArchetypeId(componentTypes: ComponentType[]): ArchetypeId { + return componentTypes + .map(type => type.name) + .sort() + .join('|'); + } + + /** + * 创建新原型 + */ + private createArchetype(componentTypes: ComponentType[]): Archetype { + const id = this.generateArchetypeId(componentTypes); + + const archetype: Archetype = { + id, + componentTypes: [...componentTypes], + entities: [], + createdAt: Date.now(), + updatedAt: Date.now() + }; + + this._archetypes.set(id, archetype); + return archetype; + } + + /** + * 检查原型是否包含所有指定组件 + */ + private archetypeContainsAllComponents(archetype: Archetype, componentTypes: ComponentType[]): boolean { + for (const componentType of componentTypes) { + if (!archetype.componentTypes.includes(componentType)) { + return false; + } + } + return true; + } + + /** + * 更新组件索引 + */ + private updateComponentIndexes(archetype: Archetype, componentTypes: ComponentType[], add: boolean): void { + for (const componentType of componentTypes) { + let archetypes = this._componentToArchetypes.get(componentType); + if (!archetypes) { + archetypes = new Set(); + this._componentToArchetypes.set(componentType, archetypes); + } + + if (add) { + archetypes.add(archetype); + } else { + archetypes.delete(archetype); + if (archetypes.size === 0) { + this._componentToArchetypes.delete(componentType); + } + } + } + } + + /** + * 使查询缓存失效 + */ + private invalidateQueryCache(): void { + this._queryCache.clear(); + } +} diff --git a/source/src/ECS/Core/ComponentIndex.ts b/source/src/ECS/Core/ComponentIndex.ts new file mode 100644 index 00000000..c40aa504 --- /dev/null +++ b/source/src/ECS/Core/ComponentIndex.ts @@ -0,0 +1,488 @@ +import { Entity } from '../Entity'; +import { Component } from '../Component'; +import { ComponentType } from './ComponentStorage'; + +/** + * 组件索引类型 + */ +export enum IndexType { + /** 哈希索引 - 最快查找 */ + HASH = 'hash', + /** 位图索引 - 内存高效 */ + BITMAP = 'bitmap', + /** 排序索引 - 支持范围查询 */ + SORTED = 'sorted' +} + +/** + * 索引统计信息 + */ +export interface IndexStats { + /** 索引类型 */ + type: IndexType; + /** 索引大小 */ + size: number; + /** 内存使用量(字节) */ + memoryUsage: number; + /** 查询次数 */ + queryCount: number; + /** 平均查询时间(毫秒) */ + avgQueryTime: number; + /** 最后更新时间 */ + lastUpdated: number; +} + +/** + * 组件索引接口 + */ +export interface IComponentIndex { + /** 索引类型 */ + readonly type: IndexType; + /** 添加实体到索引 */ + addEntity(entity: Entity): void; + /** 从索引中移除实体 */ + removeEntity(entity: Entity): void; + /** 查询包含指定组件的实体 */ + query(componentType: ComponentType): Set; + /** 批量查询多个组件 */ + queryMultiple(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set; + /** 清空索引 */ + clear(): void; + /** 获取索引统计信息 */ + getStats(): IndexStats; +} + +/** + * 哈希索引实现 + * + * 使用Map数据结构,提供O(1)的查找性能。 + * 适合大多数查询场景。 + */ +export class HashComponentIndex implements IComponentIndex { + public readonly type = IndexType.HASH; + + private _componentToEntities = new Map>(); + private _entityToComponents = new Map>(); + private _queryCount = 0; + private _totalQueryTime = 0; + private _lastUpdated = Date.now(); + + public addEntity(entity: Entity): void { + const components = entity.components; + const componentTypes = new Set(); + + for (const component of components) { + const componentType = component.constructor as ComponentType; + componentTypes.add(componentType); + + let entities = this._componentToEntities.get(componentType); + if (!entities) { + entities = new Set(); + this._componentToEntities.set(componentType, entities); + } + entities.add(entity); + } + + this._entityToComponents.set(entity, componentTypes); + this._lastUpdated = Date.now(); + } + + public removeEntity(entity: Entity): void { + const componentTypes = this._entityToComponents.get(entity); + if (!componentTypes) return; + + for (const componentType of componentTypes) { + const entities = this._componentToEntities.get(componentType); + if (entities) { + entities.delete(entity); + if (entities.size === 0) { + this._componentToEntities.delete(componentType); + } + } + } + + this._entityToComponents.delete(entity); + this._lastUpdated = Date.now(); + } + + public query(componentType: ComponentType): Set { + const startTime = performance.now(); + const result = new Set(this._componentToEntities.get(componentType) || []); + + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + + return result; + } + + public queryMultiple(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set { + const startTime = performance.now(); + + if (componentTypes.length === 0) { + return new Set(); + } + + if (componentTypes.length === 1) { + return this.query(componentTypes[0]); + } + + let result: Set; + + if (operation === 'AND') { + let smallestSet: Set | undefined; + let smallestSize = Infinity; + + for (const componentType of componentTypes) { + const entities = this._componentToEntities.get(componentType); + if (!entities || entities.size === 0) { + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + return new Set(); + } + if (entities.size < smallestSize) { + smallestSize = entities.size; + smallestSet = entities; + } + } + + result = new Set(); + if (smallestSet) { + for (const entity of smallestSet) { + let hasAll = true; + for (const componentType of componentTypes) { + const entities = this._componentToEntities.get(componentType); + if (!entities || !entities.has(entity)) { + hasAll = false; + break; + } + } + if (hasAll) { + result.add(entity); + } + } + } + } else { + result = new Set(); + for (const componentType of componentTypes) { + const entities = this._componentToEntities.get(componentType); + if (entities) { + for (const entity of entities) { + result.add(entity); + } + } + } + } + + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + + return result; + } + + public clear(): void { + this._componentToEntities.clear(); + this._entityToComponents.clear(); + this._lastUpdated = Date.now(); + } + + public getStats(): IndexStats { + let memoryUsage = 0; + + memoryUsage += this._componentToEntities.size * 64; + memoryUsage += this._entityToComponents.size * 64; + + for (const entities of this._componentToEntities.values()) { + memoryUsage += entities.size * 8; + } + + for (const components of this._entityToComponents.values()) { + memoryUsage += components.size * 8; + } + + return { + type: this.type, + size: this._componentToEntities.size, + memoryUsage, + queryCount: this._queryCount, + avgQueryTime: this._queryCount > 0 ? this._totalQueryTime / this._queryCount : 0, + lastUpdated: this._lastUpdated + }; + } +} + +/** + * 位图索引实现 + * + * 使用位操作进行快速集合运算,内存效率高。 + * 适合有限组件类型和大量实体的场景。 + */ +export class BitmapComponentIndex implements IComponentIndex { + public readonly type = IndexType.BITMAP; + + private _componentTypeToBit = new Map(); + private _entityToBitmap = new Map(); + private _bitToEntities = new Map>(); + private _nextBit = 0; + private _queryCount = 0; + private _totalQueryTime = 0; + private _lastUpdated = Date.now(); + + public addEntity(entity: Entity): void { + let bitmap = 0; + + for (const component of entity.components) { + const componentType = component.constructor as ComponentType; + let bit = this._componentTypeToBit.get(componentType); + + if (bit === undefined) { + bit = this._nextBit++; + this._componentTypeToBit.set(componentType, bit); + } + + bitmap |= (1 << bit); + + let entities = this._bitToEntities.get(1 << bit); + if (!entities) { + entities = new Set(); + this._bitToEntities.set(1 << bit, entities); + } + entities.add(entity); + } + + this._entityToBitmap.set(entity, bitmap); + this._lastUpdated = Date.now(); + } + + public removeEntity(entity: Entity): void { + const bitmap = this._entityToBitmap.get(entity); + if (bitmap === undefined) return; + + // 从所有相关的位集合中移除实体 + for (const [bitMask, entities] of this._bitToEntities) { + if ((bitmap & bitMask) !== 0) { + entities.delete(entity); + if (entities.size === 0) { + this._bitToEntities.delete(bitMask); + } + } + } + + this._entityToBitmap.delete(entity); + this._lastUpdated = Date.now(); + } + + public query(componentType: ComponentType): Set { + const startTime = performance.now(); + + const bit = this._componentTypeToBit.get(componentType); + if (bit === undefined) { + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + return new Set(); + } + + const result = new Set(this._bitToEntities.get(1 << bit) || []); + + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + + return result; + } + + public queryMultiple(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set { + const startTime = performance.now(); + + if (componentTypes.length === 0) { + return new Set(); + } + + let targetBitmap = 0; + const validBits: number[] = []; + + for (const componentType of componentTypes) { + const bit = this._componentTypeToBit.get(componentType); + if (bit !== undefined) { + targetBitmap |= (1 << bit); + validBits.push(1 << bit); + } + } + + const result = new Set(); + + if (operation === 'AND') { + for (const [entity, entityBitmap] of this._entityToBitmap) { + if ((entityBitmap & targetBitmap) === targetBitmap) { + result.add(entity); + } + } + } else { + for (const bitMask of validBits) { + const entities = this._bitToEntities.get(bitMask); + if (entities) { + for (const entity of entities) { + result.add(entity); + } + } + } + } + + this._queryCount++; + this._totalQueryTime += performance.now() - startTime; + + return result; + } + + public clear(): void { + this._componentTypeToBit.clear(); + this._entityToBitmap.clear(); + this._bitToEntities.clear(); + this._nextBit = 0; + this._lastUpdated = Date.now(); + } + + public getStats(): IndexStats { + let memoryUsage = 0; + + memoryUsage += this._componentTypeToBit.size * 12; + memoryUsage += this._entityToBitmap.size * 12; + memoryUsage += this._bitToEntities.size * 64; + + for (const entities of this._bitToEntities.values()) { + memoryUsage += entities.size * 8; + } + + return { + type: this.type, + size: this._componentTypeToBit.size, + memoryUsage, + queryCount: this._queryCount, + avgQueryTime: this._queryCount > 0 ? this._totalQueryTime / this._queryCount : 0, + lastUpdated: this._lastUpdated + }; + } +} + +/** + * 智能组件索引管理器 + * + * 根据使用模式自动选择最优的索引策略。 + * 支持动态切换索引类型以获得最佳性能。 + */ +export class ComponentIndexManager { + private _activeIndex: IComponentIndex; + private _indexHistory: Map = new Map(); + private _autoOptimize = true; + private _optimizationThreshold = 1000; + + constructor(initialType: IndexType = IndexType.HASH) { + this._activeIndex = this.createIndex(initialType); + } + + /** + * 添加实体到索引 + */ + public addEntity(entity: Entity): void { + this._activeIndex.addEntity(entity); + this.checkOptimization(); + } + + /** + * 从索引中移除实体 + */ + public removeEntity(entity: Entity): void { + this._activeIndex.removeEntity(entity); + } + + /** + * 查询包含指定组件的实体 + */ + public query(componentType: ComponentType): Set { + return this._activeIndex.query(componentType); + } + + /** + * 批量查询多个组件 + */ + public queryMultiple(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set { + return this._activeIndex.queryMultiple(componentTypes, operation); + } + + /** + * 手动切换索引类型 + */ + public switchIndexType(type: IndexType): void { + if (type === this._activeIndex.type) return; + + this._indexHistory.set(this._activeIndex.type, this._activeIndex.getStats()); + + const oldIndex = this._activeIndex; + this._activeIndex = this.createIndex(type); + + oldIndex.clear(); + } + + /** + * 启用/禁用自动优化 + */ + public setAutoOptimize(enabled: boolean): void { + this._autoOptimize = enabled; + } + + /** + * 获取当前索引统计信息 + */ + public getStats(): IndexStats { + return this._activeIndex.getStats(); + } + + /** + * 获取所有索引类型的历史统计信息 + */ + public getAllStats(): Map { + const current = this._activeIndex.getStats(); + return new Map([ + ...this._indexHistory, + [current.type, current] + ]); + } + + /** + * 清空索引 + */ + public clear(): void { + this._activeIndex.clear(); + } + + /** + * 创建指定类型的索引 + */ + private createIndex(type: IndexType): IComponentIndex { + switch (type) { + case IndexType.HASH: + return new HashComponentIndex(); + case IndexType.BITMAP: + return new BitmapComponentIndex(); + case IndexType.SORTED: + return new HashComponentIndex(); + default: + return new HashComponentIndex(); + } + } + + /** + * 检查是否需要优化索引 + */ + private checkOptimization(): void { + if (!this._autoOptimize) return; + + const stats = this._activeIndex.getStats(); + if (stats.queryCount < this._optimizationThreshold) return; + + + if (stats.avgQueryTime > 1.0 && stats.type !== IndexType.HASH) { + this.switchIndexType(IndexType.HASH); + } else if (stats.memoryUsage > 10 * 1024 * 1024 && stats.type !== IndexType.BITMAP) { + this.switchIndexType(IndexType.BITMAP); + } + } +} \ No newline at end of file diff --git a/source/src/ECS/Core/DirtyTrackingSystem.ts b/source/src/ECS/Core/DirtyTrackingSystem.ts new file mode 100644 index 00000000..1b03ae33 --- /dev/null +++ b/source/src/ECS/Core/DirtyTrackingSystem.ts @@ -0,0 +1,375 @@ +import { Entity } from '../Entity'; +import { Component } from '../Component'; +import { ComponentType } from './ComponentStorage'; + +/** + * 脏标记类型 + */ +export enum DirtyFlag { + /** 组件数据已修改 */ + COMPONENT_MODIFIED = 1 << 0, + /** 组件已添加 */ + COMPONENT_ADDED = 1 << 1, + /** 组件已移除 */ + COMPONENT_REMOVED = 1 << 2, + /** 实体位置已改变 */ + TRANSFORM_CHANGED = 1 << 3, + /** 实体状态已改变 */ + STATE_CHANGED = 1 << 4, + /** 自定义标记1 */ + CUSTOM_1 = 1 << 8, + /** 自定义标记2 */ + CUSTOM_2 = 1 << 9, + /** 自定义标记3 */ + CUSTOM_3 = 1 << 10, + /** 所有标记 */ + ALL = 0xFFFFFFFF +} + +/** + * 脏标记数据 + */ +export interface DirtyData { + /** 实体引用 */ + entity: Entity; + /** 脏标记位 */ + flags: number; + /** 修改的组件类型列表 */ + modifiedComponents: Set; + /** 标记时间戳 */ + timestamp: number; + /** 帧编号 */ + frameNumber: number; +} + +/** + * 脏标记监听器 + */ +export interface DirtyListener { + /** 感兴趣的标记类型 */ + flags: number; + /** 回调函数 */ + callback: (dirtyData: DirtyData) => void; + /** 监听器优先级(数字越小优先级越高) */ + priority?: number; +} + +/** + * 脏标记统计信息 + */ +export interface DirtyStats { + /** 当前脏实体数量 */ + dirtyEntityCount: number; + /** 总标记次数 */ + totalMarkings: number; + /** 总清理次数 */ + totalCleanups: number; + /** 监听器数量 */ + listenerCount: number; + /** 平均每帧脏实体数量 */ + avgDirtyPerFrame: number; + /** 内存使用量估算 */ + estimatedMemoryUsage: number; +} + +/** + * 脏标记追踪系统 + * + * 提供高效的组件和实体变更追踪,避免不必要的计算和更新。 + * 支持细粒度的脏标记和批量处理机制。 + * + * @example + * ```typescript + * const dirtySystem = new DirtyTrackingSystem(); + * + * // 标记实体的位置组件已修改 + * dirtySystem.markDirty(entity, DirtyFlag.TRANSFORM_CHANGED, [PositionComponent]); + * + * // 监听位置变化 + * dirtySystem.addListener({ + * flags: DirtyFlag.TRANSFORM_CHANGED, + * callback: (data) => { + * console.log('Entity position changed:', data.entity.name); + * } + * }); + * + * // 处理所有脏标记 + * dirtySystem.processDirtyEntities(); + * ``` + */ +export class DirtyTrackingSystem { + /** 脏实体映射表 */ + private _dirtyEntities = new Map(); + + /** 脏标记监听器 */ + private _listeners: DirtyListener[] = []; + + /** 性能统计 */ + private _stats = { + totalMarkings: 0, + totalCleanups: 0, + frameCount: 0, + totalDirtyPerFrame: 0 + }; + + /** 当前帧编号 */ + private _currentFrame = 0; + + private _batchSize = 100; + private _maxProcessingTime = 16; + + /** 延迟处理队列 */ + private _processingQueue: DirtyData[] = []; + private _isProcessing = false; + + /** + * 标记实体为脏状态 + * + * @param entity 要标记的实体 + * @param flags 脏标记位 + * @param modifiedComponents 修改的组件类型列表 + */ + public markDirty(entity: Entity, flags: DirtyFlag, modifiedComponents: ComponentType[] = []): void { + this._stats.totalMarkings++; + + let dirtyData = this._dirtyEntities.get(entity); + if (!dirtyData) { + dirtyData = { + entity, + flags: 0, + modifiedComponents: new Set(), + timestamp: performance.now(), + frameNumber: this._currentFrame + }; + this._dirtyEntities.set(entity, dirtyData); + } + + dirtyData.flags |= flags; + dirtyData.timestamp = performance.now(); + dirtyData.frameNumber = this._currentFrame; + + for (const componentType of modifiedComponents) { + dirtyData.modifiedComponents.add(componentType); + } + + this.notifyListeners(dirtyData, flags); + } + + /** + * 检查实体是否有指定的脏标记 + * + * @param entity 要检查的实体 + * @param flags 要检查的标记位 + * @returns 是否有指定的脏标记 + */ + public isDirty(entity: Entity, flags: DirtyFlag = DirtyFlag.ALL): boolean { + const dirtyData = this._dirtyEntities.get(entity); + return dirtyData ? (dirtyData.flags & flags) !== 0 : false; + } + + /** + * 清除实体的脏标记 + * + * @param entity 要清除的实体 + * @param flags 要清除的标记位,默认清除所有 + */ + public clearDirty(entity: Entity, flags: DirtyFlag = DirtyFlag.ALL): void { + const dirtyData = this._dirtyEntities.get(entity); + if (!dirtyData) return; + + if (flags === DirtyFlag.ALL) { + this._dirtyEntities.delete(entity); + } else { + dirtyData.flags &= ~flags; + if (dirtyData.flags === 0) { + this._dirtyEntities.delete(entity); + } + } + + this._stats.totalCleanups++; + } + + /** + * 获取所有脏实体 + * + * @param flags 过滤标记位,只返回包含指定标记的实体 + * @returns 脏实体数据数组 + */ + public getDirtyEntities(flags: DirtyFlag = DirtyFlag.ALL): DirtyData[] { + const result: DirtyData[] = []; + + for (const dirtyData of this._dirtyEntities.values()) { + if ((dirtyData.flags & flags) !== 0) { + result.push(dirtyData); + } + } + + return result; + } + + /** + * 批量处理脏实体 + * + * 使用时间分片的方式处理脏实体,避免单帧卡顿 + */ + public processDirtyEntities(): void { + if (this._isProcessing) return; + + this._isProcessing = true; + const startTime = performance.now(); + + if (this._processingQueue.length === 0) { + this._processingQueue.push(...this._dirtyEntities.values()); + } + + let processed = 0; + while (this._processingQueue.length > 0 && processed < this._batchSize) { + const elapsed = performance.now() - startTime; + if (elapsed > this._maxProcessingTime) { + break; + } + + const dirtyData = this._processingQueue.shift()!; + this.processEntity(dirtyData); + processed++; + } + + if (this._processingQueue.length === 0) { + this._isProcessing = false; + this.onFrameEnd(); + } + } + + /** + * 添加脏标记监听器 + * + * @param listener 监听器配置 + */ + public addListener(listener: DirtyListener): void { + this._listeners.push(listener); + + this._listeners.sort((a, b) => (a.priority || 100) - (b.priority || 100)); + } + + /** + * 移除脏标记监听器 + * + * @param callback 要移除的回调函数 + */ + public removeListener(callback: (dirtyData: DirtyData) => void): void { + const index = this._listeners.findIndex(l => l.callback === callback); + if (index !== -1) { + this._listeners.splice(index, 1); + } + } + + /** + * 开始新的帧 + */ + public beginFrame(): void { + this._currentFrame++; + } + + /** + * 结束当前帧 + */ + public endFrame(): void { + if (!this._isProcessing) { + this.processDirtyEntities(); + } + } + + /** + * 获取统计信息 + */ + public getStats(): DirtyStats { + return { + dirtyEntityCount: this._dirtyEntities.size, + totalMarkings: this._stats.totalMarkings, + totalCleanups: this._stats.totalCleanups, + listenerCount: this._listeners.length, + avgDirtyPerFrame: this._stats.frameCount > 0 ? + this._stats.totalDirtyPerFrame / this._stats.frameCount : 0, + estimatedMemoryUsage: this.estimateMemoryUsage() + }; + } + + /** + * 清空所有脏标记和统计信息 + */ + public clear(): void { + this._dirtyEntities.clear(); + this._processingQueue.length = 0; + this._isProcessing = false; + this._stats = { + totalMarkings: 0, + totalCleanups: 0, + frameCount: 0, + totalDirtyPerFrame: 0 + }; + } + + /** + * 配置批量处理参数 + * + * @param batchSize 每次处理的最大实体数量 + * @param maxProcessingTime 每帧最大处理时间(毫秒) + */ + public configureBatchProcessing(batchSize: number, maxProcessingTime: number): void { + this._batchSize = batchSize; + this._maxProcessingTime = maxProcessingTime; + } + + /** + * 处理单个脏实体 + */ + private processEntity(dirtyData: DirtyData): void { + for (const listener of this._listeners) { + if ((dirtyData.flags & listener.flags) !== 0) { + try { + listener.callback(dirtyData); + } catch (error) { + console.error('Dirty listener error:', error); + } + } + } + + this.clearDirty(dirtyData.entity); + } + + /** + * 通知监听器 + */ + private notifyListeners(dirtyData: DirtyData, newFlags: DirtyFlag): void { + for (const listener of this._listeners) { + if ((newFlags & listener.flags) !== 0) { + try { + listener.callback(dirtyData); + } catch (error) { + console.error('Dirty listener notification error:', error); + } + } + } + } + + /** + * 帧结束时的统计更新 + */ + private onFrameEnd(): void { + this._stats.frameCount++; + this._stats.totalDirtyPerFrame += this._dirtyEntities.size; + } + + /** + * 估算内存使用量 + */ + private estimateMemoryUsage(): number { + let usage = 0; + + usage += this._dirtyEntities.size * 100; + usage += this._listeners.length * 50; + usage += this._processingQueue.length * 8; + + return usage; + } +} \ No newline at end of file diff --git a/source/src/ECS/Core/EntityManager.ts b/source/src/ECS/Core/EntityManager.ts new file mode 100644 index 00000000..eda6ce35 --- /dev/null +++ b/source/src/ECS/Core/EntityManager.ts @@ -0,0 +1,674 @@ +import { Entity } from '../Entity'; +import { Component } from '../Component'; +import { ComponentType } from './ComponentStorage'; +import { IdentifierPool } from '../Utils/IdentifierPool'; +import { ComponentIndexManager, IndexType } from './ComponentIndex'; +import { ArchetypeSystem } from './ArchetypeSystem'; +import { DirtyTrackingSystem, DirtyFlag } from './DirtyTrackingSystem'; +import { EventBus } from './EventBus'; +import { ECSEventType } from '../CoreEvents'; +import { IEntityEventData, IComponentEventData } from '../../Types'; + +/** + * 实体查询构建器 + * + * 提供流式API来构建复杂的实体查询条件。支持组件过滤、标签过滤、状态过滤和自定义条件。 + * + * @example + * ```typescript + * const results = entityManager.query() + * .withAll(PositionComponent, HealthComponent) + * .without(VelocityComponent) + * .withTag(1) + * .active() + * .where(entity => entity.name.startsWith("Player")) + * .execute(); + * ``` + */ +export class EntityQueryBuilder { + /** 必须包含的组件类型 */ + private _allComponents: ComponentType[] = []; + /** 至少包含一个的组件类型 */ + private _anyComponents: ComponentType[] = []; + /** 不能包含的组件类型 */ + private _withoutComponents: ComponentType[] = []; + /** 必须包含的标签 */ + private _withTags: number[] = []; + /** 不能包含的标签 */ + private _withoutTags: number[] = []; + /** 是否只查询激活状态的实体 */ + private _activeOnly: boolean = false; + /** 是否只查询启用状态的实体 */ + private _enabledOnly: boolean = false; + /** 自定义过滤条件 */ + private _customPredicates: Array<(entity: Entity) => boolean> = []; + + /** + * 创建查询构建器实例 + * @param entityManager 实体管理器实例 + */ + constructor(private entityManager: EntityManager) {} + + /** + * 添加必须包含的组件条件 + * + * 返回的实体必须包含所有指定的组件类型。 + * + * @param componentTypes 组件类型列表 + * @returns 查询构建器实例,支持链式调用 + */ + public withAll(...componentTypes: ComponentType[]): EntityQueryBuilder { + this._allComponents.push(...componentTypes); + return this; + } + + /** + * 添加至少包含一个的组件条件 + * + * 返回的实体必须至少包含其中一个指定的组件类型。 + * + * @param componentTypes 组件类型列表 + * @returns 查询构建器实例,支持链式调用 + */ + public withAny(...componentTypes: ComponentType[]): EntityQueryBuilder { + this._anyComponents.push(...componentTypes); + return this; + } + + /** + * 添加不能包含的组件条件 + * + * 返回的实体不能包含任何指定的组件类型。 + * + * @param componentTypes 组件类型列表 + * @returns 查询构建器实例,支持链式调用 + */ + public without(...componentTypes: ComponentType[]): EntityQueryBuilder { + this._withoutComponents.push(...componentTypes); + return this; + } + + /** + * 添加必须包含的标签条件 + * + * 返回的实体必须具有指定的标签。 + * + * @param tag 标签值 + * @returns 查询构建器实例,支持链式调用 + */ + public withTag(tag: number): EntityQueryBuilder { + this._withTags.push(tag); + return this; + } + + /** + * 添加不能包含的标签条件 + * + * 返回的实体不能具有指定的标签。 + * + * @param tag 标签值 + * @returns 查询构建器实例,支持链式调用 + */ + public withoutTag(tag: number): EntityQueryBuilder { + this._withoutTags.push(tag); + return this; + } + + /** + * 添加激活状态过滤条件 + * + * 返回的实体必须处于激活状态(active = true)。 + * + * @returns 查询构建器实例,支持链式调用 + */ + public active(): EntityQueryBuilder { + this._activeOnly = true; + return this; + } + + /** + * 添加启用状态过滤条件 + * + * 返回的实体必须处于启用状态(enabled = true)。 + * + * @returns 查询构建器实例,支持链式调用 + */ + public enabled(): EntityQueryBuilder { + this._enabledOnly = true; + return this; + } + + /** + * 添加自定义过滤条件 + * + * 允许用户定义复杂的过滤逻辑。 + * + * @param predicate 自定义过滤函数,接收实体作为参数,返回布尔值 + * @returns 查询构建器实例,支持链式调用 + * + * @example + * ```typescript + * .where(entity => entity.name.startsWith("Player")) + * .where(entity => entity.components.length > 5) + * ``` + */ + public where(predicate: (entity: Entity) => boolean): EntityQueryBuilder { + this._customPredicates.push(predicate); + return this; + } + + /** + * 执行查询并返回所有匹配的实体 + * + * @returns 符合所有查询条件的实体数组 + */ + public execute(): Entity[] { + let candidates: Entity[] = []; + + if (this._allComponents.length > 0) { + const indexResult = this.entityManager.queryWithComponentIndex(this._allComponents, 'AND'); + candidates = Array.from(indexResult); + } else if (this._anyComponents.length > 0) { + const indexResult = this.entityManager.queryWithComponentIndex(this._anyComponents, 'OR'); + candidates = Array.from(indexResult); + } else { + candidates = this.entityManager.getAllEntities(); + } + + return candidates.filter(entity => this.matchesEntity(entity)); + } + + /** + * 执行查询并返回第一个匹配的实体 + * + * @returns 第一个符合查询条件的实体,如果没有找到则返回null + */ + public first(): Entity | null { + const entities = this.entityManager.getAllEntities(); + return entities.find(entity => this.matchesEntity(entity)) || null; + } + + /** + * 执行查询并返回匹配实体的数量 + * + * @returns 符合查询条件的实体数量 + */ + public count(): number { + const entities = this.entityManager.getAllEntities(); + return entities.filter(entity => this.matchesEntity(entity)).length; + } + + /** + * 对所有匹配的实体执行指定操作 + * + * @param action 要执行的操作函数,接收匹配的实体作为参数 + */ + public forEach(action: (entity: Entity) => void): void { + const entities = this.entityManager.getAllEntities(); + entities.forEach(entity => { + if (this.matchesEntity(entity)) { + action(entity); + } + }); + } + + /** + * 检查实体是否匹配所有查询条件 + * + * 按优先级顺序检查各种过滤条件,一旦发现不匹配立即返回false。 + * + * @param entity 要检查的实体 + * @returns 实体是否匹配所有查询条件 + */ + private matchesEntity(entity: Entity): boolean { + // 检查激活状态 + if (this._activeOnly && !entity.active) { + return false; + } + + // 检查启用状态 + if (this._enabledOnly && !entity.enabled) { + return false; + } + + // 检查必须包含的组件 + if (this._allComponents.length > 0) { + for (const componentType of this._allComponents) { + if (!entity.hasComponent(componentType)) { + return false; + } + } + } + + // 检查至少包含一个的组件 + if (this._anyComponents.length > 0) { + let hasAny = false; + for (const componentType of this._anyComponents) { + if (entity.hasComponent(componentType)) { + hasAny = true; + break; + } + } + if (!hasAny) { + return false; + } + } + + // 检查不能包含的组件 + if (this._withoutComponents.length > 0) { + for (const componentType of this._withoutComponents) { + if (entity.hasComponent(componentType)) { + return false; + } + } + } + + // 检查必须包含的标签 + if (this._withTags.length > 0) { + if (!this._withTags.includes(entity.tag)) { + return false; + } + } + + // 检查不能包含的标签 + if (this._withoutTags.length > 0) { + if (this._withoutTags.includes(entity.tag)) { + return false; + } + } + + // 检查自定义条件 + if (this._customPredicates.length > 0) { + for (const predicate of this._customPredicates) { + if (!predicate(entity)) { + return false; + } + } + } + + return true; + } +} + +/** + * 实体管理器 + * + * 提供统一的实体管理和查询机制,支持高效的实体操作。 + * 包括实体的创建、销毁、查询和索引管理功能。 + * + * @example + * ```typescript + * const entityManager = new EntityManager(); + * + * // 创建实体 + * const player = entityManager.createEntity("Player"); + * + * // 查询实体 + * const playerEntity = entityManager.getEntityByName("Player"); + * + * // 复杂查询 + * const results = entityManager.query() + * .withAll(HealthComponent, PositionComponent) + * .active() + * .execute(); + * ``` + */ +export class EntityManager { + /** 主要实体存储,使用ID作为键 */ + private _entities: Map = new Map(); + /** 按名称索引的实体映射 */ + private _entitiesByName: Map = new Map(); + /** 按标签索引的实体映射 */ + private _entitiesByTag: Map = new Map(); + /** 实体ID分配器 */ + private _identifierPool: IdentifierPool; + /** 已销毁实体的ID集合 */ + private _destroyedEntities: Set = new Set(); + + /** 性能优化系统 */ + private _componentIndexManager: ComponentIndexManager; + private _archetypeSystem: ArchetypeSystem; + private _dirtyTrackingSystem: DirtyTrackingSystem; + /** 事件总线 */ + private _eventBus: EventBus; + + /** + * 创建实体管理器实例 + * + * 初始化内部数据结构和ID分配器。 + */ + constructor() { + this._identifierPool = new IdentifierPool(); + + // 初始化性能优化系统 + this._componentIndexManager = new ComponentIndexManager(IndexType.HASH); + this._archetypeSystem = new ArchetypeSystem(); + this._dirtyTrackingSystem = new DirtyTrackingSystem(); + this._eventBus = new EventBus(false); + + // 设置Entity的静态事件总线引用 + Entity.eventBus = this._eventBus; + } + + /** + * 获取实体总数 + * + * @returns 当前管理的实体总数量 + */ + public get entityCount(): number { + return this._entities.size; + } + + /** + * 获取激活状态的实体数量 + * + * 只计算同时满足激活状态且未被销毁的实体。 + * + * @returns 激活状态的实体数量 + */ + public get activeEntityCount(): number { + let count = 0; + for (const entity of this._entities.values()) { + if (entity.active && !entity.isDestroyed) { + count++; + } + } + return count; + } + + /** + * 创建新实体 + * + * 分配唯一ID并将实体添加到管理系统中,同时更新相关索引。 + * + * @param name 实体名称,如果未指定则使用时间戳生成默认名称 + * @returns 创建的实体实例 + * + * @example + * ```typescript + * const player = entityManager.createEntity("Player"); + * const enemy = entityManager.createEntity(); // 使用默认名称 + * ``` + */ + public createEntity(name: string = `Entity_${Date.now()}`): Entity { + const id = this._identifierPool.checkOut(); + const entity = new Entity(name, id); + + this._entities.set(id, entity); + this.updateNameIndex(entity, true); + this.updateTagIndex(entity, true); + + this._componentIndexManager.addEntity(entity); + this._archetypeSystem.addEntity(entity); + this._dirtyTrackingSystem.markDirty(entity, DirtyFlag.COMPONENT_ADDED); + + // 发射实体创建事件 + this._eventBus.emitEntityCreated({ + timestamp: Date.now(), + source: 'EntityManager', + entityId: entity.id, + entityName: entity.name, + entityTag: entity.tag?.toString() + }); + + return entity; + } + + /** + * 销毁实体 + * + * 支持通过实体对象、名称或ID来销毁实体。 + * 会清理所有相关索引并回收ID。 + * + * @param entityOrId 要销毁的实体,可以是实体对象、名称字符串或ID数字 + * @returns 是否成功销毁实体 + * + * @example + * ```typescript + * // 通过实体对象销毁 + * entityManager.destroyEntity(player); + * + * // 通过名称销毁 + * entityManager.destroyEntity("Enemy_1"); + * + * // 通过ID销毁 + * entityManager.destroyEntity(123); + * ``` + */ + public destroyEntity(entityOrId: Entity | string | number): boolean { + let entity: Entity | null = null; + + if (typeof entityOrId === 'string') { + entity = this.getEntityByName(entityOrId); + } else if (typeof entityOrId === 'number') { + entity = this._entities.get(entityOrId) || null; + } else { + entity = this._entities.get(entityOrId.id) || null; + } + + if (!entity) { + return false; + } + + this._destroyedEntities.add(entity.id); + this.updateNameIndex(entity, false); + this.updateTagIndex(entity, false); + + this._componentIndexManager.removeEntity(entity); + this._archetypeSystem.removeEntity(entity); + this._dirtyTrackingSystem.markDirty(entity, DirtyFlag.COMPONENT_REMOVED); + + // 发射实体销毁事件 + this._eventBus.emitEntityDestroyed({ + timestamp: Date.now(), + source: 'EntityManager', + entityId: entity.id, + entityName: entity.name, + entityTag: entity.tag?.toString() + }); + + entity.destroy(); + this._entities.delete(entity.id); + this._identifierPool.checkIn(entity.id); + + return true; + } + + /** + * 获取所有实体 + * + * 返回当前管理的所有实体的副本数组。 + * + * @returns 所有实体的数组 + */ + public getAllEntities(): Entity[] { + return Array.from(this._entities.values()); + } + + /** + * 根据ID获取实体 + * + * 支持字符串和数字类型的ID。 + * + * @param id 实体ID,可以是字符串或数字 + * @returns 对应的实体,如果不存在则返回null + */ + public getEntity(id: string | number): Entity | null { + const numId = typeof id === 'string' ? parseInt(id) : id; + return this._entities.get(numId) || null; + } + + /** + * 根据名称获取实体 + * + * 如果存在多个同名实体,返回第一个找到的实体。 + * + * @param name 实体名称 + * @returns 匹配的实体,如果不存在则返回null + */ + public getEntityByName(name: string): Entity | null { + const entities = this._entitiesByName.get(name); + return entities && entities.length > 0 ? entities[0] : null; + } + + /** + * 根据标签获取实体列表 + * + * 返回所有具有指定标签的实体。 + * + * @param tag 标签值 + * @returns 具有指定标签的实体数组 + */ + public getEntitiesByTag(tag: number): Entity[] { + return [...(this._entitiesByTag.get(tag) || [])]; + } + + /** + * 获取包含指定组件的所有实体 + * + * 遍历所有实体,查找包含指定组件类型的实体。 + * + * @param componentType 组件类型 + * @returns 包含指定组件的实体数组 + * + * @example + * ```typescript + * const entitiesWithHealth = entityManager.getEntitiesWithComponent(HealthComponent); + * ``` + */ + public getEntitiesWithComponent(componentType: ComponentType): Entity[] { + const indexResult = this._componentIndexManager.query(componentType); + return Array.from(indexResult); + } + + /** + * 创建查询构建器 + * + * 返回一个新的查询构建器实例,用于构建复杂的实体查询。 + * + * @returns 新的查询构建器实例 + * + * @example + * ```typescript + * const results = entityManager.query() + * .withAll(PositionComponent, HealthComponent) + * .without(VelocityComponent) + * .active() + * .execute(); + * ``` + */ + public query(): EntityQueryBuilder { + return new EntityQueryBuilder(this); + } + + /** + * 使用组件索引进行多组件查询 + * + * @param componentTypes 组件类型数组 + * @param operation 查询操作:'AND' 或 'OR' + * @returns 匹配的实体集合 + */ + public queryWithComponentIndex(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set { + return this._componentIndexManager.queryMultiple(componentTypes, operation); + } + + /** + * 标记实体组件已修改 + * + * @param entity 修改的实体 + * @param componentTypes 修改的组件类型 + */ + public markEntityDirty(entity: Entity, componentTypes: ComponentType[]): void { + this._dirtyTrackingSystem.markDirty(entity, DirtyFlag.COMPONENT_MODIFIED, componentTypes); + } + + /** + * 获取性能优化统计信息 + */ + public getOptimizationStats(): any { + return { + componentIndex: this._componentIndexManager.getStats(), + archetypeSystem: this._archetypeSystem.getAllArchetypes().map(a => ({ + id: a.id, + componentTypes: a.componentTypes.map(t => t.name), + entityCount: a.entities.length + })), + dirtyTracking: this._dirtyTrackingSystem.getStats() + }; + } + + /** + * 获取事件总线实例 + * + * 允许外部代码监听和发射ECS相关事件。 + * + * @returns 事件总线实例 + */ + public get eventBus(): EventBus { + return this._eventBus; + } + + /** + * 更新名称索引 + * + * 维护按名称查找实体的索引结构。支持添加和移除操作。 + * + * @param entity 要更新索引的实体 + * @param isAdd true表示添加到索引,false表示从索引中移除 + */ + private updateNameIndex(entity: Entity, isAdd: boolean): void { + if (!entity.name) { + return; + } + + if (isAdd) { + let entities = this._entitiesByName.get(entity.name); + if (!entities) { + entities = []; + this._entitiesByName.set(entity.name, entities); + } + entities.push(entity); + } else { + const entities = this._entitiesByName.get(entity.name); + if (entities) { + const index = entities.indexOf(entity); + if (index !== -1) { + entities.splice(index, 1); + if (entities.length === 0) { + this._entitiesByName.delete(entity.name); + } + } + } + } + } + + /** + * 更新标签索引 + * + * 维护按标签查找实体的索引结构。支持添加和移除操作。 + * + * @param entity 要更新索引的实体 + * @param isAdd true表示添加到索引,false表示从索引中移除 + */ + private updateTagIndex(entity: Entity, isAdd: boolean): void { + if (isAdd) { + let entities = this._entitiesByTag.get(entity.tag); + if (!entities) { + entities = []; + this._entitiesByTag.set(entity.tag, entities); + } + entities.push(entity); + } else { + const entities = this._entitiesByTag.get(entity.tag); + if (entities) { + const index = entities.indexOf(entity); + if (index !== -1) { + entities.splice(index, 1); + if (entities.length === 0) { + this._entitiesByTag.delete(entity.tag); + } + } + } + } + } +} diff --git a/source/src/ECS/Core/EventBus.ts b/source/src/ECS/Core/EventBus.ts new file mode 100644 index 00000000..b2426edf --- /dev/null +++ b/source/src/ECS/Core/EventBus.ts @@ -0,0 +1,497 @@ +import { + IEventBus, + IEventListenerConfig, + IEventStats, + IEventData, + IEntityEventData, + IComponentEventData, + ISystemEventData, + ISceneEventData, + IPerformanceEventData +} from '../../Types'; +import { + TypeSafeEventSystem, + EventListenerConfig, + EventStats +} from './EventSystem'; +import { + ECSEventType, + EventPriority, + EVENT_TYPES, + EventTypeValidator +} from '../CoreEvents'; + +/** + * 增强的事件总线实现 + * 基于TypeSafeEventSystem,提供类型安全的事件发布订阅机制 + */ +export class EventBus implements IEventBus { + private eventSystem: TypeSafeEventSystem; + private eventIdCounter = 0; + private isDebugMode = false; + + constructor(debugMode: boolean = false) { + this.eventSystem = new TypeSafeEventSystem(); + this.isDebugMode = debugMode; + } + + /** + * 发射事件 + * @param eventType 事件类型 + * @param data 事件数据 + */ + public emit(eventType: string, data: T): void { + this.validateEventType(eventType); + + // 增强事件数据 + const enhancedData = this.enhanceEventData(eventType, data); + + if (this.isDebugMode) { + console.log(`[EventBus] Emitting event: ${eventType}`, enhancedData); + } + + this.eventSystem.emitSync(eventType, enhancedData); + } + + /** + * 异步发射事件 + * @param eventType 事件类型 + * @param data 事件数据 + */ + public async emitAsync(eventType: string, data: T): Promise { + this.validateEventType(eventType); + + // 增强事件数据 + const enhancedData = this.enhanceEventData(eventType, data); + + if (this.isDebugMode) { + console.log(`[EventBus] Emitting async event: ${eventType}`, enhancedData); + } + + await this.eventSystem.emit(eventType, enhancedData); + } + + /** + * 监听事件 + * @param eventType 事件类型 + * @param handler 事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + public on( + eventType: string, + handler: (data: T) => void, + config: IEventListenerConfig = {} + ): string { + this.validateEventType(eventType); + + const eventConfig: EventListenerConfig = { + once: config.once || false, + priority: config.priority || EventPriority.NORMAL, + async: config.async || false, + context: config.context + }; + + if (this.isDebugMode) { + console.log(`[EventBus] Adding listener for: ${eventType}`, eventConfig); + } + + return this.eventSystem.on(eventType, handler, eventConfig); + } + + /** + * 监听事件(一次性) + * @param eventType 事件类型 + * @param handler 事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + public once( + eventType: string, + handler: (data: T) => void, + config: IEventListenerConfig = {} + ): string { + return this.on(eventType, handler, { ...config, once: true }); + } + + /** + * 异步监听事件 + * @param eventType 事件类型 + * @param handler 异步事件处理器 + * @param config 监听器配置 + * @returns 监听器ID + */ + public onAsync( + eventType: string, + handler: (data: T) => Promise, + config: IEventListenerConfig = {} + ): string { + return this.on(eventType, handler as any, { ...config, async: true }); + } + + /** + * 移除事件监听器 + * @param eventType 事件类型 + * @param listenerId 监听器ID + */ + public off(eventType: string, listenerId: string): boolean { + if (this.isDebugMode) { + console.log(`[EventBus] Removing listener: ${listenerId} for event: ${eventType}`); + } + + return this.eventSystem.off(eventType, listenerId); + } + + /** + * 移除指定事件类型的所有监听器 + * @param eventType 事件类型 + */ + public offAll(eventType: string): void { + if (this.isDebugMode) { + console.log(`[EventBus] Removing all listeners for event: ${eventType}`); + } + + this.eventSystem.offAll(eventType); + } + + /** + * 检查是否有指定事件的监听器 + * @param eventType 事件类型 + */ + public hasListeners(eventType: string): boolean { + return this.eventSystem.hasListeners(eventType); + } + + /** + * 获取事件统计信息 + * @param eventType 事件类型(可选) + */ + public getStats(eventType?: string): IEventStats | Map { + const stats = this.eventSystem.getStats(eventType); + + if (stats instanceof Map) { + // 转换Map中的每个EventStats为IEventStats + const result = new Map(); + stats.forEach((stat, key) => { + result.set(key, this.convertEventStats(stat)); + }); + return result; + } else { + return this.convertEventStats(stats); + } + } + + /** + * 清空所有监听器 + */ + public clear(): void { + if (this.isDebugMode) { + console.log('[EventBus] Clearing all listeners'); + } + + this.eventSystem.clear(); + } + + /** + * 启用或禁用事件系统 + * @param enabled 是否启用 + */ + public setEnabled(enabled: boolean): void { + this.eventSystem.setEnabled(enabled); + } + + /** + * 设置调试模式 + * @param debug 是否启用调试 + */ + public setDebugMode(debug: boolean): void { + this.isDebugMode = debug; + } + + /** + * 设置最大监听器数量 + * @param max 最大数量 + */ + public setMaxListeners(max: number): void { + this.eventSystem.setMaxListeners(max); + } + + /** + * 获取监听器数量 + * @param eventType 事件类型 + */ + public getListenerCount(eventType: string): number { + return this.eventSystem.getListenerCount(eventType); + } + + /** + * 设置事件批处理配置 + * @param eventType 事件类型 + * @param batchSize 批处理大小 + * @param delay 延迟时间(毫秒) + */ + public setBatchConfig(eventType: string, batchSize: number, delay: number): void { + this.eventSystem.setBatchConfig(eventType, { + batchSize, + delay, + enabled: true + }); + } + + /** + * 刷新指定事件的批处理队列 + * @param eventType 事件类型 + */ + public flushBatch(eventType: string): void { + this.eventSystem.flushBatch(eventType); + } + + /** + * 重置事件统计 + * @param eventType 事件类型(可选) + */ + public resetStats(eventType?: string): void { + this.eventSystem.resetStats(eventType); + } + + // 便捷方法:发射预定义的ECS事件 + + /** + * 发射实体创建事件 + * @param entityData 实体事件数据 + */ + public emitEntityCreated(entityData: IEntityEventData): void { + this.emit(ECSEventType.ENTITY_CREATED, entityData); + } + + /** + * 发射实体销毁事件 + * @param entityData 实体事件数据 + */ + public emitEntityDestroyed(entityData: IEntityEventData): void { + this.emit(ECSEventType.ENTITY_DESTROYED, entityData); + } + + /** + * 发射组件添加事件 + * @param componentData 组件事件数据 + */ + public emitComponentAdded(componentData: IComponentEventData): void { + this.emit(ECSEventType.COMPONENT_ADDED, componentData); + } + + /** + * 发射组件移除事件 + * @param componentData 组件事件数据 + */ + public emitComponentRemoved(componentData: IComponentEventData): void { + this.emit(ECSEventType.COMPONENT_REMOVED, componentData); + } + + /** + * 发射系统添加事件 + * @param systemData 系统事件数据 + */ + public emitSystemAdded(systemData: ISystemEventData): void { + this.emit(ECSEventType.SYSTEM_ADDED, systemData); + } + + /** + * 发射系统移除事件 + * @param systemData 系统事件数据 + */ + public emitSystemRemoved(systemData: ISystemEventData): void { + this.emit(ECSEventType.SYSTEM_REMOVED, systemData); + } + + /** + * 发射场景变化事件 + * @param sceneData 场景事件数据 + */ + public emitSceneChanged(sceneData: ISceneEventData): void { + this.emit(EVENT_TYPES.CORE.SCENE_CHANGED, sceneData); + } + + /** + * 发射性能警告事件 + * @param performanceData 性能事件数据 + */ + public emitPerformanceWarning(performanceData: IPerformanceEventData): void { + this.emit(ECSEventType.PERFORMANCE_WARNING, performanceData); + } + + // 便捷方法:监听预定义的ECS事件 + + /** + * 监听实体创建事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + public onEntityCreated( + handler: (data: IEntityEventData) => void, + config?: IEventListenerConfig + ): string { + return this.on(ECSEventType.ENTITY_CREATED, handler, config); + } + + /** + * 监听组件添加事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + public onComponentAdded( + handler: (data: IComponentEventData) => void, + config?: IEventListenerConfig + ): string { + return this.on(ECSEventType.COMPONENT_ADDED, handler, config); + } + + /** + * 监听系统错误事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + public onSystemError( + handler: (data: ISystemEventData) => void, + config?: IEventListenerConfig + ): string { + return this.on(ECSEventType.SYSTEM_ERROR, handler, config); + } + + /** + * 监听性能警告事件 + * @param handler 事件处理器 + * @param config 监听器配置 + */ + public onPerformanceWarning( + handler: (data: IPerformanceEventData) => void, + config?: IEventListenerConfig + ): string { + return this.on(ECSEventType.PERFORMANCE_WARNING, handler, config); + } + + // 私有方法 + + /** + * 验证事件类型 + * @param eventType 事件类型 + */ + private validateEventType(eventType: string): void { + if (!EventTypeValidator.isValid(eventType)) { + if (this.isDebugMode) { + console.warn(`[EventBus] Unknown event type: ${eventType}`); + } + // 在调试模式下添加自定义事件类型 + if (this.isDebugMode) { + EventTypeValidator.addCustomType(eventType); + } + } + } + + /** + * 增强事件数据 + * @param eventType 事件类型 + * @param data 原始数据 + */ + private enhanceEventData(eventType: string, data: T): T & IEventData { + const enhanced = data as T & IEventData; + + // 如果数据还没有基础事件属性,添加它们 + if (!enhanced.timestamp) { + enhanced.timestamp = Date.now(); + } + if (!enhanced.eventId) { + enhanced.eventId = `${eventType}_${++this.eventIdCounter}`; + } + if (!enhanced.source) { + enhanced.source = 'EventBus'; + } + + return enhanced; + } + + /** + * 转换EventStats为IEventStats + * @param stats EventStats实例 + */ + private convertEventStats(stats: EventStats): IEventStats { + return { + eventType: stats.eventType, + listenerCount: stats.listenerCount, + triggerCount: stats.triggerCount, + totalExecutionTime: stats.totalExecutionTime, + averageExecutionTime: stats.averageExecutionTime, + lastTriggerTime: stats.lastTriggerTime + }; + } +} + +/** + * 全局事件总线实例 + * 提供全局访问的事件总线 + */ +export class GlobalEventBus { + private static instance: EventBus; + + /** + * 获取全局事件总线实例 + * @param debugMode 是否启用调试模式 + */ + public static getInstance(debugMode: boolean = false): EventBus { + if (!this.instance) { + this.instance = new EventBus(debugMode); + } + return this.instance; + } + + /** + * 重置全局事件总线实例 + * @param debugMode 是否启用调试模式 + */ + public static reset(debugMode: boolean = false): EventBus { + if (this.instance) { + this.instance.clear(); + } + this.instance = new EventBus(debugMode); + return this.instance; + } +} + +/** + * 事件装饰器工厂 + * 用于自动注册事件监听器 + */ +export function EventHandler(eventType: string, config: IEventListenerConfig = {}) { + return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { + const originalMethod = descriptor.value; + + // 在类实例化时自动注册监听器 + const initMethod = target.constructor.prototype.initEventListeners || function() {}; + target.constructor.prototype.initEventListeners = function() { + initMethod.call(this); + const eventBus = GlobalEventBus.getInstance(); + eventBus.on(eventType, originalMethod.bind(this), config); + }; + + return descriptor; + }; +} + +/** + * 异步事件装饰器工厂 + * 用于自动注册异步事件监听器 + */ +export function AsyncEventHandler(eventType: string, config: IEventListenerConfig = {}) { + return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { + const originalMethod = descriptor.value; + + const initMethod = target.constructor.prototype.initEventListeners || function() {}; + target.constructor.prototype.initEventListeners = function() { + initMethod.call(this); + const eventBus = GlobalEventBus.getInstance(); + eventBus.onAsync(eventType, originalMethod.bind(this), config); + }; + + return descriptor; + }; +} \ No newline at end of file diff --git a/source/src/performance.ts b/source/src/performance.ts new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/source/src/performance.ts @@ -0,0 +1 @@ + \ No newline at end of file