@phalanx-engine/client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1037 -0
- package/dist/DesyncDetector.d.ts +80 -0
- package/dist/DesyncDetector.d.ts.map +1 -0
- package/dist/DesyncDetector.js +93 -0
- package/dist/DesyncDetector.js.map +1 -0
- package/dist/DeterministicRandom.d.ts +78 -0
- package/dist/DeterministicRandom.d.ts.map +1 -0
- package/dist/DeterministicRandom.js +122 -0
- package/dist/DeterministicRandom.js.map +1 -0
- package/dist/EventEmitter.d.ts +65 -0
- package/dist/EventEmitter.d.ts.map +1 -0
- package/dist/EventEmitter.js +102 -0
- package/dist/EventEmitter.js.map +1 -0
- package/dist/FixedMath.d.ts +22 -0
- package/dist/FixedMath.d.ts.map +1 -0
- package/dist/FixedMath.js +26 -0
- package/dist/FixedMath.js.map +1 -0
- package/dist/PhalanxClient.d.ts +335 -0
- package/dist/PhalanxClient.d.ts.map +1 -0
- package/dist/PhalanxClient.js +844 -0
- package/dist/PhalanxClient.js.map +1 -0
- package/dist/RenderLoop.d.ts +95 -0
- package/dist/RenderLoop.d.ts.map +1 -0
- package/dist/RenderLoop.js +192 -0
- package/dist/RenderLoop.js.map +1 -0
- package/dist/SocketManager.d.ts +228 -0
- package/dist/SocketManager.d.ts.map +1 -0
- package/dist/SocketManager.js +584 -0
- package/dist/SocketManager.js.map +1 -0
- package/dist/StateHasher.d.ts +76 -0
- package/dist/StateHasher.d.ts.map +1 -0
- package/dist/StateHasher.js +129 -0
- package/dist/StateHasher.js.map +1 -0
- package/dist/auth/AuthManager.d.ts +188 -0
- package/dist/auth/AuthManager.d.ts.map +1 -0
- package/dist/auth/AuthManager.js +462 -0
- package/dist/auth/AuthManager.js.map +1 -0
- package/dist/auth/adapters/GoogleOAuthAdapter.d.ts +164 -0
- package/dist/auth/adapters/GoogleOAuthAdapter.d.ts.map +1 -0
- package/dist/auth/adapters/GoogleOAuthAdapter.js +521 -0
- package/dist/auth/adapters/GoogleOAuthAdapter.js.map +1 -0
- package/dist/auth/index.d.ts +45 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +54 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/storage.d.ts +56 -0
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js +78 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/auth/types.d.ts +212 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +7 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/recovery/BrowserLifecycle.d.ts +33 -0
- package/dist/recovery/BrowserLifecycle.d.ts.map +1 -0
- package/dist/recovery/BrowserLifecycle.js +62 -0
- package/dist/recovery/BrowserLifecycle.js.map +1 -0
- package/dist/recovery/GuestPlayerIdStore.d.ts +17 -0
- package/dist/recovery/GuestPlayerIdStore.d.ts.map +1 -0
- package/dist/recovery/GuestPlayerIdStore.js +31 -0
- package/dist/recovery/GuestPlayerIdStore.js.map +1 -0
- package/dist/recovery/KeyValueStorage.d.ts +32 -0
- package/dist/recovery/KeyValueStorage.d.ts.map +1 -0
- package/dist/recovery/KeyValueStorage.js +58 -0
- package/dist/recovery/KeyValueStorage.js.map +1 -0
- package/dist/recovery/MobileTransport.d.ts +12 -0
- package/dist/recovery/MobileTransport.d.ts.map +1 -0
- package/dist/recovery/MobileTransport.js +24 -0
- package/dist/recovery/MobileTransport.js.map +1 -0
- package/dist/recovery/NetworkQuality.d.ts +22 -0
- package/dist/recovery/NetworkQuality.d.ts.map +1 -0
- package/dist/recovery/NetworkQuality.js +35 -0
- package/dist/recovery/NetworkQuality.js.map +1 -0
- package/dist/recovery/RoomPersistence.d.ts +55 -0
- package/dist/recovery/RoomPersistence.d.ts.map +1 -0
- package/dist/recovery/RoomPersistence.js +68 -0
- package/dist/recovery/RoomPersistence.js.map +1 -0
- package/dist/recovery/RoomRecoveryController.d.ts +146 -0
- package/dist/recovery/RoomRecoveryController.d.ts.map +1 -0
- package/dist/recovery/RoomRecoveryController.js +348 -0
- package/dist/recovery/RoomRecoveryController.js.map +1 -0
- package/dist/recovery/index.d.ts +13 -0
- package/dist/recovery/index.d.ts.map +1 -0
- package/dist/recovery/index.js +8 -0
- package/dist/recovery/index.js.map +1 -0
- package/dist/types.d.ts +501 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SocketManager - Manages socket.io connection and event handling
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - Connection/disconnection to server
|
|
6
|
+
* - Socket event routing
|
|
7
|
+
* - Reconnection logic with retries
|
|
8
|
+
* - Connection state tracking
|
|
9
|
+
*/
|
|
10
|
+
import { io } from 'socket.io-client';
|
|
11
|
+
/**
|
|
12
|
+
* SocketManager - Handles socket.io connection and event handling
|
|
13
|
+
*/
|
|
14
|
+
export class SocketManager {
|
|
15
|
+
socket = null;
|
|
16
|
+
config;
|
|
17
|
+
callbacks;
|
|
18
|
+
connectionState = 'disconnected';
|
|
19
|
+
reconnectAttempts = 0;
|
|
20
|
+
constructor(config, callbacks) {
|
|
21
|
+
this.config = config;
|
|
22
|
+
this.callbacks = callbacks;
|
|
23
|
+
}
|
|
24
|
+
// ============================================
|
|
25
|
+
// CONNECTION
|
|
26
|
+
// ============================================
|
|
27
|
+
/**
|
|
28
|
+
* Connect to the server
|
|
29
|
+
*/
|
|
30
|
+
async connect() {
|
|
31
|
+
if (this.connectionState === 'connected') {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.connectionState = 'connecting';
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const timeout = setTimeout(() => {
|
|
37
|
+
this.socket?.disconnect();
|
|
38
|
+
this.connectionState = 'disconnected';
|
|
39
|
+
reject(new Error('Connection timeout'));
|
|
40
|
+
}, this.config.connectionTimeoutMs);
|
|
41
|
+
this.socket = io(this.config.serverUrl, {
|
|
42
|
+
forceNew: true,
|
|
43
|
+
transports: [...this.config.socketTransports],
|
|
44
|
+
reconnection: false, // We handle reconnection ourselves
|
|
45
|
+
auth: this.config.authToken
|
|
46
|
+
? { token: this.config.authToken }
|
|
47
|
+
: undefined,
|
|
48
|
+
});
|
|
49
|
+
this.socket.on('connect', () => {
|
|
50
|
+
clearTimeout(timeout);
|
|
51
|
+
this.connectionState = 'connected';
|
|
52
|
+
this.reconnectAttempts = 0;
|
|
53
|
+
this.setupEventHandlers();
|
|
54
|
+
this.callbacks.onConnected();
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
57
|
+
this.socket.on('connect_error', (error) => {
|
|
58
|
+
clearTimeout(timeout);
|
|
59
|
+
this.connectionState = 'disconnected';
|
|
60
|
+
reject(new Error(`Connection failed: ${error.message}`));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Disconnect from the server
|
|
66
|
+
*/
|
|
67
|
+
disconnect() {
|
|
68
|
+
if (this.socket) {
|
|
69
|
+
this.socket.removeAllListeners();
|
|
70
|
+
this.socket.disconnect();
|
|
71
|
+
this.socket = null;
|
|
72
|
+
}
|
|
73
|
+
this.connectionState = 'disconnected';
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check if connected
|
|
77
|
+
*/
|
|
78
|
+
isConnected() {
|
|
79
|
+
return (this.connectionState === 'connected' && this.socket?.connected === true);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get connection state
|
|
83
|
+
*/
|
|
84
|
+
getConnectionState() {
|
|
85
|
+
return this.connectionState;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Update player credentials (after auth)
|
|
89
|
+
*/
|
|
90
|
+
updateCredentials(playerId, username, authToken) {
|
|
91
|
+
this.config.playerId = playerId;
|
|
92
|
+
this.config.username = username;
|
|
93
|
+
this.config.authToken = authToken;
|
|
94
|
+
}
|
|
95
|
+
// ============================================
|
|
96
|
+
// QUEUE OPERATIONS
|
|
97
|
+
// ============================================
|
|
98
|
+
/**
|
|
99
|
+
* Join the matchmaking queue
|
|
100
|
+
*/
|
|
101
|
+
async joinQueue() {
|
|
102
|
+
this.ensureConnected();
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const errorHandler = (error) => {
|
|
105
|
+
this.socket?.off('queue-status', statusHandler);
|
|
106
|
+
reject(new Error(error.message));
|
|
107
|
+
};
|
|
108
|
+
const statusHandler = (status) => {
|
|
109
|
+
this.socket?.off('queue-error', errorHandler);
|
|
110
|
+
resolve(status);
|
|
111
|
+
};
|
|
112
|
+
this.socket.once('queue-status', statusHandler);
|
|
113
|
+
this.socket.once('queue-error', errorHandler);
|
|
114
|
+
this.socket.emit('queue-join', {
|
|
115
|
+
playerId: this.config.playerId,
|
|
116
|
+
username: this.config.username,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Leave the matchmaking queue
|
|
122
|
+
*/
|
|
123
|
+
leaveQueue() {
|
|
124
|
+
this.ensureConnected();
|
|
125
|
+
this.socket.emit('queue-leave', {
|
|
126
|
+
playerId: this.config.playerId,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// ============================================
|
|
130
|
+
// PRIVATE ROOM OPERATIONS
|
|
131
|
+
// ============================================
|
|
132
|
+
/**
|
|
133
|
+
* Create a private room. Resolves with the room code.
|
|
134
|
+
*/
|
|
135
|
+
async createRoom(gameType) {
|
|
136
|
+
this.ensureConnected();
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
const errorHandler = (error) => {
|
|
139
|
+
this.socket?.off('room-created', createdHandler);
|
|
140
|
+
reject(new Error(error.message));
|
|
141
|
+
};
|
|
142
|
+
const createdHandler = (event) => {
|
|
143
|
+
this.socket?.off('room-error', errorHandler);
|
|
144
|
+
resolve(event);
|
|
145
|
+
};
|
|
146
|
+
this.socket.once('room-created', createdHandler);
|
|
147
|
+
this.socket.once('room-error', errorHandler);
|
|
148
|
+
this.socket.emit('room-create', {
|
|
149
|
+
playerId: this.config.playerId,
|
|
150
|
+
username: this.config.username,
|
|
151
|
+
gameType,
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Join an existing private room by code.
|
|
157
|
+
* After joining, the server will emit match-found to both players.
|
|
158
|
+
*/
|
|
159
|
+
joinRoom(code) {
|
|
160
|
+
this.ensureConnected();
|
|
161
|
+
this.socket.emit('room-join', {
|
|
162
|
+
playerId: this.config.playerId,
|
|
163
|
+
username: this.config.username,
|
|
164
|
+
code,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Cancel a previously created private room.
|
|
169
|
+
*/
|
|
170
|
+
cancelRoom() {
|
|
171
|
+
this.ensureConnected();
|
|
172
|
+
this.socket.emit('room-cancel');
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Reclaim a private room after the underlying socket was briefly torn
|
|
176
|
+
* down and reconnected.
|
|
177
|
+
*
|
|
178
|
+
* This is the client half of the host-disconnect grace-period contract
|
|
179
|
+
* introduced server-side in PR #18 and extended with countdown/game-start
|
|
180
|
+
* snapshotting in PR #19: the server holds the room (and, if the guest
|
|
181
|
+
* already joined, the running match) open for `HOST_DISCONNECT_GRACE_MS`
|
|
182
|
+
* so the host's new socket can reclaim it via `room-recover`.
|
|
183
|
+
*
|
|
184
|
+
* Typical trigger: a mobile browser kills the WebSocket when the user
|
|
185
|
+
* switches to a messenger to share the invite link, then re-opens the
|
|
186
|
+
* tab. The caller (Game / UI layer) should listen for `visibilitychange`
|
|
187
|
+
* and, when the tab becomes visible again and the socket is dead, call
|
|
188
|
+
* `connect()` followed by `recoverRoom(code)`.
|
|
189
|
+
*
|
|
190
|
+
* Resolves with the `RoomRecoveredEvent` on success. Rejects with the
|
|
191
|
+
* server's error message on `room-error`, or with `'Recover timeout'`
|
|
192
|
+
* if the server never answers within `timeoutMs` (default 10 s). The
|
|
193
|
+
* timeout is important because a stubbornly flaky connection can cause
|
|
194
|
+
* `socket.emit` to succeed locally but never round-trip — we must not
|
|
195
|
+
* leave the host hanging on a dead promise while their countdown UI
|
|
196
|
+
* stays frozen.
|
|
197
|
+
*/
|
|
198
|
+
async recoverRoom(code, timeoutMs = this.config.recoverRoomTimeoutMs) {
|
|
199
|
+
this.ensureConnected();
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
let settled = false;
|
|
202
|
+
const cleanup = () => {
|
|
203
|
+
this.socket?.off('room-recovered', recoveredHandler);
|
|
204
|
+
this.socket?.off('room-error', errorHandler);
|
|
205
|
+
clearTimeout(timer);
|
|
206
|
+
};
|
|
207
|
+
const recoveredHandler = (event) => {
|
|
208
|
+
if (settled)
|
|
209
|
+
return;
|
|
210
|
+
settled = true;
|
|
211
|
+
cleanup();
|
|
212
|
+
resolve(event);
|
|
213
|
+
};
|
|
214
|
+
const errorHandler = (error) => {
|
|
215
|
+
if (settled)
|
|
216
|
+
return;
|
|
217
|
+
settled = true;
|
|
218
|
+
cleanup();
|
|
219
|
+
reject(new Error(error.message));
|
|
220
|
+
};
|
|
221
|
+
const timer = setTimeout(() => {
|
|
222
|
+
if (settled)
|
|
223
|
+
return;
|
|
224
|
+
settled = true;
|
|
225
|
+
cleanup();
|
|
226
|
+
reject(new Error('Recover timeout'));
|
|
227
|
+
}, timeoutMs);
|
|
228
|
+
this.socket.once('room-recovered', recoveredHandler);
|
|
229
|
+
this.socket.once('room-error', errorHandler);
|
|
230
|
+
this.socket.emit('room-recover', {
|
|
231
|
+
playerId: this.config.playerId,
|
|
232
|
+
username: this.config.username,
|
|
233
|
+
code,
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Register a handler for room-recovered events. Exposed alongside the
|
|
239
|
+
* one-shot `recoverRoom` promise so callers that want to observe
|
|
240
|
+
* recoveries initiated elsewhere (e.g. for analytics) can do so.
|
|
241
|
+
*/
|
|
242
|
+
onRoomRecovered(handler) {
|
|
243
|
+
this.socket?.on('room-recovered', handler);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Register a handler for room-expired events.
|
|
247
|
+
*/
|
|
248
|
+
onRoomExpired(handler) {
|
|
249
|
+
this.socket?.on('room-expired', handler);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Register a handler for room-cancelled events.
|
|
253
|
+
*/
|
|
254
|
+
onRoomCancelled(handler) {
|
|
255
|
+
this.socket?.on('room-cancelled', handler);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Wait for match found event
|
|
259
|
+
*/
|
|
260
|
+
async waitForMatch() {
|
|
261
|
+
this.ensureConnected();
|
|
262
|
+
return new Promise((resolve) => {
|
|
263
|
+
this.socket.once('match-found', (data) => {
|
|
264
|
+
resolve(data);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Wait for countdown to complete
|
|
270
|
+
*/
|
|
271
|
+
async waitForCountdown(onCountdown) {
|
|
272
|
+
this.ensureConnected();
|
|
273
|
+
return new Promise((resolve) => {
|
|
274
|
+
const countdownHandler = (data) => {
|
|
275
|
+
this.callbacks.onCountdown(data);
|
|
276
|
+
onCountdown?.(data);
|
|
277
|
+
if (data.seconds === 0) {
|
|
278
|
+
this.socket?.off('countdown', countdownHandler);
|
|
279
|
+
resolve();
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
this.socket.on('countdown', countdownHandler);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Wait for game start event
|
|
287
|
+
*/
|
|
288
|
+
async waitForGameStart() {
|
|
289
|
+
this.ensureConnected();
|
|
290
|
+
return new Promise((resolve) => {
|
|
291
|
+
this.socket.once('game-start', (data) => {
|
|
292
|
+
resolve(data);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
// ============================================
|
|
297
|
+
// COMMANDS
|
|
298
|
+
// ============================================
|
|
299
|
+
/**
|
|
300
|
+
* Submit commands with acknowledgment
|
|
301
|
+
*/
|
|
302
|
+
async submitCommands(tick, commands) {
|
|
303
|
+
this.ensureConnected();
|
|
304
|
+
return new Promise((resolve) => {
|
|
305
|
+
this.socket.once('submit-commands-ack', (ack) => {
|
|
306
|
+
resolve(ack);
|
|
307
|
+
});
|
|
308
|
+
this.socket.emit('submit-commands', { tick, commands });
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Submit commands without acknowledgment (fire and forget)
|
|
313
|
+
*/
|
|
314
|
+
submitCommandsAsync(tick, commands) {
|
|
315
|
+
this.ensureConnected();
|
|
316
|
+
this.socket.emit('submit-commands', { tick, commands });
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Send state hash for desync detection
|
|
320
|
+
* @param tick - The tick this hash is for
|
|
321
|
+
* @param hash - The state hash string
|
|
322
|
+
*/
|
|
323
|
+
sendStateHash(tick, hash) {
|
|
324
|
+
this.ensureConnected();
|
|
325
|
+
this.socket.emit('state-hash', { tick, hash });
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Send a pause-game request to the server (fire-and-forget)
|
|
329
|
+
*/
|
|
330
|
+
sendPauseGame() {
|
|
331
|
+
this.ensureConnected();
|
|
332
|
+
this.socket.emit('pause-game');
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Send a resume-game request to the server (fire-and-forget)
|
|
336
|
+
*/
|
|
337
|
+
sendResumeGame() {
|
|
338
|
+
this.ensureConnected();
|
|
339
|
+
this.socket.emit('resume-game');
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Notify the server that this client has finished loading and is ready to receive ticks.
|
|
343
|
+
*/
|
|
344
|
+
sendReady() {
|
|
345
|
+
this.ensureConnected();
|
|
346
|
+
this.socket.emit('client-ready');
|
|
347
|
+
}
|
|
348
|
+
// ============================================
|
|
349
|
+
// RECONNECTION
|
|
350
|
+
// ============================================
|
|
351
|
+
/**
|
|
352
|
+
* Reconnect to a specific match
|
|
353
|
+
*/
|
|
354
|
+
async reconnectToMatch(matchId) {
|
|
355
|
+
this.ensureConnected();
|
|
356
|
+
return new Promise((resolve, reject) => {
|
|
357
|
+
const statusHandler = (status) => {
|
|
358
|
+
this.callbacks.onReconnectStatus(status);
|
|
359
|
+
if (!status.success) {
|
|
360
|
+
this.socket?.off('reconnect-state', stateHandler);
|
|
361
|
+
reject(new Error(status.reason || 'Reconnection failed'));
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
const stateHandler = (state) => {
|
|
365
|
+
this.socket?.off('reconnect-status', statusHandler);
|
|
366
|
+
// Do NOT invoke `callbacks.onReconnectState` here — the global
|
|
367
|
+
// `reconnect-state` handler registered in `setupEventHandlers`
|
|
368
|
+
// already fires for this same message. Calling it twice would
|
|
369
|
+
// drive downstream state updates (and any synthetic countdown /
|
|
370
|
+
// game-start replays) through the client twice per server event.
|
|
371
|
+
resolve(state);
|
|
372
|
+
};
|
|
373
|
+
this.socket.once('reconnect-status', statusHandler);
|
|
374
|
+
this.socket.once('reconnect-state', stateHandler);
|
|
375
|
+
this.socket.emit('reconnect-match', {
|
|
376
|
+
playerId: this.config.playerId,
|
|
377
|
+
matchId,
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Attempt automatic reconnection with retries
|
|
383
|
+
*/
|
|
384
|
+
async attemptReconnection() {
|
|
385
|
+
if (!this.config.autoReconnect) {
|
|
386
|
+
throw new Error('Auto-reconnect is disabled');
|
|
387
|
+
}
|
|
388
|
+
const savedMatchId = this.callbacks.getCurrentMatchId();
|
|
389
|
+
this.connectionState = 'reconnecting';
|
|
390
|
+
while (this.reconnectAttempts < this.config.maxReconnectAttempts) {
|
|
391
|
+
this.reconnectAttempts++;
|
|
392
|
+
this.callbacks.onReconnecting(this.reconnectAttempts);
|
|
393
|
+
try {
|
|
394
|
+
await this.delay(this.config.reconnectDelayMs);
|
|
395
|
+
await this.connect();
|
|
396
|
+
if (savedMatchId) {
|
|
397
|
+
await this.reconnectToMatch(savedMatchId);
|
|
398
|
+
}
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
// Continue to next attempt
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
this.callbacks.onReconnectFailed();
|
|
406
|
+
throw new Error('Max reconnection attempts reached');
|
|
407
|
+
}
|
|
408
|
+
// ============================================
|
|
409
|
+
// PRIVATE METHODS
|
|
410
|
+
// ============================================
|
|
411
|
+
setupEventHandlers() {
|
|
412
|
+
if (!this.socket)
|
|
413
|
+
return;
|
|
414
|
+
if (this.config.debug) { }
|
|
415
|
+
// Match found
|
|
416
|
+
this.socket.on('match-found', (data) => {
|
|
417
|
+
if (this.config.debug) { }
|
|
418
|
+
this.callbacks.onMatchFound(data);
|
|
419
|
+
});
|
|
420
|
+
// Game start
|
|
421
|
+
this.socket.on('game-start', (data) => {
|
|
422
|
+
if (this.config.debug) { }
|
|
423
|
+
this.callbacks.onGameStart(data);
|
|
424
|
+
});
|
|
425
|
+
// Countdown
|
|
426
|
+
this.socket.on('countdown', (data) => {
|
|
427
|
+
if (this.config.debug) { }
|
|
428
|
+
this.callbacks.onCountdown(data);
|
|
429
|
+
});
|
|
430
|
+
// Tick synchronization
|
|
431
|
+
this.socket.on('tick-sync', (data) => {
|
|
432
|
+
this.callbacks.onTickSync(data);
|
|
433
|
+
});
|
|
434
|
+
// Commands batch
|
|
435
|
+
this.socket.on('commands-batch', (data) => {
|
|
436
|
+
this.callbacks.onCommandsBatch(data);
|
|
437
|
+
});
|
|
438
|
+
// Player events
|
|
439
|
+
this.socket.on('player-disconnected', (data) => {
|
|
440
|
+
this.callbacks.onPlayerDisconnected(data);
|
|
441
|
+
});
|
|
442
|
+
this.socket.on('player-reconnected', (data) => {
|
|
443
|
+
this.callbacks.onPlayerReconnected(data);
|
|
444
|
+
});
|
|
445
|
+
this.socket.on('player-ready', (data) => {
|
|
446
|
+
this.callbacks.onPlayerReady(data);
|
|
447
|
+
});
|
|
448
|
+
// Match end
|
|
449
|
+
this.socket.on('match-end', (data) => {
|
|
450
|
+
this.callbacks.onMatchEnd(data);
|
|
451
|
+
});
|
|
452
|
+
// Reconnect-state — unlike `reconnectToMatch` which attaches a
|
|
453
|
+
// one-shot listener for the explicit reconnect flow, this global
|
|
454
|
+
// handler catches snapshots delivered out-of-band, e.g. by the
|
|
455
|
+
// private-room host-recover path where the client initiates
|
|
456
|
+
// `room-recover` and the server proactively emits reconnect-state
|
|
457
|
+
// to wire the socket back into a match that started while the host
|
|
458
|
+
// was offline.
|
|
459
|
+
//
|
|
460
|
+
// When the snapshot reports an in-flight countdown or an already
|
|
461
|
+
// emitted `game-start`, we fan it out through the same `countdown`
|
|
462
|
+
// / `game-start` callbacks the normal lifecycle uses, so client
|
|
463
|
+
// code that blocks on `waitForCountdown` / `waitForGameStart`
|
|
464
|
+
// wakes up instead of hanging forever waiting for events that
|
|
465
|
+
// were broadcast while the socket was dead.
|
|
466
|
+
this.socket.on('reconnect-state', (data) => {
|
|
467
|
+
this.callbacks.onReconnectState(data);
|
|
468
|
+
// Fan the snapshot out through the same socket event bus that
|
|
469
|
+
// `setupEventHandlers` and `waitForCountdown`/`waitForGameStart`
|
|
470
|
+
// listen on. Using `socket.emit` against the local socket would
|
|
471
|
+
// send to the server, not the local listeners — socket.io-client
|
|
472
|
+
// has no public "emit-to-self", so we replay through every
|
|
473
|
+
// registered listener instead. This wakes callers blocked in
|
|
474
|
+
// `waitForCountdown` / `waitForGameStart` on top of firing the
|
|
475
|
+
// normal callback hooks.
|
|
476
|
+
if (typeof data.countdownSecondsRemaining === 'number' &&
|
|
477
|
+
data.countdownSecondsRemaining >= 0) {
|
|
478
|
+
this.emitSyntheticLocal('countdown', {
|
|
479
|
+
seconds: data.countdownSecondsRemaining,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
// Only synthesize `game-start` when the snapshot shows the client
|
|
483
|
+
// is still in a pre-play phase. For an in-progress match (state
|
|
484
|
+
// `playing` / `paused` / `finished`) the caller is doing a normal
|
|
485
|
+
// mid-match reconnect, and PhalanxClient's `onGameStart` callback
|
|
486
|
+
// would reset `currentTick` to 0 — clobbering the authoritative
|
|
487
|
+
// tick that `onReconnectState` just applied. In that case the
|
|
488
|
+
// client is already past the game-start transition, so there's
|
|
489
|
+
// nothing to replay.
|
|
490
|
+
if (data.gameStartEmitted === true &&
|
|
491
|
+
(data.state === 'countdown' || data.state === 'waiting-for-ready')) {
|
|
492
|
+
const gameStart = {
|
|
493
|
+
matchId: data.matchId,
|
|
494
|
+
...(typeof data.randomSeed === 'number'
|
|
495
|
+
? { randomSeed: data.randomSeed }
|
|
496
|
+
: {}),
|
|
497
|
+
};
|
|
498
|
+
this.emitSyntheticLocal('game-start', gameStart);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
// Hash comparison (for desync detection)
|
|
502
|
+
this.socket.on('hash-comparison', (data) => {
|
|
503
|
+
this.callbacks.onHashComparison(data);
|
|
504
|
+
});
|
|
505
|
+
// Pause events
|
|
506
|
+
this.socket.on('game-paused', (data) => {
|
|
507
|
+
this.callbacks.onGamePaused(data);
|
|
508
|
+
});
|
|
509
|
+
this.socket.on('game-resumed', (data) => {
|
|
510
|
+
this.callbacks.onGameResumed(data);
|
|
511
|
+
});
|
|
512
|
+
// Private room events
|
|
513
|
+
this.socket.on('room-error', (data) => {
|
|
514
|
+
this.callbacks.onRoomError(data);
|
|
515
|
+
});
|
|
516
|
+
this.socket.on('room-expired', (data) => {
|
|
517
|
+
this.callbacks.onRoomExpired(data);
|
|
518
|
+
});
|
|
519
|
+
this.socket.on('room-cancelled', (data) => {
|
|
520
|
+
this.callbacks.onRoomCancelled(data);
|
|
521
|
+
});
|
|
522
|
+
this.socket.on('room-recovered', (data) => {
|
|
523
|
+
this.callbacks.onRoomRecovered(data);
|
|
524
|
+
});
|
|
525
|
+
// Disconnection handling
|
|
526
|
+
this.socket.on('disconnect', () => {
|
|
527
|
+
const wasPlaying = this.callbacks.isPlaying();
|
|
528
|
+
this.connectionState = 'disconnected';
|
|
529
|
+
this.callbacks.onDisconnected();
|
|
530
|
+
if (wasPlaying && this.config.autoReconnect) {
|
|
531
|
+
this.attemptReconnection().catch(() => {
|
|
532
|
+
// Reconnection failed, already emitted reconnectFailed event
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
// Error handling
|
|
537
|
+
this.socket.on('error', (error) => {
|
|
538
|
+
this.callbacks.onError(error);
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
ensureConnected() {
|
|
542
|
+
if (!this.socket || !this.isConnected()) {
|
|
543
|
+
throw new Error('Not connected to server. Call connect() first.');
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Replay `payload` through every listener currently registered for
|
|
548
|
+
* `event` on the local socket.
|
|
549
|
+
*
|
|
550
|
+
* socket.io-client's `socket.emit` sends to the server, so there is
|
|
551
|
+
* no public API to dispatch a server→client event against the
|
|
552
|
+
* client's own handlers. For the private-room recover path we need
|
|
553
|
+
* exactly that: the server already decided that, e.g., countdown
|
|
554
|
+
* should show "3", and we want every listener the application has
|
|
555
|
+
* wired up — including one-shot promises inside `waitForCountdown`
|
|
556
|
+
* / `waitForGameStart` — to observe the value as if the server had
|
|
557
|
+
* broadcast it on the wire.
|
|
558
|
+
*
|
|
559
|
+
* Iterating a snapshot of `socket.listeners(event)` (rather than
|
|
560
|
+
* the live list) is deliberate: a listener may call `socket.off`
|
|
561
|
+
* on itself during handling (e.g. `waitForCountdown`'s handler
|
|
562
|
+
* unsubscribes on `seconds === 0`), which would mutate the array
|
|
563
|
+
* under us and skip siblings.
|
|
564
|
+
*/
|
|
565
|
+
emitSyntheticLocal(event, payload) {
|
|
566
|
+
if (!this.socket)
|
|
567
|
+
return;
|
|
568
|
+
const listeners = this.socket.listeners(event).slice();
|
|
569
|
+
for (const listener of listeners) {
|
|
570
|
+
try {
|
|
571
|
+
listener(payload);
|
|
572
|
+
}
|
|
573
|
+
catch (err) {
|
|
574
|
+
if (this.config.debug) {
|
|
575
|
+
console.error(`[SocketManager] synthetic "${event}" listener threw:`, err);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
delay(ms) {
|
|
581
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
//# sourceMappingURL=SocketManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SocketManager.js","sourceRoot":"","sources":["../src/SocketManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StateHasher - Deterministic state hasher using FNV-1a algorithm
|
|
3
|
+
*
|
|
4
|
+
* Works only with primitives - game-agnostic by design.
|
|
5
|
+
* Games use this to hash their own state structure.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const hash = new StateHasher()
|
|
10
|
+
* .addInt(tick)
|
|
11
|
+
* .addInt(entityCount)
|
|
12
|
+
* .addFloat(entity.x)
|
|
13
|
+
* .addFloat(entity.y)
|
|
14
|
+
* .addString(entity.state)
|
|
15
|
+
* .finalize();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare class StateHasher {
|
|
19
|
+
private static readonly FNV_OFFSET;
|
|
20
|
+
private static readonly FNV_PRIME;
|
|
21
|
+
private static readonly FLOAT_PRECISION;
|
|
22
|
+
private hash;
|
|
23
|
+
constructor();
|
|
24
|
+
/**
|
|
25
|
+
* Add an integer to the hash
|
|
26
|
+
* @param value - Integer value to hash
|
|
27
|
+
* @returns this (for chaining)
|
|
28
|
+
*/
|
|
29
|
+
addInt(value: number): this;
|
|
30
|
+
/**
|
|
31
|
+
* Add a float to the hash (converted to fixed-point for determinism)
|
|
32
|
+
* @param value - Float value to hash
|
|
33
|
+
* @returns this (for chaining)
|
|
34
|
+
*/
|
|
35
|
+
addFloat(value: number): this;
|
|
36
|
+
/**
|
|
37
|
+
* Add a string to the hash
|
|
38
|
+
* @param value - String value to hash
|
|
39
|
+
* @returns this (for chaining)
|
|
40
|
+
*/
|
|
41
|
+
addString(value: string): this;
|
|
42
|
+
/**
|
|
43
|
+
* Add a boolean to the hash
|
|
44
|
+
* @param value - Boolean value to hash
|
|
45
|
+
* @returns this (for chaining)
|
|
46
|
+
*/
|
|
47
|
+
addBool(value: boolean): this;
|
|
48
|
+
/**
|
|
49
|
+
* Add multiple integers (useful for arrays)
|
|
50
|
+
* @param values - Array of integers to hash
|
|
51
|
+
* @returns this (for chaining)
|
|
52
|
+
*/
|
|
53
|
+
addIntArray(values: number[]): this;
|
|
54
|
+
/**
|
|
55
|
+
* Add multiple floats (useful for positions, etc.)
|
|
56
|
+
* @param values - Array of floats to hash
|
|
57
|
+
* @returns this (for chaining)
|
|
58
|
+
*/
|
|
59
|
+
addFloatArray(values: number[]): this;
|
|
60
|
+
/**
|
|
61
|
+
* Finalize and get the hash as a hex string
|
|
62
|
+
* @returns 8-character hex string (32-bit hash)
|
|
63
|
+
*/
|
|
64
|
+
finalize(): string;
|
|
65
|
+
/**
|
|
66
|
+
* Reset hasher to initial state (for reuse)
|
|
67
|
+
* @returns this (for chaining)
|
|
68
|
+
*/
|
|
69
|
+
reset(): this;
|
|
70
|
+
/**
|
|
71
|
+
* Create a new hasher (static factory)
|
|
72
|
+
* @returns New StateHasher instance
|
|
73
|
+
*/
|
|
74
|
+
static create(): StateHasher;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=StateHasher.d.ts.map
|