[Linux-only] basically bloxstap for sober
1import type {
2 PlrJoinLeaveAction,
3 GameJoinAction,
4 BloxstrapRPCAction,
5 GameState,
6 TeleportAction
7} from "./types";
8import { currentStateManager } from "./CurrentState";
9
10export type EventType =
11 | "GAME_JOIN"
12 | "GAME_LEAVE"
13 | "PLAYER_JOIN"
14 | "PLAYER_LEAVE"
15 | "TELEPORT"
16 | "BLOXSTRAP_RPC"
17 | "STATE_CHANGE";
18
19export type EventData = {
20 GAME_JOIN: GameJoinAction;
21 GAME_LEAVE: void;
22 PLAYER_JOIN: PlrJoinLeaveAction;
23 PLAYER_LEAVE: PlrJoinLeaveAction;
24 BLOXSTRAP_RPC: BloxstrapRPCAction;
25 STATE_CHANGE: GameState;
26 TELEPORT: TeleportAction;
27};
28
29export type EventCallback<T extends EventType> = (data: EventData[T]) => void;
30
31export type EventSubscription = {
32 unsubscribe: () => void;
33};
34
35class EventCollector {
36 private listeners: Map<EventType, Set<EventCallback<any>>> = new Map();
37
38 /**
39 * Subscribe to an event type
40 */
41 public on<T extends EventType>(
42 eventType: T,
43 callback: EventCallback<T>
44 ): EventSubscription {
45 if (!this.listeners.has(eventType)) {
46 this.listeners.set(eventType, new Set());
47 }
48
49 const eventListeners = this.listeners.get(eventType)!;
50 eventListeners.add(callback);
51
52 return {
53 unsubscribe: () => {
54 eventListeners.delete(callback);
55 if (eventListeners.size === 0) {
56 this.listeners.delete(eventType);
57 }
58 }
59 };
60 }
61
62 /**
63 * Emit an event to all subscribed listeners
64 */
65 public emit<T extends EventType>(eventType: T, data: EventData[T]): void {
66 const eventListeners = this.listeners.get(eventType);
67 if (eventListeners) {
68 eventListeners.forEach((callback) => {
69 try {
70 callback(data);
71 } catch (error) {
72 console.error(
73 `Error in event listener for ${eventType}:`,
74 error
75 );
76 }
77 });
78 }
79 }
80
81 /**
82 * Emit a game join event
83 */
84 public emitGameJoin(gameData: GameJoinAction): void {
85 this.emit("GAME_JOIN", gameData);
86 currentStateManager.handleGameJoin(gameData);
87 this.emit("STATE_CHANGE", currentStateManager.getCurrentState());
88 }
89
90 /**
91 * Emit a game leave event
92 */
93 public emitGameLeave(): void {
94 this.emit("GAME_LEAVE", undefined);
95 currentStateManager.handleGameLeave();
96 this.emit("STATE_CHANGE", currentStateManager.getCurrentState());
97 }
98
99 /**
100 * Emit a player join event
101 */
102 public emitPlayerJoin(playerData: PlrJoinLeaveAction): void {
103 this.emit("PLAYER_JOIN", playerData);
104 currentStateManager.handlePlayerAction(playerData);
105 this.emit("STATE_CHANGE", currentStateManager.getCurrentState());
106 }
107
108 /**
109 * Emit a player leave event
110 */
111 public emitPlayerLeave(playerData: PlrJoinLeaveAction): void {
112 this.emit("PLAYER_LEAVE", playerData);
113 currentStateManager.handlePlayerAction(playerData);
114 this.emit("STATE_CHANGE", currentStateManager.getCurrentState());
115 }
116
117 /**
118 * Emit a Bloxstrap RPC event
119 */
120 public emitBloxstrapRPC(rpcData: BloxstrapRPCAction): void {
121 this.emit("BLOXSTRAP_RPC", rpcData);
122 }
123
124 /**
125 * Emit a teleport event
126 */
127 public emitTeleport(data: TeleportAction): void {
128 this.emit("TELEPORT", data);
129 }
130
131 /**
132 * Get the number of listeners for a specific event type
133 */
134 public getListenerCount(eventType: EventType): number {
135 return this.listeners.get(eventType)?.size || 0;
136 }
137
138 /**
139 * Get all registered event types
140 */
141 public getRegisteredEvents(): EventType[] {
142 return Array.from(this.listeners.keys());
143 }
144
145 /**
146 * Clear all listeners for a specific event type
147 */
148 public clearListeners(eventType: EventType): void {
149 this.listeners.delete(eventType);
150 }
151
152 /**
153 * Clear all listeners for all event types
154 */
155 public clearAllListeners(): void {
156 this.listeners.clear();
157 }
158}
159
160// Export a singleton instance
161export const eventCollector = new EventCollector();