rollback-netcode 0.0.4

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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/dist/debug.d.ts +29 -0
  4. package/dist/debug.d.ts.map +1 -0
  5. package/dist/debug.js +56 -0
  6. package/dist/debug.js.map +1 -0
  7. package/dist/index.d.ts +62 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +57 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/protocol/encoding.d.ts +80 -0
  12. package/dist/protocol/encoding.d.ts.map +1 -0
  13. package/dist/protocol/encoding.js +992 -0
  14. package/dist/protocol/encoding.js.map +1 -0
  15. package/dist/protocol/messages.d.ts +271 -0
  16. package/dist/protocol/messages.d.ts.map +1 -0
  17. package/dist/protocol/messages.js +114 -0
  18. package/dist/protocol/messages.js.map +1 -0
  19. package/dist/rollback/engine.d.ts +261 -0
  20. package/dist/rollback/engine.d.ts.map +1 -0
  21. package/dist/rollback/engine.js +543 -0
  22. package/dist/rollback/engine.js.map +1 -0
  23. package/dist/rollback/input-buffer.d.ts +225 -0
  24. package/dist/rollback/input-buffer.d.ts.map +1 -0
  25. package/dist/rollback/input-buffer.js +483 -0
  26. package/dist/rollback/input-buffer.js.map +1 -0
  27. package/dist/rollback/snapshot-buffer.d.ts +119 -0
  28. package/dist/rollback/snapshot-buffer.d.ts.map +1 -0
  29. package/dist/rollback/snapshot-buffer.js +256 -0
  30. package/dist/rollback/snapshot-buffer.js.map +1 -0
  31. package/dist/session/desync-manager.d.ts +106 -0
  32. package/dist/session/desync-manager.d.ts.map +1 -0
  33. package/dist/session/desync-manager.js +136 -0
  34. package/dist/session/desync-manager.js.map +1 -0
  35. package/dist/session/lag-monitor.d.ts +69 -0
  36. package/dist/session/lag-monitor.d.ts.map +1 -0
  37. package/dist/session/lag-monitor.js +74 -0
  38. package/dist/session/lag-monitor.js.map +1 -0
  39. package/dist/session/message-builders.d.ts +86 -0
  40. package/dist/session/message-builders.d.ts.map +1 -0
  41. package/dist/session/message-builders.js +199 -0
  42. package/dist/session/message-builders.js.map +1 -0
  43. package/dist/session/message-router.d.ts +61 -0
  44. package/dist/session/message-router.d.ts.map +1 -0
  45. package/dist/session/message-router.js +105 -0
  46. package/dist/session/message-router.js.map +1 -0
  47. package/dist/session/player-manager.d.ts +100 -0
  48. package/dist/session/player-manager.d.ts.map +1 -0
  49. package/dist/session/player-manager.js +160 -0
  50. package/dist/session/player-manager.js.map +1 -0
  51. package/dist/session/session.d.ts +379 -0
  52. package/dist/session/session.d.ts.map +1 -0
  53. package/dist/session/session.js +1294 -0
  54. package/dist/session/session.js.map +1 -0
  55. package/dist/session/topology.d.ts +66 -0
  56. package/dist/session/topology.d.ts.map +1 -0
  57. package/dist/session/topology.js +72 -0
  58. package/dist/session/topology.js.map +1 -0
  59. package/dist/transport/adapter.d.ts +99 -0
  60. package/dist/transport/adapter.d.ts.map +1 -0
  61. package/dist/transport/adapter.js +8 -0
  62. package/dist/transport/adapter.js.map +1 -0
  63. package/dist/transport/local.d.ts +192 -0
  64. package/dist/transport/local.d.ts.map +1 -0
  65. package/dist/transport/local.js +435 -0
  66. package/dist/transport/local.js.map +1 -0
  67. package/dist/transport/transforming.d.ts +177 -0
  68. package/dist/transport/transforming.d.ts.map +1 -0
  69. package/dist/transport/transforming.js +407 -0
  70. package/dist/transport/transforming.js.map +1 -0
  71. package/dist/transport/webrtc.d.ts +285 -0
  72. package/dist/transport/webrtc.d.ts.map +1 -0
  73. package/dist/transport/webrtc.js +734 -0
  74. package/dist/transport/webrtc.js.map +1 -0
  75. package/dist/types.d.ts +394 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +256 -0
  78. package/dist/types.js.map +1 -0
  79. package/dist/utils/rate-limiter.d.ts +59 -0
  80. package/dist/utils/rate-limiter.d.ts.map +1 -0
  81. package/dist/utils/rate-limiter.js +93 -0
  82. package/dist/utils/rate-limiter.js.map +1 -0
  83. package/package.json +61 -0
