@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
84 lines (75 loc) • 2.3 kB
JavaScript
import { assert } from "../../../core/assert.js";
/**
* Per-peer "last acknowledged frame" tracker.
*
* The replicator sends actions for frames `[Baseline.last_acked(peer) + 1, current]`
* to each peer. When the peer's ack arrives (via the {@link Channel}), it
* advances the baseline.
*
* Frame numbers are absolute uint32. At 60 Hz, 2^32 frames = 2.27 years —
* we can ignore wraparound for practical sessions and use plain `>` comparison.
*
* @author Alex Goldring
* @copyright Company Named Limited (c) 2025
*/
export class Baseline {
#last_acked;
constructor() {
/**
* peer_id -> last acked frame number
* @type {Map<number, number>}
* @private
*/
this.#last_acked = new Map();
}
/**
* Record that `peer_id` has acknowledged through `frame`. Monotonic: out-of-order
* acks (for an older frame than already recorded) are ignored.
*
* @param {number} peer_id
* @param {number} frame
*/
set_acked(peer_id, frame) {
assert.isNonNegativeInteger(peer_id, 'peer_id');
assert.isNonNegativeInteger(frame, 'frame');
const current = this.#last_acked.get(peer_id);
if (current === undefined || frame > current) {
this.#last_acked.set(peer_id, frame);
}
}
/**
* Returns the most recent acknowledged frame for `peer_id`, or -1 if none.
*
* @param {number} peer_id
* @returns {number}
*/
last_acked(peer_id) {
assert.isNonNegativeInteger(peer_id, 'peer_id');
const v = this.#last_acked.get(peer_id);
return v === undefined ? -1 : v;
}
/**
* Forget tracking for `peer_id` (e.g. on disconnect).
*
* @param {number} peer_id
*/
forget(peer_id) {
assert.isNonNegativeInteger(peer_id, 'peer_id');
this.#last_acked.delete(peer_id);
}
/**
* Number of tracked peers.
* @returns {number}
*/
peer_count() {
return this.#last_acked.size;
}
/**
* Iterate (peer_id, last_acked_frame) pairs.
* @param {function(number, number): void} fn
*/
for_each(fn) {
assert.isFunction(fn, 'fn');
this.#last_acked.forEach((frame, peer_id) => fn(peer_id, frame));
}
}