/**
 * Forwards action records between peers.
 *
 * **Send path** ({@link pack_for_peer}): walk the local action log over a
 * frame range, filter records by scope, and write a packet that contains
 * only the action portion of each record (no prior state — receivers don't
 * need it; their executors capture their own prior state).
 *
 * **Receive path** ({@link unpack_from_peer}): parse the packet, deserialize
 * each action via the registry, and run it through the local executor. The
 * executor logs it into the receiver's action log just like locally-originated
 * actions, capturing the receiver's prior state for its own rewind purposes.
 *
 * The Replicator is transport-agnostic: it produces and consumes
 * `BinaryBuffer`s. The orchestrator hands the produced buffer to a transport
 * and feeds the inbound buffer in the other direction.
 *
 * Wire format:
 * ```
 *   loop while bytes remain:
 *     varint:  frame_number
 *     varint:  action_count
 *     loop action_count times:
 *       uint8:   action_type_id
 *       uint32:  action_payload_len
 *       bytes:   action_payload
 * ```
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2025
 */
export class Replicator {
    /**
     * @param {{
     *   action_log: ActionLog,
     *   action_registry: SimActionRegistry,
     *   executor: SimActionExecutor,
     *   slot_table: ReplicationSlotTable,
     *   scope_filter: { is_entity_in_scope(peer_id: number, network_id: number): boolean },
     * }} options
     */
    constructor({ action_log, action_registry, executor, slot_table, scope_filter }: {
        action_log: ActionLog;
        action_registry: SimActionRegistry;
        executor: SimActionExecutor;
        slot_table: ReplicationSlotTable;
        scope_filter: {
            is_entity_in_scope(peer_id: number, network_id: number): boolean;
        };
    });
    /**
     * @type {ActionLog}
     */
    action_log: ActionLog;
    /**
     * @type {SimActionRegistry}
     */
    action_registry: SimActionRegistry;
    /**
     * @type {SimActionExecutor}
     */
    executor: SimActionExecutor;
    /**
     * @type {ReplicationSlotTable}
     */
    slot_table: ReplicationSlotTable;
    /**
     * Receives `network_id` (peer-shared) — NOT local `entity_id`. Replicator
     * translates via `slot_table.network_for(entity_id)` before calling.
     * @type {{ is_entity_in_scope(peer_id: number, network_id: number): boolean }}
     */
    scope_filter: {
        is_entity_in_scope(peer_id: number, network_id: number): boolean;
    };
    /**
     * Fired after each per-frame action group is fully applied via
     * {@link unpack_from_peer}. Args: `(peer_id, frame_number)`.
     *
     * Subscribe to drive interpolation buffers, replay logs, diagnostics,
     * or anything else that needs to know "frame N from peer P has just
     * been applied to the local world."
     *
     * Fires in frame-ascending order within a single packet (the order
     * the wire format encodes them in).
     *
     * @type {Signal}
     */
    onFrameApplied: Signal;
    /**
     * Optional deferral hook. When non-null, {@link unpack_from_peer}
     * does NOT touch the action log or executor — it parses the packet
     * and calls this function once per action with:
     *
     *   `(peer_id, frame_number, action_type_id, in_buffer, payload_offset, payload_len)`
     *
     * The buffer is shared scratch; consumers must copy the payload bytes
     * if they need them to outlive the call. The orchestrator is then
     * responsible for executing the buffered actions in whatever order
     * the netcode model requires (e.g. rewind to oldest frame, stable-
     * sort by sender, replay forward).
     *
     * Leave null for "execute on arrival" semantics (the default and
     * what the loopback/single-orchestrator tests rely on).
     *
     * @type {((peer_id: number, frame_number: number, action_type_id: number, in_buffer: BinaryBuffer, payload_offset: number, payload_len: number) => void) | null}
     */
    on_pending_action: (peer_id: number, frame_number: number, action_type_id: number, in_buffer: BinaryBuffer, payload_offset: number, payload_len: number) => void;
    /**
     * Pack actions from frames in `[start_frame, end_frame]` (inclusive) into
     * `out_buffer` for a given peer, applying the scope filter.
     *
     * Writes nothing if no in-scope actions are found.
     *
     * @param {number} peer_id
     * @param {number} start_frame inclusive; if no frame in range is in the log, that frame is skipped
     * @param {number} end_frame inclusive
     * @param {BinaryBuffer} out_buffer
     */
    pack_for_peer(peer_id: number, start_frame: number, end_frame: number, out_buffer: BinaryBuffer): void;
    /**
     * Parse and apply actions from `in_buffer` into the local world via the executor.
     * Each frame in the packet opens a new entry in the local action log under the
     * sender's frame number, ensuring the rewind/replay machinery sees consistent
     * frame indexing across peers.
     *
     * @param {number} peer_id
     * @param {BinaryBuffer} in_buffer
     * @param {number} in_buffer_end byte position to stop reading at
     */
    unpack_from_peer(peer_id: number, in_buffer: BinaryBuffer, in_buffer_end: number): void;
    #private;
}
import Signal from "../../../core/events/signal/Signal.js";
//# sourceMappingURL=Replicator.d.ts.map