You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.0 KiB
85 lines
2.0 KiB
type EventCallback = (...args: unknown[]) => void;
|
|
type AnyEventCallback = (event: string, ...args: unknown[]) => void;
|
|
|
|
export interface RuntimeEventMap {
|
|
"runtime:ready": { startedAt: number };
|
|
"scene:changed": { current: string; previous?: string };
|
|
"game:rendered": undefined;
|
|
"game:frame-rendered": undefined;
|
|
}
|
|
|
|
export class RuntimeEvents {
|
|
private events = new Map<string, Set<EventCallback>>();
|
|
private anyEventCallbacks = new Set<AnyEventCallback>();
|
|
|
|
on(event: string, callback: EventCallback): () => void {
|
|
if (!this.events.has(event)) {
|
|
this.events.set(event, new Set());
|
|
}
|
|
|
|
this.events.get(event)!.add(callback);
|
|
return () => this.off(event, callback);
|
|
}
|
|
|
|
off(event: string, callback: EventCallback): void {
|
|
const callbacks = this.events.get(event);
|
|
if (!callbacks) {
|
|
return;
|
|
}
|
|
|
|
callbacks.delete(callback);
|
|
if (callbacks.size === 0) {
|
|
this.events.delete(event);
|
|
}
|
|
}
|
|
|
|
once(event: string, callback: EventCallback): () => void {
|
|
const wrapped: EventCallback = (...args) => {
|
|
try {
|
|
callback(...args);
|
|
} finally {
|
|
this.off(event, wrapped);
|
|
}
|
|
};
|
|
return this.on(event, wrapped);
|
|
}
|
|
|
|
emit(event: string, ...args: unknown[]): void {
|
|
this.anyEventCallbacks.forEach((cb) => {
|
|
try {
|
|
cb(event, ...args);
|
|
} catch (error) {
|
|
console.error(`RuntimeEvents: tap listener failed for "${event}"`, error);
|
|
}
|
|
});
|
|
|
|
const callbacks = this.events.get(event);
|
|
if (!callbacks) {
|
|
return;
|
|
}
|
|
|
|
callbacks.forEach((cb) => {
|
|
try {
|
|
cb(...args);
|
|
} catch (error) {
|
|
console.error(`RuntimeEvents: listener failed for "${event}"`, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
clear(): void {
|
|
this.events.clear();
|
|
this.anyEventCallbacks.clear();
|
|
}
|
|
|
|
getEventCount(): number {
|
|
return this.events.size;
|
|
}
|
|
|
|
onAny(callback: AnyEventCallback): () => void {
|
|
this.anyEventCallbacks.add(callback);
|
|
return () => {
|
|
this.anyEventCallbacks.delete(callback);
|
|
};
|
|
}
|
|
}
|
|
|