@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
94 lines • 3.43 kB
TypeScript
/**
* Per-frame ring of action records.
*
* Each frame's `BinaryBuffer` holds a sequence of action records. One record per
* `SimActionExecutor.execute` call:
*
* ```
* varint: prior_state_count
* loop:
* varint: entity_id
* uint8: component_type_id (assigned by the ReplicatedComponentRegistry)
* uint32: prior_payload_len
* bytes: prior_payload (adapter.serialize of the component's prior state)
* uint8: action_type_id
* uint8: sender_id (peer that originated the action; local-only,
* STRIPPED by Replicator before send)
* uint32: action_payload_len
* bytes: action_payload (the action's own serialize output)
* ```
*
* Self-describing: records can be skipped without consulting the action registry,
* which means rewind code can walk records forward to find boundaries, then
* iterate backward to apply prior states — no need to instantiate any actions.
*
* Note that `sender_id` is recorded in-buffer for local rollback orchestrators
* (stable-sort tie-breaking by sender on replay) but never crosses the wire —
* {@link Replicator#pack_for_peer} strips it and the receiver derives sender
* from the inbound packet's peer_id, so a hostile peer cannot impersonate.
*
* Ring depth is set at construction. When the ring fills, the oldest frame's
* buffer is recycled for the new frame.
*
* @author Alex Goldring
* @copyright Company Named Limited (c) 2025
*/
export class ActionLog {
/**
* @param {{ frame_capacity: number, initial_buffer_size?: number }} options
*/
constructor({ frame_capacity, initial_buffer_size }: {
frame_capacity: number;
initial_buffer_size?: number;
});
/**
* @readonly
* @type {number}
*/
readonly frame_capacity: number;
/**
* Open a new frame for writing. Recycles the oldest slot if the ring is full.
*
* @param {number} frame absolute frame number
*/
begin_frame(frame: number): void;
/**
* Close the currently-open frame.
*/
end_frame(): void;
/**
* Get the buffer for the currently-open frame for direct writing.
*
* @returns {BinaryBuffer}
*/
current_buffer(): BinaryBuffer;
/**
* Has the given frame number ever been written, and is it still in the ring?
*
* @param {number} frame
* @returns {boolean}
*/
has_frame(frame: number): boolean;
/**
* Read-only access to a closed frame's buffer. Throws if the frame is not in the ring.
* The buffer's `position` will be set to 0 and its valid byte length is `write_end_for(frame)`.
*
* **Only valid for frames that have been closed via {@link end_frame}.** While a
* frame is open, `__write_ends[slot]` still holds the previous occupant's
* length — `buffer_for`/`write_end_for` would return mismatched
* buffer-contents-vs-length and any reader would walk garbage.
*
* @param {number} frame
* @returns {BinaryBuffer}
*/
buffer_for(frame: number): BinaryBuffer;
/**
* Number of valid bytes written to the given frame's buffer.
* @param {number} frame
* @returns {number}
*/
write_end_for(frame: number): number;
#private;
}
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
//# sourceMappingURL=ActionLog.d.ts.map