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 {
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 {
}
}

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;
/** 是否异步执行 */
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();

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 { 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]>;
};
}
/**

View File

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

View File

@@ -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();
});
});