UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

63 lines (56 loc) 2.3 kB
import { assert } from "../../../core/assert.js"; import { clamp } from "../../../core/math/clamp.js"; /** * Server-side computation of "tell client to run a bit faster or slower." * * The server maintains a target depth for its per-client input buffer. When the * buffer is too shallow (client's inputs aren't arriving fast enough), the * server tells the client to run the next few ticks at a slightly compressed * tick duration ("speed up"). When the buffer is too deep (client is sending * inputs faster than the server consumes them), the server asks for stretching. * * This is the same primitive used in Overwatch ("time dilation") and Rocket * League. Adjustment is bounded to a few percent so it's imperceptible. * * Output is a multiplier on tick duration: * factor < 1.0 → run faster (smaller tick interval) * factor > 1.0 → run slower (larger tick interval) * factor = 1.0 → run at nominal rate * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class TimeDilation { /** * @param {{ * target_buffer_depth?: number, * max_dilation?: number, * gain?: number, * }} [options] */ constructor({ target_buffer_depth = 2, max_dilation = 0.05, gain = 0.05 } = {}) { assert.isNumber(target_buffer_depth, 'target_buffer_depth'); assert.isNumber(max_dilation, 'max_dilation'); assert.isNumber(gain, 'gain'); /** @readonly */ this.target_buffer_depth = target_buffer_depth; /** @readonly */ this.max_dilation = max_dilation; /** @readonly */ this.gain = gain; } /** * Compute the dilation factor for a client whose current input buffer depth * is `current_depth` (number of unconsumed input frames). * * @param {number} current_depth * @returns {number} factor in `[1 - max_dilation, 1 + max_dilation]` */ compute(current_depth) { assert.isNumber(current_depth, 'current_depth'); // depth > target ⇒ slow client down (factor > 1). depth < target ⇒ speed up (factor < 1). const raw = (current_depth - this.target_buffer_depth) * this.gain; const clamped = clamp(raw, -this.max_dilation, this.max_dilation); return 1.0 + clamped; } }