interface Type extends Function { new (...args: any[]): T; } export interface IEventProcessor { processEvents: (events: any[]) => void; } export class EventProcessor { private handlers = new Map(); static watch>(Base: T) { const eventProcessor = new EventProcessor(); return class extends Base { constructor(...args: any[]) { super(...args); const methods = Base.prototype["eventProcessorMethods"] || new Map(); for (const [eventType, handler] of methods) { eventProcessor.setHandler(eventType, handler.bind(this)); } } processEvents(events: any[]) { for (const event of events) { eventProcessor.emit(event); } } }; } static handle(eventType: Type) { return ( target: any, _propertyKey: string, descriptor: TypedPropertyDescriptor<(ev: T) => void> ) => { if (!("eventProcessorMethods" in target)) { target["eventProcessorMethods"] = new Map(); } const methods = target["eventProcessorMethods"]; methods.set(eventType, descriptor.value); }; } setHandler(GameEvent: Type, handler: (gameEvent: T) => void) { this.handlers.set(GameEvent, handler); } emit(gameEvent: T) { const handler = this.handlers.get(gameEvent.constructor); if (handler !== undefined) { handler(gameEvent); } } }