@@ -0,0 +1,483 @@
1
+ /**
2
+ * Per-player input tracking with support for dynamic join/leave.
3
+ *
4
+ * Tracks received inputs, confirmed ticks, and used (predicted) inputs
5
+ * to enable misprediction detection during rollback.
6
+ */
7
+ import { asTick } from "../types.js";
8
+ /**
9
+ * Compares two Uint8Arrays for equality.
10
+ */
11
+ function inputsEqual(a, b) {
12
+ if (a.length !== b.length)
13
+ return false;
14
+ for (let i = 0; i < a.length; i++) {
15
+ if (a[i] !== b[i])
16
+ return false;
17
+ }
18
+ return true;
19
+ }
20
+ /**
21
+ * Buffer for tracking inputs from all players.
22
+ *
23
+ * Supports:
24
+ * - Dynamic player join/leave
25
+ * - Out-of-order input reception
26
+ * - Misprediction detection
27
+ * - Confirmed tick tracking
28
+ */
29
+ export class InputBuffer {
30
+ players = new Map();
31
+ /** Index of players by their join tick for O(1) lookup */
32
+ joinsByTick = new Map();
33
+ /** Index of players by their leave tick for O(1) lookup */
34
+ leavesByTick = new Map();
35
+ /**
36
+ * Add a player to the buffer.
37
+ *
38
+ * @param playerId - The player's ID
39
+ * @param joinTick - The tick at which the player joins
40
+ */
41
+ addPlayer(playerId, joinTick) {
42
+ const existing = this.players.get(playerId);
43
+ if (existing) {
44
+ // If player is rejoining, update join tick and clear leave tick
45
+ if (existing.leaveTick !== null) {
46
+ // Remove from old join tick index
47
+ this.removeFromTickIndex(this.joinsByTick, existing.joinTick, playerId);
48
+ // Remove from leave tick index
49
+ this.removeFromTickIndex(this.leavesByTick, existing.leaveTick, playerId);
50
+ existing.joinTick = joinTick;
51
+ existing.leaveTick = null;
52
+ existing.confirmedTick = asTick(joinTick - 1);
53
+ existing.received.clear();
54
+ existing.usedInputs.clear();
55
+ // Add to new join tick index
56
+ this.addToTickIndex(this.joinsByTick, joinTick, playerId);
57
+ }
58
+ return;
59
+ }
60
+ this.players.set(playerId, {
61
+ joinTick,
62
+ leaveTick: null,
63
+ received: new Map(),
64
+ confirmedTick: asTick(joinTick - 1), // No inputs confirmed yet
65
+ usedInputs: new Map(),
66
+ });
67
+ // Add to join tick index
68
+ this.addToTickIndex(this.joinsByTick, joinTick, playerId);
69
+ }
70
+ /**
71
+ * Mark a player as having left.
72
+ *
73
+ * @param playerId - The player's ID
74
+ * @param leaveTick - The tick at which the player leaves
75
+ */
76
+ removePlayer(playerId, leaveTick) {
77
+ const player = this.players.get(playerId);
78
+ if (player) {
79
+ // Remove from old leave tick index if they had one
80
+ if (player.leaveTick !== null) {
81
+ this.removeFromTickIndex(this.leavesByTick, player.leaveTick, playerId);
82
+ }
83
+ player.leaveTick = leaveTick;
84
+ // Add to leave tick index
85
+ this.addToTickIndex(this.leavesByTick, leaveTick, playerId);
86
+ }
87
+ }
88
+ /**
89
+ * Set the confirmed tick for all active players to a specific value.
90
+ * Used after a state sync to indicate that all inputs up to that tick
91
+ * are implicitly confirmed by the synced state.
92
+ *
93
+ * @param tick - The tick to set as confirmed for all active players
94
+ */
95
+ setConfirmedTickForSync(tick) {
96
+ // Guard against underflow when tick is 0 or negative
97
+ if (tick <= 0) {
98
+ return;
99
+ }
100
+ const confirmedTick = asTick(tick - 1);
101
+ for (const player of this.players.values()) {
102
+ // Only update if the player was active at or before this tick
103
+ if (player.leaveTick === null || player.leaveTick > tick) {
104
+ // Set confirmed tick to tick-1 (the state represents confirmed state)
105
+ if (player.confirmedTick < confirmedTick) {
106
+ player.confirmedTick = confirmedTick;
107
+ }
108
+ }
109
+ }
110
+ }
111
+ /**
112
+ * Check if a player is active at a given tick.
113
+ *
114
+ * @param playerId - The player's ID
115
+ * @param tick - The tick to check
116
+ * @returns true if the player is active at that tick
117
+ */
118
+ isPlayerActive(playerId, tick) {
119
+ const player = this.players.get(playerId);
120
+ if (!player)
121
+ return false;
122
+ if (tick < player.joinTick)
123
+ return false;
124
+ if (player.leaveTick !== null && tick >= player.leaveTick)
125
+ return false;
126
+ return true;
127
+ }
128
+ /**
129
+ * Get all players that are active at a given tick.
130
+ *
131
+ * @param tick - The tick to check
132
+ * @returns Array of active player IDs
133
+ */
134
+ getActivePlayers(tick) {
135
+ const active = [];
136
+ for (const [playerId] of this.players) {
137
+ if (this.isPlayerActive(playerId, tick)) {
138
+ active.push(playerId);
139
+ }
140
+ }
141
+ return active;
142
+ }
143
+ /**
144
+ * Get all player IDs (active or not).
145
+ *
146
+ * @returns Array of all player IDs
147
+ */
148
+ getAllPlayers() {
149
+ return Array.from(this.players.keys());
150
+ }
151
+ /**
152
+ * Receive an input from a player.
153
+ * The input is copied to prevent external mutation.
154
+ *
155
+ * @param playerId - The player's ID
156
+ * @param tick - The tick the input is for
157
+ * @param input - The input data
158
+ */
159
+ receiveInput(playerId, tick, input) {
160
+ const player = this.players.get(playerId);
161
+ if (!player)
162
+ return;
163
+ // Don't accept inputs for ticks before the player joined
164
+ if (tick < player.joinTick)
165
+ return;
166
+ // Don't accept inputs for ticks after the player left
167
+ if (player.leaveTick !== null && tick >= player.leaveTick)
168
+ return;
169
+ // Copy input to prevent external mutation
170
+ const inputCopy = new Uint8Array(input.length);
171
+ inputCopy.set(input);
172
+ player.received.set(tick, inputCopy);
173
+ // Update confirmed tick (highest consecutive tick with input)
174
+ this.updateConfirmedTick(player);
175
+ }
176
+ /**
177
+ * Update the confirmed tick for a player.
178
+ * Confirmed tick is the highest tick where all ticks from joinTick
179
+ * to that tick have received inputs.
180
+ */
181
+ updateConfirmedTick(player) {
182
+ let tick = player.confirmedTick + 1;
183
+ while (player.received.has(asTick(tick))) {
184
+ tick++;
185
+ }
186
+ player.confirmedTick = asTick(tick - 1);
187
+ }
188
+ /**
189
+ * Get the received input for a player at a specific tick.
190
+ *
191
+ * @param playerId - The player's ID
192
+ * @param tick - The tick to get input for
193
+ * @returns The input, or undefined if not received
194
+ */
195
+ getInput(playerId, tick) {
196
+ const player = this.players.get(playerId);
197
+ if (!player)
198
+ return undefined;
199
+ return player.received.get(tick);
200
+ }
201
+ /**
202
+ * Get the confirmed tick for a player.
203
+ * This is the highest consecutive tick for which we have received input.
204
+ *
205
+ * @param playerId - The player's ID
206
+ * @returns The confirmed tick, or undefined if player not found
207
+ */
208
+ getConfirmedTick(playerId) {
209
+ const player = this.players.get(playerId);
210
+ if (!player)
211
+ return undefined;
212
+ return player.confirmedTick;
213
+ }
214
+ /**
215
+ * Get the join tick for a player.
216
+ *
217
+ * @param playerId - The player's ID
218
+ * @returns The join tick, or undefined if player not found
219
+ */
220
+ getJoinTick(playerId) {
221
+ const player = this.players.get(playerId);
222
+ return player?.joinTick;
223
+ }
224
+ /**
225
+ * Get the leave tick for a player.
226
+ *
227
+ * @param playerId - The player's ID
228
+ * @returns The leave tick, or null/undefined if player hasn't left or not found
229
+ */
230
+ getLeaveTick(playerId) {
231
+ const player = this.players.get(playerId);
232
+ return player?.leaveTick;
233
+ }
234
+ /**
235
+ * Record the input that was actually used for a player at a tick.
236
+ * This may be the real input or a predicted input.
237
+ *
238
+ * @param playerId - The player's ID
239
+ * @param tick - The tick
240
+ * @param input - The input that was used
241
+ */
242
+ recordUsedInput(playerId, tick, input) {
243
+ const player = this.players.get(playerId);
244
+ if (!player)
245
+ return;
246
+ // Copy input
247
+ const inputCopy = new Uint8Array(input.length);
248
+ inputCopy.set(input);
249
+ player.usedInputs.set(tick, inputCopy);
250
+ }
251
+ /**
252
+ * Get the input that was used for a player at a tick.
253
+ *
254
+ * @param playerId - The player's ID
255
+ * @param tick - The tick
256
+ * @returns The used input, or undefined if not recorded
257
+ */
258
+ getUsedInput(playerId, tick) {
259
+ const player = this.players.get(playerId);
260
+ if (!player)
261
+ return undefined;
262
+ return player.usedInputs.get(tick);
263
+ }
264
+ /**
265
+ * Find the first tick where a misprediction occurred for a player.
266
+ * A misprediction is when we used a predicted input that differs
267
+ * from the actual received input.
268
+ *
269
+ * @param playerId - The player's ID
270
+ * @param fromTick - Start searching from this tick
271
+ * @returns The tick of the first misprediction, or undefined if none found
272
+ */
273
+ findMisprediction(playerId, fromTick) {
274
+ const player = this.players.get(playerId);
275
+ if (!player)
276
+ return undefined;
277
+ // Check each tick from fromTick up to confirmedTick
278
+ for (let tick = fromTick; tick <= player.confirmedTick; tick++) {
279
+ const received = player.received.get(asTick(tick));
280
+ const used = player.usedInputs.get(asTick(tick));
281
+ // If we have both received and used inputs, compare them
282
+ if (received !== undefined && used !== undefined) {
283
+ if (!inputsEqual(received, used)) {
284
+ return asTick(tick);
285
+ }
286
+ }
287
+ }
288
+ return undefined;
289
+ }
290
+ /**
291
+ * Check if there are any mispredictions for a player in a tick range.
292
+ *
293
+ * @param playerId - The player's ID
294
+ * @param fromTick - Start of range (inclusive)
295
+ * @param toTick - End of range (inclusive)
296
+ * @returns true if any misprediction found
297
+ */
298
+ hasMisprediction(playerId, fromTick, toTick) {
299
+ const player = this.players.get(playerId);
300
+ if (!player)
301
+ return false;
302
+ for (let tick = fromTick; tick <= toTick; tick++) {
303
+ const received = player.received.get(asTick(tick));
304
+ const used = player.usedInputs.get(asTick(tick));
305
+ if (received !== undefined && used !== undefined) {
306
+ if (!inputsEqual(received, used)) {
307
+ return true;
308
+ }
309
+ }
310
+ }
311
+ return false;
312
+ }
313
+ /**
314
+ * Get the last confirmed input for a player.
315
+ * Useful for input prediction.
316
+ *
317
+ * @param playerId - The player's ID
318
+ * @returns The last confirmed input, or undefined if none
319
+ */
320
+ getLastConfirmedInput(playerId) {
321
+ const player = this.players.get(playerId);
322
+ if (!player)
323
+ return undefined;
324
+ // Return input at confirmedTick, not just any received input
325
+ // confirmedTick is the highest consecutive tick with input
326
+ if (player.confirmedTick >= player.joinTick) {
327
+ return player.received.get(player.confirmedTick);
328
+ }
329
+ return undefined;
330
+ }
331
+ /**
332
+ * Remove all data before a given tick.
333
+ * Used to clean up old inputs that are no longer needed.
334
+ *
335
+ * @param tick - Remove all data for ticks < this value
336
+ */
337
+ pruneBeforeTick(tick) {
338
+ for (const player of this.players.values()) {
339
+ // Remove old received inputs
340
+ for (const t of player.received.keys()) {
341
+ if (t < tick) {
342
+ player.received.delete(t);
343
+ }
344
+ }
345
+ // Remove old used inputs
346
+ for (const t of player.usedInputs.keys()) {
347
+ if (t < tick) {
348
+ player.usedInputs.delete(t);
349
+ }
350
+ }
351
+ }
352
+ }
353
+ /**
354
+ * Clear used inputs for a player from a given tick onwards.
355
+ * Called during rollback to allow re-recording inputs.
356
+ *
357
+ * @param playerId - The player's ID
358
+ * @param fromTick - Clear from this tick onwards
359
+ */
360
+ clearUsedInputsFrom(playerId, fromTick) {
361
+ const player = this.players.get(playerId);
362
+ if (!player)
363
+ return;
364
+ for (const tick of player.usedInputs.keys()) {
365
+ if (tick >= fromTick) {
366
+ player.usedInputs.delete(tick);
367
+ }
368
+ }
369
+ }
370
+ /**
371
+ * Clear all used inputs from a given tick onwards for all players.
372
+ *
373
+ * @param fromTick - Clear from this tick onwards
374
+ */
375
+ clearAllUsedInputsFrom(fromTick) {
376
+ for (const playerId of this.players.keys()) {
377
+ this.clearUsedInputsFrom(playerId, fromTick);
378
+ }
379
+ }
380
+ /**
381
+ * Get the minimum confirmed tick across all active players at a given tick.
382
+ *
383
+ * @param tick - The reference tick for determining active players
384
+ * @returns The minimum confirmed tick, or undefined if no active players
385
+ */
386
+ getMinConfirmedTick(tick) {
387
+ let minTick;
388
+ for (const [playerId, player] of this.players) {
389
+ if (this.isPlayerActive(playerId, tick)) {
390
+ if (minTick === undefined || player.confirmedTick < minTick) {
391
+ minTick = player.confirmedTick;
392
+ }
393
+ }
394
+ }
395
+ return minTick;
396
+ }
397
+ /**
398
+ * Check if we have all inputs for a given tick from all active players.
399
+ *
400
+ * @param tick - The tick to check
401
+ * @returns true if all inputs are available
402
+ */
403
+ hasAllInputsForTick(tick) {
404
+ for (const [playerId] of this.players) {
405
+ if (this.isPlayerActive(playerId, tick)) {
406
+ if (!this.getInput(playerId, tick)) {
407
+ return false;
408
+ }
409
+ }
410
+ }
411
+ return true;
412
+ }
413
+ /**
414
+ * Clear all data for a player.
415
+ *
416
+ * @param playerId - The player's ID
417
+ */
418
+ clearPlayer(playerId) {
419
+ const player = this.players.get(playerId);
420
+ if (player) {
421
+ // Remove from tick indexes
422
+ this.removeFromTickIndex(this.joinsByTick, player.joinTick, playerId);
423
+ if (player.leaveTick !== null) {
424
+ this.removeFromTickIndex(this.leavesByTick, player.leaveTick, playerId);
425
+ }
426
+ }
427
+ this.players.delete(playerId);
428
+ }
429
+ /**
430
+ * Clear all players and data.
431
+ */
432
+ clear() {
433
+ this.players.clear();
434
+ this.joinsByTick.clear();
435
+ this.leavesByTick.clear();
436
+ }
437
+ /**
438
+ * Get all players that join at a specific tick.
439
+ * O(1) lookup using tick-indexed map.
440
+ *
441
+ * @param tick - The tick to check
442
+ * @returns Array of player IDs joining at this tick
443
+ */
444
+ getPlayersJoiningAtTick(tick) {
445
+ const players = this.joinsByTick.get(tick);
446
+ return players ? Array.from(players) : [];
447
+ }
448
+ /**
449
+ * Get all players that leave at a specific tick.
450
+ * O(1) lookup using tick-indexed map.
451
+ *
452
+ * @param tick - The tick to check
453
+ * @returns Array of player IDs leaving at this tick
454
+ */
455
+ getPlayersLeavingAtTick(tick) {
456
+ const players = this.leavesByTick.get(tick);
457
+ return players ? Array.from(players) : [];
458
+ }
459
+ /**
460
+ * Add a player to a tick index.
461
+ */
462
+ addToTickIndex(index, tick, playerId) {
463
+ let players = index.get(tick);
464
+ if (!players) {
465
+ players = new Set();
466
+ index.set(tick, players);
467
+ }
468
+ players.add(playerId);
469
+ }
470
+ /**
471
+ * Remove a player from a tick index.
472
+ */
473
+ removeFromTickIndex(index, tick, playerId) {
474
+ const players = index.get(tick);
475
+ if (players) {
476
+ players.delete(playerId);
477
+ if (players.size === 0) {
478
+ index.delete(tick);
479
+ }
480
+ }
481
+ }
482
+ }
483
+ //# sourceMappingURL=input-buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-buffer.js","sourceRoot":"","sources":["../../src/rollback/input-buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Ring buffer for storing game state snapshots.
3
+ *
4
+ * Used for rollback: when a misprediction is detected, the game state
5
+ * is restored from a snapshot and resimulated forward.
6
+ */
7
+ import type { Snapshot, Tick } from "../types.js";
8
+ /**
9
+ * A ring buffer that stores game state snapshots for rollback.
10
+ *
11
+ * Snapshots are stored at specific ticks and can be retrieved by tick.
12
+ * When the buffer is full, the oldest snapshot is evicted.
13
+ * Uses a tick-to-index map for O(1) lookup performance.
14
+ *
15
+ * INVARIANT: Snapshots must be saved in ascending tick order. This is required
16
+ * for O(log n) binary search in getAtOrBefore(). The invariant is maintained by:
17
+ * - Normal simulation: ticks advance sequentially (0, 1, 2, ...)
18
+ * - Resimulation: existing ticks are updated in-place, preserving order
19
+ *
20
+ * Saving a non-existing tick out of order will corrupt the sort order and
21
+ * cause getAtOrBefore() to return incorrect results.
22
+ */
23
+ export declare class SnapshotBuffer {
24
+ readonly capacity: number;
25
+ private readonly buffer;
26
+ private readonly tickToIndex;
27
+ private head;
28
+ private count;
29
+ private _oldestTick;
30
+ private _newestTick;
31
+ /**
32
+ * Create a new snapshot buffer.
33
+ *
34
+ * @param capacity - Maximum number of snapshots to store
35
+ */
36
+ constructor(capacity: number);
37
+ /**
38
+ * Number of snapshots currently stored.
39
+ */
40
+ get size(): number;
41
+ /**
42
+ * The oldest tick in the buffer, or undefined if empty.
43
+ */
44
+ get oldestTick(): Tick | undefined;
45
+ /**
46
+ * The newest tick in the buffer, or undefined if empty.
47
+ */
48
+ get newestTick(): Tick | undefined;
49
+ /**
50
+ * Save a snapshot at a specific tick.
51
+ *
52
+ * If the tick already exists, updates in-place to maintain sort order.
53
+ * If the buffer is full, the oldest snapshot is evicted.
54
+ * The state is copied to prevent external mutation.
55
+ *
56
+ * PRECONDITION: New ticks (not already in buffer) must be >= all existing ticks.
57
+ * Saving an out-of-order new tick corrupts sort order. See class invariant.
58
+ *
59
+ * @param tick - The tick this snapshot was taken at
60
+ * @param state - The serialized game state
61
+ * @param hash - The hash of the game state
62
+ */
63
+ save(tick: Tick, state: Uint8Array, hash: number): void;
64
+ /**
65
+ * Get a snapshot at a specific tick.
66
+ * Uses O(1) map lookup for performance.
67
+ *
68
+ * @param tick - The tick to retrieve
69
+ * @returns The snapshot at that tick, or undefined if not found
70
+ */
71
+ get(tick: Tick): Snapshot | undefined;
72
+ /**
73
+ * Get the oldest snapshot in the buffer.
74
+ *
75
+ * @returns The oldest snapshot, or undefined if empty
76
+ */
77
+ getOldest(): Snapshot | undefined;
78
+ /**
79
+ * Get the newest snapshot in the buffer.
80
+ *
81
+ * @returns The newest snapshot, or undefined if empty
82
+ */
83
+ getNewest(): Snapshot | undefined;
84
+ /**
85
+ * Clear all snapshots from the buffer.
86
+ */
87
+ clear(): void;
88
+ /**
89
+ * Get the snapshot at or before a given tick.
90
+ * Useful for finding the closest snapshot for rollback.
91
+ *
92
+ * O(log n) binary search. Snapshots are stored in ascending tick order.
93
+ *
94
+ * @param tick - The target tick
95
+ * @returns The snapshot at or before that tick, or undefined if none exists
96
+ */
97
+ getAtOrBefore(tick: Tick): Snapshot | undefined;
98
+ /**
99
+ * Remove all snapshots before a given tick.
100
+ * Used to clean up old snapshots that are no longer needed.
101
+ *
102
+ * @param tick - Remove all snapshots with tick < this value
103
+ */
104
+ pruneBeforeTick(tick: Tick): void;
105
+ /**
106
+ * Check if a snapshot exists at a given tick.
107
+ *
108
+ * @param tick - The tick to check
109
+ * @returns true if a snapshot exists at that tick
110
+ */
111
+ has(tick: Tick): boolean;
112
+ /**
113
+ * Get all ticks that have snapshots, in order from oldest to newest.
114
+ *
115
+ * @returns Array of ticks with snapshots
116
+ */
117
+ getTicks(): Tick[];
118
+ }
119
+ //# sourceMappingURL=snapshot-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-buffer.d.ts","sourceRoot":"","sources":["../../src/rollback/snapshot-buffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAc;aAaE,QAAQ,EAAE,MAAM;IAZ5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgC;IAC5D,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,WAAW,CAAmB;IAEtC;;;;OAIG;gBACyB,QAAQ,EAAE,MAAM;IAO5C;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,IAAI,GAAG,SAAS,CAEjC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,IAAI,GAAG,SAAS,CAEjC;IAED;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAsDvD;;;;;;OAMG;IACH,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,GAAG,SAAS;IAQrC;;;;OAIG;IACH,SAAS,IAAI,QAAQ,GAAG,SAAS;IAOjC;;;;OAIG;IACH,SAAS,IAAI,QAAQ,GAAG,SAAS;IAQjC;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;;;;;;;OAQG;IACH,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,GAAG,SAAS;IA6B/C;;;;;OAKG;IACH,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAqBjC;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;IAIxB;;;;OAIG;IACH,QAAQ,IAAI,IAAI,EAAE;CAWlB"}