refactor(core): 改进事件系统类型安全并消除 ESLint 警告 (#208)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
IEventBus,
|
||||
IEventListenerConfig,
|
||||
import {
|
||||
IEventBus,
|
||||
IEventListenerConfig,
|
||||
IEventStats,
|
||||
IEventData,
|
||||
IEntityEventData,
|
||||
@@ -10,10 +10,10 @@ import {
|
||||
IPerformanceEventData
|
||||
} from '../../Types';
|
||||
import { createLogger } from '../../Utils/Logger';
|
||||
import {
|
||||
TypeSafeEventSystem,
|
||||
EventListenerConfig,
|
||||
EventStats
|
||||
import {
|
||||
TypeSafeEventSystem,
|
||||
EventListenerConfig,
|
||||
EventStats
|
||||
} from './EventSystem';
|
||||
import {
|
||||
ECSEventType,
|
||||
@@ -30,12 +30,12 @@ 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 事件类型
|
||||
@@ -53,7 +53,7 @@ export class EventBus implements IEventBus {
|
||||
|
||||
this.eventSystem.emitSync(eventType, finalData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 异步发射事件
|
||||
* @param eventType 事件类型
|
||||
@@ -71,7 +71,7 @@ export class EventBus implements IEventBus {
|
||||
|
||||
await this.eventSystem.emit(eventType, finalData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 监听事件
|
||||
* @param eventType 事件类型
|
||||
@@ -80,26 +80,29 @@ export class EventBus implements IEventBus {
|
||||
* @returns 监听器ID
|
||||
*/
|
||||
public on<T>(
|
||||
eventType: string,
|
||||
handler: (data: T) => void,
|
||||
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
|
||||
async: config.async || false
|
||||
};
|
||||
|
||||
|
||||
if (config.thisArg) {
|
||||
eventConfig.thisArg = config.thisArg as object;
|
||||
}
|
||||
|
||||
if (this.isDebugMode) {
|
||||
EventBus._logger.info(`添加监听器: ${eventType}`, eventConfig);
|
||||
}
|
||||
|
||||
|
||||
return this.eventSystem.on(eventType, handler, eventConfig);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 监听事件(一次性)
|
||||
* @param eventType 事件类型
|
||||
@@ -108,13 +111,13 @@ export class EventBus implements IEventBus {
|
||||
* @returns 监听器ID
|
||||
*/
|
||||
public once<T>(
|
||||
eventType: string,
|
||||
handler: (data: T) => void,
|
||||
eventType: string,
|
||||
handler: (data: T) => void,
|
||||
config: IEventListenerConfig = {}
|
||||
): string {
|
||||
return this.on(eventType, handler, { ...config, once: true });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 异步监听事件
|
||||
* @param eventType 事件类型
|
||||
@@ -123,13 +126,13 @@ export class EventBus implements IEventBus {
|
||||
* @returns 监听器ID
|
||||
*/
|
||||
public onAsync<T>(
|
||||
eventType: string,
|
||||
handler: (data: T) => Promise<void>,
|
||||
eventType: string,
|
||||
handler: (data: T) => Promise<void>,
|
||||
config: IEventListenerConfig = {}
|
||||
): string {
|
||||
return this.on(eventType, handler as any, { ...config, async: true });
|
||||
return this.on(eventType, handler, { ...config, async: true });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 移除事件监听器
|
||||
* @param eventType 事件类型
|
||||
@@ -139,10 +142,10 @@ export class EventBus implements IEventBus {
|
||||
if (this.isDebugMode) {
|
||||
EventBus._logger.info(`移除监听器: ${listenerId} 事件: ${eventType}`);
|
||||
}
|
||||
|
||||
|
||||
return this.eventSystem.off(eventType, listenerId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 移除指定事件类型的所有监听器
|
||||
* @param eventType 事件类型
|
||||
@@ -151,10 +154,10 @@ export class EventBus implements IEventBus {
|
||||
if (this.isDebugMode) {
|
||||
EventBus._logger.info(`移除所有监听器: ${eventType}`);
|
||||
}
|
||||
|
||||
|
||||
this.eventSystem.offAll(eventType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查是否有指定事件的监听器
|
||||
* @param eventType 事件类型
|
||||
@@ -162,14 +165,14 @@ export class EventBus implements IEventBus {
|
||||
public hasListeners(eventType: string): boolean {
|
||||
return this.eventSystem.hasListeners(eventType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取事件统计信息
|
||||
* @param eventType 事件类型(可选)
|
||||
*/
|
||||
public getStats(eventType?: string): IEventStats | Map<string, IEventStats> {
|
||||
const stats = this.eventSystem.getStats(eventType);
|
||||
|
||||
|
||||
if (stats instanceof Map) {
|
||||
// 转换Map中的每个EventStats为IEventStats
|
||||
const result = new Map<string, IEventStats>();
|
||||
@@ -181,7 +184,7 @@ export class EventBus implements IEventBus {
|
||||
return this.convertEventStats(stats);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 清空所有监听器
|
||||
*/
|
||||
@@ -189,10 +192,10 @@ export class EventBus implements IEventBus {
|
||||
if (this.isDebugMode) {
|
||||
EventBus._logger.info('清空所有监听器');
|
||||
}
|
||||
|
||||
|
||||
this.eventSystem.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 启用或禁用事件系统
|
||||
* @param enabled 是否启用
|
||||
@@ -200,7 +203,7 @@ export class EventBus implements IEventBus {
|
||||
public setEnabled(enabled: boolean): void {
|
||||
this.eventSystem.setEnabled(enabled);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置调试模式
|
||||
* @param debug 是否启用调试
|
||||
@@ -208,7 +211,7 @@ export class EventBus implements IEventBus {
|
||||
public setDebugMode(debug: boolean): void {
|
||||
this.isDebugMode = debug;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置最大监听器数量
|
||||
* @param max 最大数量
|
||||
@@ -216,7 +219,7 @@ export class EventBus implements IEventBus {
|
||||
public setMaxListeners(max: number): void {
|
||||
this.eventSystem.setMaxListeners(max);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取监听器数量
|
||||
* @param eventType 事件类型
|
||||
@@ -224,7 +227,7 @@ export class EventBus implements IEventBus {
|
||||
public getListenerCount(eventType: string): number {
|
||||
return this.eventSystem.getListenerCount(eventType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置事件批处理配置
|
||||
* @param eventType 事件类型
|
||||
@@ -238,7 +241,7 @@ export class EventBus implements IEventBus {
|
||||
enabled: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 刷新指定事件的批处理队列
|
||||
* @param eventType 事件类型
|
||||
@@ -246,7 +249,7 @@ export class EventBus implements IEventBus {
|
||||
public flushBatch(eventType: string): void {
|
||||
this.eventSystem.flushBatch(eventType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重置事件统计
|
||||
* @param eventType 事件类型(可选)
|
||||
@@ -254,9 +257,9 @@ export class EventBus implements IEventBus {
|
||||
public resetStats(eventType?: string): void {
|
||||
this.eventSystem.resetStats(eventType);
|
||||
}
|
||||
|
||||
|
||||
// 便捷方法:发射预定义的ECS事件
|
||||
|
||||
|
||||
/**
|
||||
* 发射实体创建事件
|
||||
* @param entityData 实体事件数据
|
||||
@@ -320,59 +323,59 @@ export class EventBus implements IEventBus {
|
||||
public emitPerformanceWarning(performanceData: IPerformanceEventData): void {
|
||||
this.emit(ECSEventType.PERFORMANCE_WARNING, performanceData);
|
||||
}
|
||||
|
||||
|
||||
// 便捷方法:监听预定义的ECS事件
|
||||
|
||||
|
||||
/**
|
||||
* 监听实体创建事件
|
||||
* @param handler 事件处理器
|
||||
* @param config 监听器配置
|
||||
*/
|
||||
public onEntityCreated(
|
||||
handler: (data: IEntityEventData) => void,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
handler: (data: IPerformanceEventData) => void,
|
||||
config?: IEventListenerConfig
|
||||
): string {
|
||||
return this.on(ECSEventType.PERFORMANCE_WARNING, handler, config);
|
||||
}
|
||||
|
||||
|
||||
// 私有方法
|
||||
|
||||
|
||||
/**
|
||||
* 验证事件类型(仅在debug模式下执行,提升性能)
|
||||
* @param eventType 事件类型
|
||||
@@ -387,7 +390,7 @@ export class EventBus implements IEventBus {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 增强事件数据
|
||||
* @param eventType 事件类型
|
||||
@@ -402,9 +405,9 @@ export class EventBus implements IEventBus {
|
||||
source: 'EventBus'
|
||||
} as T & IEventData;
|
||||
}
|
||||
|
||||
|
||||
const enhanced = data as T & IEventData;
|
||||
|
||||
|
||||
// 如果数据还没有基础事件属性,添加它们
|
||||
if (!enhanced.timestamp) {
|
||||
enhanced.timestamp = Date.now();
|
||||
@@ -415,10 +418,10 @@ export class EventBus implements IEventBus {
|
||||
if (!enhanced.source) {
|
||||
enhanced.source = 'EventBus';
|
||||
}
|
||||
|
||||
|
||||
return enhanced;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转换EventStats为IEventStats
|
||||
* @param stats EventStats实例
|
||||
@@ -441,7 +444,7 @@ export class EventBus implements IEventBus {
|
||||
*/
|
||||
export class GlobalEventBus {
|
||||
private static instance: EventBus;
|
||||
|
||||
|
||||
/**
|
||||
* 获取全局事件总线实例
|
||||
* @param debugMode 是否启用调试模式
|
||||
@@ -452,7 +455,7 @@ export class GlobalEventBus {
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重置全局事件总线实例
|
||||
* @param debugMode 是否启用调试模式
|
||||
@@ -466,4 +469,3 @@ export class GlobalEventBus {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
/** 是否异步执行 */
|
||||
async?: boolean;
|
||||
/** 执行上下文 */
|
||||
context?: any;
|
||||
/** 事件处理函数的 this 绑定对象 */
|
||||
thisArg?: object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部事件监听器
|
||||
*
|
||||
* 注意:handler 使用 any 是必要的类型擦除
|
||||
* 原因:需要在同一数组中存储处理不同事件类型(T)的监听器
|
||||
* 类型安全保证:公共 API (on<T>/emit<T>) 在编译时保证类型匹配
|
||||
*/
|
||||
interface InternalEventListener<T = any> {
|
||||
handler: EventHandler<T> | AsyncEventHandler<T>;
|
||||
interface InternalEventListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
handler: EventHandler<any> | AsyncEventHandler<any>;
|
||||
config: EventListenerConfig;
|
||||
id: string;
|
||||
}
|
||||
@@ -71,8 +76,9 @@ export class TypeSafeEventSystem {
|
||||
private static readonly _logger = createLogger('EventSystem');
|
||||
private listeners = new Map<string, InternalEventListener[]>();
|
||||
private stats = new Map<string, EventStats>();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-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 nextListenerId = 0;
|
||||
private isEnabled = true;
|
||||
@@ -81,13 +87,13 @@ export class TypeSafeEventSystem {
|
||||
/**
|
||||
* 添加事件监听器
|
||||
* @param eventType 事件类型
|
||||
* @param handler 事件处理器
|
||||
* @param handler 事件处理器(同步或异步,根据 config.async 决定)
|
||||
* @param config 监听器配置
|
||||
* @returns 监听器ID(用于移除)
|
||||
*/
|
||||
public on<T>(
|
||||
eventType: string,
|
||||
handler: EventHandler<T>,
|
||||
handler: EventHandler<T> | AsyncEventHandler<T>,
|
||||
config: EventListenerConfig = {}
|
||||
): string {
|
||||
return this.addListener(eventType, handler, config);
|
||||
@@ -100,11 +106,7 @@ export class TypeSafeEventSystem {
|
||||
* @param config 监听器配置
|
||||
* @returns 监听器ID
|
||||
*/
|
||||
public once<T>(
|
||||
eventType: string,
|
||||
handler: EventHandler<T>,
|
||||
config: EventListenerConfig = {}
|
||||
): string {
|
||||
public once<T>(eventType: string, handler: EventHandler<T>, config: EventListenerConfig = {}): string {
|
||||
return this.addListener(eventType, handler, { ...config, once: true });
|
||||
}
|
||||
|
||||
@@ -115,11 +117,7 @@ export class TypeSafeEventSystem {
|
||||
* @param config 监听器配置
|
||||
* @returns 监听器ID
|
||||
*/
|
||||
public onAsync<T>(
|
||||
eventType: string,
|
||||
handler: AsyncEventHandler<T>,
|
||||
config: EventListenerConfig = {}
|
||||
): string {
|
||||
public onAsync<T>(eventType: string, handler: AsyncEventHandler<T>, config: EventListenerConfig = {}): string {
|
||||
return this.addListener(eventType, handler, { ...config, async: true });
|
||||
}
|
||||
|
||||
@@ -133,7 +131,7 @@ export class TypeSafeEventSystem {
|
||||
const listeners = this.listeners.get(eventType);
|
||||
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;
|
||||
|
||||
listeners.splice(index, 1);
|
||||
@@ -197,8 +195,8 @@ export class TypeSafeEventSystem {
|
||||
if (listener.config.async) continue; // 跳过异步监听器
|
||||
|
||||
try {
|
||||
if (listener.config.context) {
|
||||
(listener.handler as EventHandler<T>).call(listener.config.context, event);
|
||||
if (listener.config.thisArg) {
|
||||
(listener.handler as EventHandler<T>).call(listener.config.thisArg, event);
|
||||
} else {
|
||||
(listener.handler as EventHandler<T>)(event);
|
||||
}
|
||||
@@ -344,7 +342,7 @@ export class TypeSafeEventSystem {
|
||||
}
|
||||
|
||||
const listenerId = `listener_${this.nextListenerId++}`;
|
||||
const listener: InternalEventListener<T> = {
|
||||
const listener: InternalEventListener = {
|
||||
handler,
|
||||
config: {
|
||||
priority: 0,
|
||||
@@ -379,14 +377,14 @@ export class TypeSafeEventSystem {
|
||||
const sortedListeners = this.sortListenersByPriority(listeners);
|
||||
|
||||
// 分离同步和异步监听器
|
||||
const syncListeners = sortedListeners.filter(l => !l.config.async);
|
||||
const asyncListeners = sortedListeners.filter(l => l.config.async);
|
||||
const syncListeners = sortedListeners.filter((l) => !l.config.async);
|
||||
const asyncListeners = sortedListeners.filter((l) => l.config.async);
|
||||
|
||||
// 执行同步监听器
|
||||
for (const listener of syncListeners) {
|
||||
try {
|
||||
if (listener.config.context) {
|
||||
(listener.handler as EventHandler<T>).call(listener.config.context, event);
|
||||
if (listener.config.thisArg) {
|
||||
(listener.handler as EventHandler<T>).call(listener.config.thisArg, event);
|
||||
} else {
|
||||
(listener.handler as EventHandler<T>)(event);
|
||||
}
|
||||
@@ -402,8 +400,8 @@ export class TypeSafeEventSystem {
|
||||
// 执行异步监听器
|
||||
const asyncPromises = asyncListeners.map(async (listener) => {
|
||||
try {
|
||||
if (listener.config.context) {
|
||||
await (listener.handler as AsyncEventHandler<T>).call(listener.config.context, event);
|
||||
if (listener.config.thisArg) {
|
||||
await (listener.handler as AsyncEventHandler<T>).call(listener.config.thisArg, event);
|
||||
} else {
|
||||
await (listener.handler as AsyncEventHandler<T>)(event);
|
||||
}
|
||||
@@ -431,7 +429,7 @@ export class TypeSafeEventSystem {
|
||||
* @param listeners 监听器数组
|
||||
* @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));
|
||||
}
|
||||
|
||||
@@ -447,7 +445,7 @@ export class TypeSafeEventSystem {
|
||||
if (!listeners) return;
|
||||
|
||||
for (const id of listenerIds) {
|
||||
const index = listeners.findIndex(l => l.id === id);
|
||||
const index = listeners.findIndex((l) => l.id === id);
|
||||
if (index !== -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
@@ -488,7 +486,7 @@ export class TypeSafeEventSystem {
|
||||
this.flushBatch(eventType);
|
||||
}, 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();
|
||||
|
||||
|
||||
166
packages/core/src/ECS/Systems/EntityCache.ts
Normal file
166
packages/core/src/ECS/Systems/EntityCache.ts
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,15 @@ import { createLogger } from '../../Utils/Logger';
|
||||
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
|
||||
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
|
||||
import type { IService } from '../../Core/ServiceContainer';
|
||||
import { EntityCache } from './EntityCache';
|
||||
|
||||
/**
|
||||
* 事件监听器记录
|
||||
* 只存储引用信息,用于系统销毁时自动清理
|
||||
*/
|
||||
interface EventListenerRecord {
|
||||
eventSystem: TypeSafeEventSystem;
|
||||
eventType: string;
|
||||
handler: EventHandler;
|
||||
listenerRef: string;
|
||||
}
|
||||
|
||||
@@ -63,9 +64,7 @@ interface EventListenerRecord {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export abstract class EntitySystem<_TComponents extends readonly ComponentConstructor[] = []>
|
||||
implements ISystemBase, IService
|
||||
{
|
||||
export abstract class EntitySystem implements ISystemBase, IService {
|
||||
private _updateOrder: number;
|
||||
private _enabled: boolean;
|
||||
private _performanceMonitor: PerformanceMonitor | null;
|
||||
@@ -85,30 +84,24 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
|
||||
/**
|
||||
* 统一的实体缓存管理器
|
||||
*/
|
||||
private _entityCache: {
|
||||
frame: readonly Entity[] | null;
|
||||
persistent: readonly Entity[] | null;
|
||||
tracked: Set<Entity>;
|
||||
invalidate(): void;
|
||||
clearFrame(): void;
|
||||
clearAll(): void;
|
||||
};
|
||||
private _entityCache: EntityCache;
|
||||
|
||||
/**
|
||||
* 获取系统处理的实体列表
|
||||
*/
|
||||
public get entities(): readonly Entity[] {
|
||||
// 如果在update周期内,优先使用帧缓存
|
||||
if (this._entityCache.frame !== null) {
|
||||
return this._entityCache.frame;
|
||||
const frameCache = this._entityCache.getFrame();
|
||||
if (frameCache !== null) {
|
||||
return frameCache;
|
||||
}
|
||||
|
||||
// 否则使用持久缓存
|
||||
if (this._entityCache.persistent === null) {
|
||||
this._entityCache.persistent = this.queryEntities();
|
||||
if (!this._entityCache.hasPersistent()) {
|
||||
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
|
||||
this.logger = createLogger(this.getLoggerName());
|
||||
|
||||
this._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();
|
||||
}
|
||||
};
|
||||
this._entityCache = new EntityCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,7 +499,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
|
||||
const entityMap = this.getEntityIdMap(allEntities);
|
||||
|
||||
const size = idSet.size;
|
||||
const result = new Array(size);
|
||||
const result = new Array<Entity>(size);
|
||||
let index = 0;
|
||||
|
||||
for (const id of idSet) {
|
||||
@@ -564,10 +542,11 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
|
||||
this.onBegin();
|
||||
// 查询实体并存储到帧缓存中
|
||||
// 响应式查询会自动维护最新的实体列表,updateEntityTracking会在检测到变化时invalidate
|
||||
this._entityCache.frame = this.queryEntities();
|
||||
entityCount = this._entityCache.frame.length;
|
||||
const queriedEntities = this.queryEntities();
|
||||
this._entityCache.setFrame(queriedEntities);
|
||||
entityCount = queriedEntities.length;
|
||||
|
||||
this.process(this._entityCache.frame);
|
||||
this.process(queriedEntities);
|
||||
} finally {
|
||||
monitor.endMonitoring(this._systemName, startTime, entityCount);
|
||||
}
|
||||
@@ -587,7 +566,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
|
||||
|
||||
try {
|
||||
// 使用缓存的实体列表,避免重复查询
|
||||
const entities = this._entityCache.frame || [];
|
||||
const entities = this._entityCache.getFrame() || [];
|
||||
entityCount = entities.length;
|
||||
this.lateProcess(entities);
|
||||
this.onEnd();
|
||||
@@ -697,17 +676,17 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
|
||||
|
||||
// 检查新增的实体
|
||||
for (const entity of currentEntities) {
|
||||
if (!this._entityCache.tracked.has(entity)) {
|
||||
this._entityCache.tracked.add(entity);
|
||||
if (!this._entityCache.isTracked(entity)) {
|
||||
this._entityCache.addTracked(entity);
|
||||
this.onAdded(entity);
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查移除的实体
|
||||
for (const entity of this._entityCache.tracked) {
|
||||
for (const entity of this._entityCache.getTracked()) {
|
||||
if (!currentSet.has(entity)) {
|
||||
this._entityCache.tracked.delete(entity);
|
||||
this._entityCache.removeTracked(entity);
|
||||
this.onRemoved(entity);
|
||||
hasChanged = true;
|
||||
}
|
||||
@@ -778,15 +757,16 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
|
||||
* @param eventType 事件类型
|
||||
* @param handler 事件处理函数
|
||||
* @param config 监听器配置
|
||||
* @returns 监听器引用ID,可用于手动移除监听器
|
||||
*/
|
||||
protected addEventListener<T = any>(
|
||||
protected addEventListener<T>(
|
||||
eventType: string,
|
||||
handler: EventHandler<T>,
|
||||
config?: EventListenerConfig
|
||||
): void {
|
||||
): string | null {
|
||||
if (!this.scene?.eventSystem) {
|
||||
this.logger.warn(`${this.systemName}: 无法添加事件监听器,scene.eventSystem 不可用`);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
const listenerRef = this.scene.eventSystem.on(eventType, handler, config);
|
||||
@@ -796,21 +776,22 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
|
||||
this._eventListeners.push({
|
||||
eventSystem: this.scene.eventSystem,
|
||||
eventType,
|
||||
handler,
|
||||
listenerRef
|
||||
});
|
||||
}
|
||||
|
||||
return listenerRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除特定的事件监听器
|
||||
*
|
||||
* @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(
|
||||
(listener) => listener.eventType === eventType && listener.handler === handler
|
||||
(listener) => listener.eventType === eventType && listener.listenerRef === listenerRef
|
||||
);
|
||||
|
||||
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> {
|
||||
const component = entity.getComponent(componentType as any);
|
||||
const component = entity.getComponent(componentType);
|
||||
if (!component) {
|
||||
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,
|
||||
...components: T
|
||||
): { [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]>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -142,8 +142,8 @@ export interface IEventListenerConfig {
|
||||
priority?: number;
|
||||
/** 是否异步执行 */
|
||||
async?: boolean;
|
||||
/** 执行上下文 */
|
||||
context?: unknown;
|
||||
/** 事件处理函数的 this 绑定对象 */
|
||||
thisArg?: object;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,17 +50,19 @@ class ConcreteEntitySystem extends EntitySystem {
|
||||
const handler = (event: any) => {
|
||||
this.eventHandlerCallCount++;
|
||||
};
|
||||
this.addEventListener('manual_event', handler);
|
||||
this.removeEventListener('manual_event', handler);
|
||||
const listenerRef = this.addEventListener('manual_event', handler);
|
||||
if (listenerRef) {
|
||||
this.removeEventListener('manual_event', listenerRef);
|
||||
}
|
||||
}
|
||||
|
||||
// 公开测试方法
|
||||
public testAddEventListener(eventType: string, handler: (event: any) => void): void {
|
||||
this.addEventListener(eventType, handler);
|
||||
public testAddEventListener(eventType: string, handler: (event: any) => void): string | null {
|
||||
return this.addEventListener(eventType, handler);
|
||||
}
|
||||
|
||||
public testRemoveEventListener(eventType: string, handler: (event: any) => void): void {
|
||||
this.removeEventListener(eventType, handler);
|
||||
public testRemoveEventListener(eventType: string, listenerRef: string): void {
|
||||
this.removeEventListener(eventType, listenerRef);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,14 +120,16 @@ describe('EntitySystem', () => {
|
||||
const handler = jest.fn();
|
||||
|
||||
// 添加监听器
|
||||
system.testAddEventListener('manual_remove_event', handler);
|
||||
const listenerRef = system.testAddEventListener('manual_remove_event', handler);
|
||||
|
||||
// 发射事件验证监听器工作
|
||||
scene.eventSystem.emitSync('manual_remove_event', {});
|
||||
expect(handler).toHaveBeenCalledTimes(1);
|
||||
|
||||
// 移除监听器
|
||||
system.testRemoveEventListener('manual_remove_event', handler);
|
||||
if (listenerRef) {
|
||||
system.testRemoveEventListener('manual_remove_event', listenerRef);
|
||||
}
|
||||
|
||||
// 再次发射事件
|
||||
scene.eventSystem.emitSync('manual_remove_event', {});
|
||||
@@ -205,11 +209,11 @@ describe('EntitySystem', () => {
|
||||
});
|
||||
|
||||
it('当移除不存在的监听器时,应该安全处理', () => {
|
||||
const nonExistentHandler = () => {};
|
||||
const nonExistentListenerRef = 'non_existent_listener_ref';
|
||||
|
||||
// 应该不会抛出错误
|
||||
expect(() => {
|
||||
system.testRemoveEventListener('non_existent_event', nonExistentHandler);
|
||||
system.testRemoveEventListener('non_existent_event', nonExistentListenerRef);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user