UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

85 lines (76 loc) 2.52 kB
import { assert } from "../../../core/assert.js"; /** * Tracks the boundary between confirmed and speculative frames. * * A frame is **confirmed** if its actions have been acknowledged by the * authoritative source (server, or remote peer in P2P) — meaning the frame * cannot be rewound away. A frame is **speculative** if it's been predicted * locally but not yet acked. * * Used for: * - **Side-effect gating.** One-shot effects (sounds, particle bursts, * scene transitions, brutalities) should only fire from confirmed frames; * speculative frames may be rolled back, and re-firing the effect on * replay produces the same audio/VFX glitch the MK X postmortem warned * about. * - **Garbage collection of action-log frames.** Frames at or below the * confirmed boundary will not be rewound to, so their action records * can be dropped from the ring once they fall out of the per-peer * baseline window too. * * Implementation is intentionally trivial: a single monotonic counter. * Frames `<= confirmed_through` are confirmed; frames `> confirmed_through` * are speculative. There is no per-frame metadata. * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class SpeculationLog { #confirmed_through; constructor() { /** * The most recent frame known to be confirmed. -1 if no frame has been confirmed yet. * @type {number} * @private */ this.#confirmed_through = -1; } /** * Advance the confirmed boundary. Monotonic: setting an older frame is a no-op. * @param {number} frame */ mark_confirmed(frame) { assert.isNonNegativeInteger(frame, 'frame'); if (frame > this.#confirmed_through) { this.#confirmed_through = frame; } } /** * @param {number} frame * @returns {boolean} */ is_confirmed(frame) { assert.isInteger(frame, 'frame'); return frame <= this.#confirmed_through; } /** * @param {number} frame * @returns {boolean} */ is_speculative(frame) { assert.isInteger(frame, 'frame'); return frame > this.#confirmed_through; } /** * @returns {number} the most recent confirmed frame, or -1 if none */ confirmed_through() { return this.#confirmed_through; } /** * Reset the log (e.g. on disconnect). */ reset() { this.#confirmed_through = -1; } }