Files
esengine/src/ECS/Core/EventBus.ts
2025-06-30 20:43:11 +08:00

497 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
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<T>(eventType: string, data: T): void {
this.validateEventType(eventType);
// 增强事件数据
const enhancedData = this.enhanceEventData(eventType, data);
if (this.isDebugMode) {
console.log(`[EventBus] 发射事件: ${eventType}`, enhancedData);
}
this.eventSystem.emitSync(eventType, enhancedData);
}
/**
* 异步发射事件
* @param eventType 事件类型
* @param data 事件数据
*/
public async emitAsync<T>(eventType: string, data: T): Promise<void> {
this.validateEventType(eventType);
// 增强事件数据
const enhancedData = this.enhanceEventData(eventType, data);
if (this.isDebugMode) {
console.log(`[EventBus] 发射异步事件: ${eventType}`, enhancedData);
}
await this.eventSystem.emit(eventType, enhancedData);
}
/**
* 监听事件
* @param eventType 事件类型
* @param handler 事件处理器
* @param config 监听器配置
* @returns 监听器ID
*/
public on<T>(
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] 添加监听器: ${eventType}`, eventConfig);
}
return this.eventSystem.on(eventType, handler, eventConfig);
}
/**
* 监听事件(一次性)
* @param eventType 事件类型
* @param handler 事件处理器
* @param config 监听器配置
* @returns 监听器ID
*/
public once<T>(
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<T>(
eventType: string,
handler: (data: T) => Promise<void>,
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] 移除监听器: ${listenerId} 事件: ${eventType}`);
}
return this.eventSystem.off(eventType, listenerId);
}
/**
* 移除指定事件类型的所有监听器
* @param eventType 事件类型
*/
public offAll(eventType: string): void {
if (this.isDebugMode) {
console.log(`[EventBus] 移除所有监听器: ${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<string, IEventStats> {
const stats = this.eventSystem.getStats(eventType);
if (stats instanceof Map) {
// 转换Map中的每个EventStats为IEventStats
const result = new Map<string, IEventStats>();
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] 清空所有监听器');
}
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(ECSEventType.SCENE_ACTIVATED, 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] 未知事件类型: ${eventType}`);
}
// 在调试模式下添加自定义事件类型
if (this.isDebugMode) {
EventTypeValidator.addCustomType(eventType);
}
}
}
/**
* 增强事件数据
* @param eventType 事件类型
* @param data 原始数据
*/
private enhanceEventData<T>(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;
};
}