UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

104 lines 4.13 kB
/** * Per-action-type priority accumulator for bandwidth-aware packet packing. * * Each action class is assigned a static priority at registration; per * tick, each type's accumulator grows by `priority * dt`. When the * outgoing packet's byte budget is tight, the orchestrator queries * {@link sorted_descending} to get types in priority-ranked order and * packs from highest down until the packet is full. Calling * {@link consume} after a type has been packed reduces its accumulator, * letting other types win the next tick — this is the starvation- * resistant scheduling pattern Glenn Fiedler's *Networked Physics* * series describes. * * Memory layout: two Float32Arrays indexed by `type_id` (assumed dense * starting at 0, matching the engine's `SimActionRegistry` numbering). * `tick` is a single pass over both arrays — cache-friendly and * allocation-free in steady state. * * Scope: this module is the data-structure half. Wiring it into * `Replicator.pack_for_peer` is the orchestrator's concern — the * prototype's tiny action volumes make integration unnecessary, but * a real production game with hundreds of replicated entities will * need the Replicator to consult {@link sorted_descending} when its * outgoing buffer approaches the MTU. * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class PriorityAccumulator { /** * @param {{ type_count: number }} options * `type_count` is the dense range `[0, type_count)` of action type_ids * the accumulator will track. Should be at least one more than the * highest registered type_id. */ constructor({ type_count }: { type_count: number; }); /** @readonly */ readonly type_count: number; /** * Set the static priority for a type. Typically called at action * registration (per type, once). Larger = more important. * * @param {number} type_id * @param {number} priority units are arbitrary; only relative magnitudes matter */ set_priority(type_id: number, priority: number): void; /** * @param {number} type_id * @returns {number} the configured static priority for this type */ priority(type_id: number): number; /** * Advance every accumulator by `priority * dt`. Call once per tick * before consulting {@link sorted_descending} / {@link consume}. * * @param {number} dt elapsed seconds (or any time unit consistent with * the priority units you configured) */ tick(dt: number): void; /** * Current accumulator value for a type. * @param {number} type_id * @returns {number} */ value(type_id: number): number; /** * Reduce a type's accumulator by `amount`. Clamped at 0 — a type's * accumulator never goes negative, so missing a single tick doesn't * permanently penalize it. Call after packing an action of this type * into an outgoing packet. * * @param {number} type_id * @param {number} amount */ consume(type_id: number, amount: number): void; /** * Clear a type's accumulator to 0. Useful when an entire backlog has * been packed (e.g. all pending actions of a type fit in one packet). * * @param {number} type_id */ reset(type_id: number): void; /** * Write type_ids to `out_array` in descending accumulator order. The * orchestrator then iterates `out_array` to know which types to pack * first. * * `out_array` must have capacity for `type_count` entries. Stable * within ties (insertion order = type_id ascending), so the result * is deterministic given the same accumulator state. * * @param {Int32Array|number[]} out_array */ sorted_descending(out_array: Int32Array | number[]): void; /** * Reset every accumulator to 0. Priorities are preserved. Use when * re-establishing fresh state (e.g. after a disconnect/reconnect). */ clear_accumulators(): void; #private; } //# sourceMappingURL=PriorityAccumulator.d.ts.map