refactor(core): 改进事件系统类型安全并消除 ESLint 警告 (#208)

This commit is contained in:
YHH
2025-11-01 16:12:18 +08:00
committed by GitHub
parent 57c7e7be3f
commit 3ad5dc9ca3
6 changed files with 310 additions and 159 deletions

View File

@@ -1,6 +1,6 @@
import { import {
IEventBus, IEventBus,
IEventListenerConfig, IEventListenerConfig,
IEventStats, IEventStats,
IEventData, IEventData,
IEntityEventData, IEntityEventData,
@@ -10,10 +10,10 @@ import {
IPerformanceEventData IPerformanceEventData
} from '../../Types'; } from '../../Types';
import { createLogger } from '../../Utils/Logger'; import { createLogger } from '../../Utils/Logger';
import { import {
TypeSafeEventSystem, TypeSafeEventSystem,
EventListenerConfig, EventListenerConfig,
EventStats EventStats
} from './EventSystem'; } from './EventSystem';
import { import {
ECSEventType, ECSEventType,
@@ -30,12 +30,12 @@ export class EventBus implements IEventBus {
private eventSystem: TypeSafeEventSystem; private eventSystem: TypeSafeEventSystem;
private eventIdCounter = 0; private eventIdCounter = 0;
private isDebugMode = false; private isDebugMode = false;
constructor(debugMode: boolean = false) { constructor(debugMode: boolean = false) {
this.eventSystem = new TypeSafeEventSystem(); this.eventSystem = new TypeSafeEventSystem();
this.isDebugMode = debugMode; this.isDebugMode = debugMode;
} }
/** /**
* 发射事件 * 发射事件
* @param eventType 事件类型 * @param eventType 事件类型
@@ -53,7 +53,7 @@ export class EventBus implements IEventBus {
this.eventSystem.emitSync(eventType, finalData); this.eventSystem.emitSync(eventType, finalData);
} }
/** /**
* 异步发射事件 * 异步发射事件
* @param eventType 事件类型 * @param eventType 事件类型
@@ -71,7 +71,7 @@ export class EventBus implements IEventBus {
await this.eventSystem.emit(eventType, finalData); await this.eventSystem.emit(eventType, finalData);
} }
/** /**
* 监听事件 * 监听事件
* @param eventType 事件类型 * @param eventType 事件类型
@@ -80,26 +80,29 @@ export class EventBus implements IEventBus {
* @returns 监听器ID * @returns 监听器ID
*/ */
public on<T>( public on<T>(
eventType: string, eventType: string,
handler: (data: T) => void, handler: (data: T) => void,
config: IEventListenerConfig = {} config: IEventListenerConfig = {}
): string { ): string {
this.validateEventType(eventType); this.validateEventType(eventType);
const eventConfig: EventListenerConfig = { const eventConfig: EventListenerConfig = {
once: config.once || false, once: config.once || false,
priority: config.priority || EventPriority.NORMAL, priority: config.priority || EventPriority.NORMAL,
async: config.async || false, async: config.async || false
context: config.context
}; };
if (config.thisArg) {
eventConfig.thisArg = config.thisArg as object;
}
if (this.isDebugMode) { if (this.isDebugMode) {
EventBus._logger.info(`添加监听器: ${eventType}`, eventConfig); EventBus._logger.info(`添加监听器: ${eventType}`, eventConfig);
} }
return this.eventSystem.on(eventType, handler, eventConfig); return this.eventSystem.on(eventType, handler, eventConfig);
} }
/** /**
* 监听事件(一次性) * 监听事件(一次性)
* @param eventType 事件类型 * @param eventType 事件类型
@@ -108,13 +111,13 @@ export class EventBus implements IEventBus {
* @returns 监听器ID * @returns 监听器ID
*/ */
public once<T>( public once<T>(
eventType: string, eventType: string,
handler: (data: T) => void, handler: (data: T) => void,
config: IEventListenerConfig = {} config: IEventListenerConfig = {}
): string { ): string {
return this.on(eventType, handler, { ...config, once: true }); return this.on(eventType, handler, { ...config, once: true });
} }
/** /**
* 异步监听事件 * 异步监听事件
* @param eventType 事件类型 * @param eventType 事件类型
@@ -123,13 +126,13 @@ export class EventBus implements IEventBus {
* @returns 监听器ID * @returns 监听器ID
*/ */
public onAsync<T>( public onAsync<T>(
eventType: string, eventType: string,
handler: (data: T) => Promise<void>, handler: (data: T) => Promise<void>,
config: IEventListenerConfig = {} config: IEventListenerConfig = {}
): string { ): string {
return this.on(eventType, handler as any, { ...config, async: true }); return this.on(eventType, handler, { ...config, async: true });
} }
/** /**
* 移除事件监听器 * 移除事件监听器
* @param eventType 事件类型 * @param eventType 事件类型
@@ -139,10 +142,10 @@ export class EventBus implements IEventBus {
if (this.isDebugMode) { if (this.isDebugMode) {
EventBus._logger.info(`移除监听器: ${listenerId} 事件: ${eventType}`); EventBus._logger.info(`移除监听器: ${listenerId} 事件: ${eventType}`);
} }
return this.eventSystem.off(eventType, listenerId); return this.eventSystem.off(eventType, listenerId);
} }
/** /**
* 移除指定事件类型的所有监听器 * 移除指定事件类型的所有监听器
* @param eventType 事件类型 * @param eventType 事件类型
@@ -151,10 +154,10 @@ export class EventBus implements IEventBus {
if (this.isDebugMode) { if (this.isDebugMode) {
EventBus._logger.info(`移除所有监听器: ${eventType}`); EventBus._logger.info(`移除所有监听器: ${eventType}`);
} }
this.eventSystem.offAll(eventType); this.eventSystem.offAll(eventType);
} }
/** /**
* 检查是否有指定事件的监听器 * 检查是否有指定事件的监听器
* @param eventType 事件类型 * @param eventType 事件类型
@@ -162,14 +165,14 @@ export class EventBus implements IEventBus {
public hasListeners(eventType: string): boolean { public hasListeners(eventType: string): boolean {
return this.eventSystem.hasListeners(eventType); return this.eventSystem.hasListeners(eventType);
} }
/** /**
* 获取事件统计信息 * 获取事件统计信息
* @param eventType 事件类型(可选) * @param eventType 事件类型(可选)
*/ */
public getStats(eventType?: string): IEventStats | Map<string, IEventStats> { public getStats(eventType?: string): IEventStats | Map<string, IEventStats> {
const stats = this.eventSystem.getStats(eventType); const stats = this.eventSystem.getStats(eventType);
if (stats instanceof Map) { if (stats instanceof Map) {
// 转换Map中的每个EventStats为IEventStats // 转换Map中的每个EventStats为IEventStats
const result = new Map<string, IEventStats>(); const result = new Map<string, IEventStats>();
@@ -181,7 +184,7 @@ export class EventBus implements IEventBus {
return this.convertEventStats(stats); return this.convertEventStats(stats);
} }
} }
/** /**
* 清空所有监听器 * 清空所有监听器
*/ */
@@ -189,10 +192,10 @@ export class EventBus implements IEventBus {
if (this.isDebugMode) { if (this.isDebugMode) {
EventBus._logger.info('清空所有监听器'); EventBus._logger.info('清空所有监听器');
} }
this.eventSystem.clear(); this.eventSystem.clear();
} }
/** /**
* 启用或禁用事件系统 * 启用或禁用事件系统
* @param enabled 是否启用 * @param enabled 是否启用
@@ -200,7 +203,7 @@ export class EventBus implements IEventBus {
public setEnabled(enabled: boolean): void { public setEnabled(enabled: boolean): void {
this.eventSystem.setEnabled(enabled); this.eventSystem.setEnabled(enabled);
} }
/** /**
* 设置调试模式 * 设置调试模式
* @param debug 是否启用调试 * @param debug 是否启用调试
@@ -208,7 +211,7 @@ export class EventBus implements IEventBus {
public setDebugMode(debug: boolean): void { public setDebugMode(debug: boolean): void {
this.isDebugMode = debug; this.isDebugMode = debug;
} }
/** /**
* 设置最大监听器数量 * 设置最大监听器数量
* @param max 最大数量 * @param max 最大数量
@@ -216,7 +219,7 @@ export class EventBus implements IEventBus {
public setMaxListeners(max: number): void { public setMaxListeners(max: number): void {
this.eventSystem.setMaxListeners(max); this.eventSystem.setMaxListeners(max);
} }
/** /**
* 获取监听器数量 * 获取监听器数量
* @param eventType 事件类型 * @param eventType 事件类型
@@ -224,7 +227,7 @@ export class EventBus implements IEventBus {
public getListenerCount(eventType: string): number { public getListenerCount(eventType: string): number {
return this.eventSystem.getListenerCount(eventType); return this.eventSystem.getListenerCount(eventType);
} }
/** /**
* 设置事件批处理配置 * 设置事件批处理配置
* @param eventType 事件类型 * @param eventType 事件类型
@@ -238,7 +241,7 @@ export class EventBus implements IEventBus {
enabled: true enabled: true
}); });
} }
/** /**
* 刷新指定事件的批处理队列 * 刷新指定事件的批处理队列
* @param eventType 事件类型 * @param eventType 事件类型
@@ -246,7 +249,7 @@ export class EventBus implements IEventBus {
public flushBatch(eventType: string): void { public flushBatch(eventType: string): void {
this.eventSystem.flushBatch(eventType); this.eventSystem.flushBatch(eventType);
} }
/** /**
* 重置事件统计 * 重置事件统计
* @param eventType 事件类型(可选) * @param eventType 事件类型(可选)
@@ -254,9 +257,9 @@ export class EventBus implements IEventBus {
public resetStats(eventType?: string): void { public resetStats(eventType?: string): void {
this.eventSystem.resetStats(eventType); this.eventSystem.resetStats(eventType);
} }
// 便捷方法发射预定义的ECS事件 // 便捷方法发射预定义的ECS事件
/** /**
* 发射实体创建事件 * 发射实体创建事件
* @param entityData 实体事件数据 * @param entityData 实体事件数据
@@ -320,59 +323,59 @@ export class EventBus implements IEventBus {
public emitPerformanceWarning(performanceData: IPerformanceEventData): void { public emitPerformanceWarning(performanceData: IPerformanceEventData): void {
this.emit(ECSEventType.PERFORMANCE_WARNING, performanceData); this.emit(ECSEventType.PERFORMANCE_WARNING, performanceData);
} }
// 便捷方法监听预定义的ECS事件 // 便捷方法监听预定义的ECS事件
/** /**
* 监听实体创建事件 * 监听实体创建事件
* @param handler 事件处理器 * @param handler 事件处理器
* @param config 监听器配置 * @param config 监听器配置
*/ */
public onEntityCreated( public onEntityCreated(
handler: (data: IEntityEventData) => void, handler: (data: IEntityEventData) => void,
config?: IEventListenerConfig config?: IEventListenerConfig
): string { ): string {
return this.on(ECSEventType.ENTITY_CREATED, handler, config); return this.on(ECSEventType.ENTITY_CREATED, handler, config);
} }
/** /**
* 监听组件添加事件 * 监听组件添加事件
* @param handler 事件处理器 * @param handler 事件处理器
* @param config 监听器配置 * @param config 监听器配置
*/ */
public onComponentAdded( public onComponentAdded(
handler: (data: IComponentEventData) => void, handler: (data: IComponentEventData) => void,
config?: IEventListenerConfig config?: IEventListenerConfig
): string { ): string {
return this.on(ECSEventType.COMPONENT_ADDED, handler, config); return this.on(ECSEventType.COMPONENT_ADDED, handler, config);
} }
/** /**
* 监听系统错误事件 * 监听系统错误事件
* @param handler 事件处理器 * @param handler 事件处理器
* @param config 监听器配置 * @param config 监听器配置
*/ */
public onSystemError( public onSystemError(
handler: (data: ISystemEventData) => void, handler: (data: ISystemEventData) => void,
config?: IEventListenerConfig config?: IEventListenerConfig
): string { ): string {
return this.on(ECSEventType.SYSTEM_ERROR, handler, config); return this.on(ECSEventType.SYSTEM_ERROR, handler, config);
} }
/** /**
* 监听性能警告事件 * 监听性能警告事件
* @param handler 事件处理器 * @param handler 事件处理器
* @param config 监听器配置 * @param config 监听器配置
*/ */
public onPerformanceWarning( public onPerformanceWarning(
handler: (data: IPerformanceEventData) => void, handler: (data: IPerformanceEventData) => void,
config?: IEventListenerConfig config?: IEventListenerConfig
): string { ): string {
return this.on(ECSEventType.PERFORMANCE_WARNING, handler, config); return this.on(ECSEventType.PERFORMANCE_WARNING, handler, config);
} }
// 私有方法 // 私有方法
/** /**
* 验证事件类型仅在debug模式下执行提升性能 * 验证事件类型仅在debug模式下执行提升性能
* @param eventType 事件类型 * @param eventType 事件类型
@@ -387,7 +390,7 @@ export class EventBus implements IEventBus {
} }
} }
} }
/** /**
* 增强事件数据 * 增强事件数据
* @param eventType 事件类型 * @param eventType 事件类型
@@ -402,9 +405,9 @@ export class EventBus implements IEventBus {
source: 'EventBus' source: 'EventBus'
} as T & IEventData; } as T & IEventData;
} }
const enhanced = data as T & IEventData; const enhanced = data as T & IEventData;
// 如果数据还没有基础事件属性,添加它们 // 如果数据还没有基础事件属性,添加它们
if (!enhanced.timestamp) { if (!enhanced.timestamp) {
enhanced.timestamp = Date.now(); enhanced.timestamp = Date.now();
@@ -415,10 +418,10 @@ export class EventBus implements IEventBus {
if (!enhanced.source) { if (!enhanced.source) {
enhanced.source = 'EventBus'; enhanced.source = 'EventBus';
} }
return enhanced; return enhanced;
} }
/** /**
* 转换EventStats为IEventStats * 转换EventStats为IEventStats
* @param stats EventStats实例 * @param stats EventStats实例
@@ -441,7 +444,7 @@ export class EventBus implements IEventBus {
*/ */
export class GlobalEventBus { export class GlobalEventBus {
private static instance: EventBus; private static instance: EventBus;
/** /**
* 获取全局事件总线实例 * 获取全局事件总线实例
* @param debugMode 是否启用调试模式 * @param debugMode 是否启用调试模式
@@ -452,7 +455,7 @@ export class GlobalEventBus {
} }
return this.instance; return this.instance;
} }
/** /**
* 重置全局事件总线实例 * 重置全局事件总线实例
* @param debugMode 是否启用调试模式 * @param debugMode 是否启用调试模式
@@ -466,4 +469,3 @@ export class GlobalEventBus {
} }
} }

View File

@@ -3,12 +3,12 @@ import { createLogger } from '../../Utils/Logger';
/** /**
* 事件处理器函数类型 * 事件处理器函数类型
*/ */
export type EventHandler<T = any> = (event: T) => void; export type EventHandler<T> = (event: T) => void;
/** /**
* 异步事件处理器函数类型 * 异步事件处理器函数类型
*/ */
export type AsyncEventHandler<T = any> = (event: T) => Promise<void>; export type AsyncEventHandler<T> = (event: T) => Promise<void>;
/** /**
* 事件监听器配置 * 事件监听器配置
@@ -20,15 +20,20 @@ export interface EventListenerConfig {
priority?: number; priority?: number;
/** 是否异步执行 */ /** 是否异步执行 */
async?: boolean; async?: boolean;
/** 执行上下文 */ /** 事件处理函数的 this 绑定对象 */
context?: any; thisArg?: object;
} }
/** /**
* 内部事件监听器 * 内部事件监听器
*
* 注意handler 使用 any 是必要的类型擦除
* 原因需要在同一数组中存储处理不同事件类型T的监听器
* 类型安全保证:公共 API (on<T>/emit<T>) 在编译时保证类型匹配
*/ */
interface InternalEventListener<T = any> { interface InternalEventListener {
handler: EventHandler<T> | AsyncEventHandler<T>; // eslint-disable-next-line @typescript-eslint/no-explicit-any
handler: EventHandler<any> | AsyncEventHandler<any>;
config: EventListenerConfig; config: EventListenerConfig;
id: string; id: string;
} }
@@ -71,8 +76,9 @@ export class TypeSafeEventSystem {
private static readonly _logger = createLogger('EventSystem'); private static readonly _logger = createLogger('EventSystem');
private listeners = new Map<string, InternalEventListener[]>(); private listeners = new Map<string, InternalEventListener[]>();
private stats = new Map<string, EventStats>(); private stats = new Map<string, EventStats>();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private batchQueue = new Map<string, any[]>(); private batchQueue = new Map<string, any[]>();
private batchTimers = new Map<string, number>(); private batchTimers = new Map<string, ReturnType<typeof setTimeout>>();
private batchConfigs = new Map<string, EventBatchConfig>(); private batchConfigs = new Map<string, EventBatchConfig>();
private nextListenerId = 0; private nextListenerId = 0;
private isEnabled = true; private isEnabled = true;
@@ -81,13 +87,13 @@ export class TypeSafeEventSystem {
/** /**
* 添加事件监听器 * 添加事件监听器
* @param eventType 事件类型 * @param eventType 事件类型
* @param handler 事件处理器 * @param handler 事件处理器(同步或异步,根据 config.async 决定)
* @param config 监听器配置 * @param config 监听器配置
* @returns 监听器ID用于移除 * @returns 监听器ID用于移除
*/ */
public on<T>( public on<T>(
eventType: string, eventType: string,
handler: EventHandler<T>, handler: EventHandler<T> | AsyncEventHandler<T>,
config: EventListenerConfig = {} config: EventListenerConfig = {}
): string { ): string {
return this.addListener(eventType, handler, config); return this.addListener(eventType, handler, config);
@@ -100,11 +106,7 @@ export class TypeSafeEventSystem {
* @param config 监听器配置 * @param config 监听器配置
* @returns 监听器ID * @returns 监听器ID
*/ */
public once<T>( public once<T>(eventType: string, handler: EventHandler<T>, config: EventListenerConfig = {}): string {
eventType: string,
handler: EventHandler<T>,
config: EventListenerConfig = {}
): string {
return this.addListener(eventType, handler, { ...config, once: true }); return this.addListener(eventType, handler, { ...config, once: true });
} }
@@ -115,11 +117,7 @@ export class TypeSafeEventSystem {
* @param config 监听器配置 * @param config 监听器配置
* @returns 监听器ID * @returns 监听器ID
*/ */
public onAsync<T>( public onAsync<T>(eventType: string, handler: AsyncEventHandler<T>, config: EventListenerConfig = {}): string {
eventType: string,
handler: AsyncEventHandler<T>,
config: EventListenerConfig = {}
): string {
return this.addListener(eventType, handler, { ...config, async: true }); return this.addListener(eventType, handler, { ...config, async: true });
} }
@@ -133,7 +131,7 @@ export class TypeSafeEventSystem {
const listeners = this.listeners.get(eventType); const listeners = this.listeners.get(eventType);
if (!listeners) return false; if (!listeners) return false;
const index = listeners.findIndex(l => l.id === listenerId); const index = listeners.findIndex((l) => l.id === listenerId);
if (index === -1) return false; if (index === -1) return false;
listeners.splice(index, 1); listeners.splice(index, 1);
@@ -197,8 +195,8 @@ export class TypeSafeEventSystem {
if (listener.config.async) continue; // 跳过异步监听器 if (listener.config.async) continue; // 跳过异步监听器
try { try {
if (listener.config.context) { if (listener.config.thisArg) {
(listener.handler as EventHandler<T>).call(listener.config.context, event); (listener.handler as EventHandler<T>).call(listener.config.thisArg, event);
} else { } else {
(listener.handler as EventHandler<T>)(event); (listener.handler as EventHandler<T>)(event);
} }
@@ -344,7 +342,7 @@ export class TypeSafeEventSystem {
} }
const listenerId = `listener_${this.nextListenerId++}`; const listenerId = `listener_${this.nextListenerId++}`;
const listener: InternalEventListener<T> = { const listener: InternalEventListener = {
handler, handler,
config: { config: {
priority: 0, priority: 0,
@@ -379,14 +377,14 @@ export class TypeSafeEventSystem {
const sortedListeners = this.sortListenersByPriority(listeners); const sortedListeners = this.sortListenersByPriority(listeners);
// 分离同步和异步监听器 // 分离同步和异步监听器
const syncListeners = sortedListeners.filter(l => !l.config.async); const syncListeners = sortedListeners.filter((l) => !l.config.async);
const asyncListeners = sortedListeners.filter(l => l.config.async); const asyncListeners = sortedListeners.filter((l) => l.config.async);
// 执行同步监听器 // 执行同步监听器
for (const listener of syncListeners) { for (const listener of syncListeners) {
try { try {
if (listener.config.context) { if (listener.config.thisArg) {
(listener.handler as EventHandler<T>).call(listener.config.context, event); (listener.handler as EventHandler<T>).call(listener.config.thisArg, event);
} else { } else {
(listener.handler as EventHandler<T>)(event); (listener.handler as EventHandler<T>)(event);
} }
@@ -402,8 +400,8 @@ export class TypeSafeEventSystem {
// 执行异步监听器 // 执行异步监听器
const asyncPromises = asyncListeners.map(async (listener) => { const asyncPromises = asyncListeners.map(async (listener) => {
try { try {
if (listener.config.context) { if (listener.config.thisArg) {
await (listener.handler as AsyncEventHandler<T>).call(listener.config.context, event); await (listener.handler as AsyncEventHandler<T>).call(listener.config.thisArg, event);
} else { } else {
await (listener.handler as AsyncEventHandler<T>)(event); await (listener.handler as AsyncEventHandler<T>)(event);
} }
@@ -431,7 +429,7 @@ export class TypeSafeEventSystem {
* @param listeners 监听器数组 * @param listeners 监听器数组
* @returns 排序后的监听器数组 * @returns 排序后的监听器数组
*/ */
private sortListenersByPriority<T>(listeners: InternalEventListener<T>[]): InternalEventListener<T>[] { private sortListenersByPriority(listeners: InternalEventListener[]): InternalEventListener[] {
return listeners.slice().sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0)); return listeners.slice().sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0));
} }
@@ -447,7 +445,7 @@ export class TypeSafeEventSystem {
if (!listeners) return; if (!listeners) return;
for (const id of listenerIds) { for (const id of listenerIds) {
const index = listeners.findIndex(l => l.id === id); const index = listeners.findIndex((l) => l.id === id);
if (index !== -1) { if (index !== -1) {
listeners.splice(index, 1); listeners.splice(index, 1);
} }
@@ -488,7 +486,7 @@ export class TypeSafeEventSystem {
this.flushBatch(eventType); this.flushBatch(eventType);
}, config.delay); }, config.delay);
this.batchTimers.set(eventType, timer as any); this.batchTimers.set(eventType, timer);
} }
} }
@@ -577,5 +575,3 @@ export class TypeSafeEventSystem {
* 全局事件系统实例 * 全局事件系统实例
*/ */
export const GlobalEventSystem = new TypeSafeEventSystem(); export const GlobalEventSystem = new TypeSafeEventSystem();

View File

@@ -0,0 +1,166 @@
import { Entity } from '../Entity';
/**
* 实体缓存管理器
*
* 负责管理 EntitySystem 中的实体缓存,提供帧缓存和持久缓存两级缓存机制。
* 使用面向对象设计,将数据和行为封装在类中。
*
* @example
* ```typescript
* const cache = new EntityCache();
* cache.setPersistent(entities);
* const cached = cache.getPersistent();
* cache.invalidate();
* ```
*/
export class EntityCache {
/**
* 帧缓存
*
* 在update周期内使用每帧结束后清理
*/
private _frameCache: readonly Entity[] | null = null;
/**
* 持久缓存
*
* 跨帧使用,直到被显式失效
*/
private _persistentCache: readonly Entity[] | null = null;
/**
* 被跟踪的实体集合
*
* 用于跟踪哪些实体正在被此系统处理
*/
private _trackedEntities: Set<Entity> = new Set();
/**
* 获取帧缓存
*/
public getFrame(): readonly Entity[] | null {
return this._frameCache;
}
/**
* 设置帧缓存
*
* @param entities 要缓存的实体列表
*/
public setFrame(entities: readonly Entity[]): void {
this._frameCache = entities;
}
/**
* 获取持久缓存
*/
public getPersistent(): readonly Entity[] | null {
return this._persistentCache;
}
/**
* 设置持久缓存
*
* @param entities 要缓存的实体列表
*/
public setPersistent(entities: readonly Entity[]): void {
this._persistentCache = entities;
}
/**
* 获取被跟踪的实体集合
*/
public getTracked(): ReadonlySet<Entity> {
return this._trackedEntities;
}
/**
* 添加被跟踪的实体
*
* @param entity 要跟踪的实体
*/
public addTracked(entity: Entity): void {
this._trackedEntities.add(entity);
}
/**
* 移除被跟踪的实体
*
* @param entity 要移除的实体
*/
public removeTracked(entity: Entity): void {
this._trackedEntities.delete(entity);
}
/**
* 检查实体是否被跟踪
*
* @param entity 要检查的实体
*/
public isTracked(entity: Entity): boolean {
return this._trackedEntities.has(entity);
}
/**
* 使持久缓存失效
*
* 当实体变化时调用,强制下次查询时重新计算
*/
public invalidate(): void {
this._persistentCache = null;
}
/**
* 清除帧缓存
*
* 在每帧结束时调用
*/
public clearFrame(): void {
this._frameCache = null;
}
/**
* 清除所有缓存
*
* 在系统重置或销毁时调用
*/
public clearAll(): void {
this._frameCache = null;
this._persistentCache = null;
this._trackedEntities.clear();
}
/**
* 检查是否有有效的持久缓存
*/
public hasPersistent(): boolean {
return this._persistentCache !== null;
}
/**
* 检查是否有有效的帧缓存
*/
public hasFrame(): boolean {
return this._frameCache !== null;
}
/**
* 获取缓存统计信息
*/
public getStats(): {
hasFrame: boolean;
hasPersistent: boolean;
trackedCount: number;
frameEntityCount: number;
persistentEntityCount: number;
} {
return {
hasFrame: this._frameCache !== null,
hasPersistent: this._persistentCache !== null,
trackedCount: this._trackedEntities.size,
frameEntityCount: this._frameCache?.length ?? 0,
persistentEntityCount: this._persistentCache?.length ?? 0
};
}
}

View File

@@ -9,14 +9,15 @@ import { createLogger } from '../../Utils/Logger';
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem'; import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers'; import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
import type { IService } from '../../Core/ServiceContainer'; import type { IService } from '../../Core/ServiceContainer';
import { EntityCache } from './EntityCache';
/** /**
* 事件监听器记录 * 事件监听器记录
* 只存储引用信息,用于系统销毁时自动清理
*/ */
interface EventListenerRecord { interface EventListenerRecord {
eventSystem: TypeSafeEventSystem; eventSystem: TypeSafeEventSystem;
eventType: string; eventType: string;
handler: EventHandler;
listenerRef: string; listenerRef: string;
} }
@@ -63,9 +64,7 @@ interface EventListenerRecord {
* } * }
* ``` * ```
*/ */
export abstract class EntitySystem<_TComponents extends readonly ComponentConstructor[] = []> export abstract class EntitySystem implements ISystemBase, IService {
implements ISystemBase, IService
{
private _updateOrder: number; private _updateOrder: number;
private _enabled: boolean; private _enabled: boolean;
private _performanceMonitor: PerformanceMonitor | null; private _performanceMonitor: PerformanceMonitor | null;
@@ -85,30 +84,24 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
/** /**
* 统一的实体缓存管理器 * 统一的实体缓存管理器
*/ */
private _entityCache: { private _entityCache: EntityCache;
frame: readonly Entity[] | null;
persistent: readonly Entity[] | null;
tracked: Set<Entity>;
invalidate(): void;
clearFrame(): void;
clearAll(): void;
};
/** /**
* 获取系统处理的实体列表 * 获取系统处理的实体列表
*/ */
public get entities(): readonly Entity[] { public get entities(): readonly Entity[] {
// 如果在update周期内优先使用帧缓存 // 如果在update周期内优先使用帧缓存
if (this._entityCache.frame !== null) { const frameCache = this._entityCache.getFrame();
return this._entityCache.frame; if (frameCache !== null) {
return frameCache;
} }
// 否则使用持久缓存 // 否则使用持久缓存
if (this._entityCache.persistent === null) { if (!this._entityCache.hasPersistent()) {
this._entityCache.persistent = this.queryEntities(); this._entityCache.setPersistent(this.queryEntities());
} }
return this._entityCache.persistent; return this._entityCache.getPersistent()!;
} }
/** /**
@@ -159,22 +152,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
// 初始化logger // 初始化logger
this.logger = createLogger(this.getLoggerName()); this.logger = createLogger(this.getLoggerName());
this._entityCache = { this._entityCache = new EntityCache();
frame: null,
persistent: null,
tracked: new Set<Entity>(),
invalidate() {
this.persistent = null;
},
clearFrame() {
this.frame = null;
},
clearAll() {
this.frame = null;
this.persistent = null;
this.tracked.clear();
}
};
} }
/** /**
@@ -521,7 +499,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
const entityMap = this.getEntityIdMap(allEntities); const entityMap = this.getEntityIdMap(allEntities);
const size = idSet.size; const size = idSet.size;
const result = new Array(size); const result = new Array<Entity>(size);
let index = 0; let index = 0;
for (const id of idSet) { for (const id of idSet) {
@@ -564,10 +542,11 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
this.onBegin(); this.onBegin();
// 查询实体并存储到帧缓存中 // 查询实体并存储到帧缓存中
// 响应式查询会自动维护最新的实体列表updateEntityTracking会在检测到变化时invalidate // 响应式查询会自动维护最新的实体列表updateEntityTracking会在检测到变化时invalidate
this._entityCache.frame = this.queryEntities(); const queriedEntities = this.queryEntities();
entityCount = this._entityCache.frame.length; this._entityCache.setFrame(queriedEntities);
entityCount = queriedEntities.length;
this.process(this._entityCache.frame); this.process(queriedEntities);
} finally { } finally {
monitor.endMonitoring(this._systemName, startTime, entityCount); monitor.endMonitoring(this._systemName, startTime, entityCount);
} }
@@ -587,7 +566,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
try { try {
// 使用缓存的实体列表,避免重复查询 // 使用缓存的实体列表,避免重复查询
const entities = this._entityCache.frame || []; const entities = this._entityCache.getFrame() || [];
entityCount = entities.length; entityCount = entities.length;
this.lateProcess(entities); this.lateProcess(entities);
this.onEnd(); this.onEnd();
@@ -697,17 +676,17 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
// 检查新增的实体 // 检查新增的实体
for (const entity of currentEntities) { for (const entity of currentEntities) {
if (!this._entityCache.tracked.has(entity)) { if (!this._entityCache.isTracked(entity)) {
this._entityCache.tracked.add(entity); this._entityCache.addTracked(entity);
this.onAdded(entity); this.onAdded(entity);
hasChanged = true; hasChanged = true;
} }
} }
// 检查移除的实体 // 检查移除的实体
for (const entity of this._entityCache.tracked) { for (const entity of this._entityCache.getTracked()) {
if (!currentSet.has(entity)) { if (!currentSet.has(entity)) {
this._entityCache.tracked.delete(entity); this._entityCache.removeTracked(entity);
this.onRemoved(entity); this.onRemoved(entity);
hasChanged = true; hasChanged = true;
} }
@@ -778,15 +757,16 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
* @param eventType 事件类型 * @param eventType 事件类型
* @param handler 事件处理函数 * @param handler 事件处理函数
* @param config 监听器配置 * @param config 监听器配置
* @returns 监听器引用ID可用于手动移除监听器
*/ */
protected addEventListener<T = any>( protected addEventListener<T>(
eventType: string, eventType: string,
handler: EventHandler<T>, handler: EventHandler<T>,
config?: EventListenerConfig config?: EventListenerConfig
): void { ): string | null {
if (!this.scene?.eventSystem) { if (!this.scene?.eventSystem) {
this.logger.warn(`${this.systemName}: 无法添加事件监听器scene.eventSystem 不可用`); this.logger.warn(`${this.systemName}: 无法添加事件监听器scene.eventSystem 不可用`);
return; return null;
} }
const listenerRef = this.scene.eventSystem.on(eventType, handler, config); const listenerRef = this.scene.eventSystem.on(eventType, handler, config);
@@ -796,21 +776,22 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
this._eventListeners.push({ this._eventListeners.push({
eventSystem: this.scene.eventSystem, eventSystem: this.scene.eventSystem,
eventType, eventType,
handler,
listenerRef listenerRef
}); });
} }
return listenerRef;
} }
/** /**
* 移除特定的事件监听器 * 移除特定的事件监听器
* *
* @param eventType 事件类型 * @param eventType 事件类型
* @param handler 事件处理函数 * @param listenerRef 监听器引用ID由 addEventListener 返回)
*/ */
protected removeEventListener<T = any>(eventType: string, handler: EventHandler<T>): void { protected removeEventListener(eventType: string, listenerRef: string): void {
const listenerIndex = this._eventListeners.findIndex( const listenerIndex = this._eventListeners.findIndex(
(listener) => listener.eventType === eventType && listener.handler === handler (listener) => listener.eventType === eventType && listener.listenerRef === listenerRef
); );
if (listenerIndex >= 0) { if (listenerIndex >= 0) {
@@ -895,7 +876,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
* ``` * ```
*/ */
protected requireComponent<T extends ComponentConstructor>(entity: Entity, componentType: T): ComponentInstance<T> { protected requireComponent<T extends ComponentConstructor>(entity: Entity, componentType: T): ComponentInstance<T> {
const component = entity.getComponent(componentType as any); const component = entity.getComponent(componentType);
if (!component) { if (!component) {
throw new Error(`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`); throw new Error(`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`);
} }
@@ -929,7 +910,9 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
entity: Entity, entity: Entity,
...components: T ...components: T
): { [K in keyof T]: ComponentInstance<T[K]> } { ): { [K in keyof T]: ComponentInstance<T[K]> } {
return components.map((type) => this.requireComponent(entity, type)) as any; return components.map((type) => this.requireComponent(entity, type)) as {
[K in keyof T]: ComponentInstance<T[K]>;
};
} }
/** /**

View File

@@ -142,8 +142,8 @@ export interface IEventListenerConfig {
priority?: number; priority?: number;
/** 是否异步执行 */ /** 是否异步执行 */
async?: boolean; async?: boolean;
/** 执行上下文 */ /** 事件处理函数的 this 绑定对象 */
context?: unknown; thisArg?: object;
} }
/** /**

View File

@@ -50,17 +50,19 @@ class ConcreteEntitySystem extends EntitySystem {
const handler = (event: any) => { const handler = (event: any) => {
this.eventHandlerCallCount++; this.eventHandlerCallCount++;
}; };
this.addEventListener('manual_event', handler); const listenerRef = this.addEventListener('manual_event', handler);
this.removeEventListener('manual_event', handler); if (listenerRef) {
this.removeEventListener('manual_event', listenerRef);
}
} }
// 公开测试方法 // 公开测试方法
public testAddEventListener(eventType: string, handler: (event: any) => void): void { public testAddEventListener(eventType: string, handler: (event: any) => void): string | null {
this.addEventListener(eventType, handler); return this.addEventListener(eventType, handler);
} }
public testRemoveEventListener(eventType: string, handler: (event: any) => void): void { public testRemoveEventListener(eventType: string, listenerRef: string): void {
this.removeEventListener(eventType, handler); this.removeEventListener(eventType, listenerRef);
} }
} }
@@ -118,14 +120,16 @@ describe('EntitySystem', () => {
const handler = jest.fn(); const handler = jest.fn();
// 添加监听器 // 添加监听器
system.testAddEventListener('manual_remove_event', handler); const listenerRef = system.testAddEventListener('manual_remove_event', handler);
// 发射事件验证监听器工作 // 发射事件验证监听器工作
scene.eventSystem.emitSync('manual_remove_event', {}); scene.eventSystem.emitSync('manual_remove_event', {});
expect(handler).toHaveBeenCalledTimes(1); expect(handler).toHaveBeenCalledTimes(1);
// 移除监听器 // 移除监听器
system.testRemoveEventListener('manual_remove_event', handler); if (listenerRef) {
system.testRemoveEventListener('manual_remove_event', listenerRef);
}
// 再次发射事件 // 再次发射事件
scene.eventSystem.emitSync('manual_remove_event', {}); scene.eventSystem.emitSync('manual_remove_event', {});
@@ -205,11 +209,11 @@ describe('EntitySystem', () => {
}); });
it('当移除不存在的监听器时,应该安全处理', () => { it('当移除不存在的监听器时,应该安全处理', () => {
const nonExistentHandler = () => {}; const nonExistentListenerRef = 'non_existent_listener_ref';
// 应该不会抛出错误 // 应该不会抛出错误
expect(() => { expect(() => {
system.testRemoveEventListener('non_existent_event', nonExistentHandler); system.testRemoveEventListener('non_existent_event', nonExistentListenerRef);
}).not.toThrow(); }).not.toThrow();
}); });
}); });