/**
 * Server-authoritative orchestrator with deterministic per-tick rollback.
 *
 * Encapsulates the algorithm previously inlined in
 * `app/src/prototype/network_prototype_prediction.js`:
 *
 *   1. Inbound action packets do NOT execute on arrival. Instead, a deferral
 *      hook on the {@link Replicator} drops them into a per-tick pending log
 *      tagged with `(client_frame, sender_id, type_id, payload_bytes)`.
 *   2. Once per server tick, `tick(current_frame)` consumes the pending log:
 *      - Rejects entries older than the action_log's rewindable window.
 *      - Determines the oldest pending frame `replay_start`.
 *      - Rewinds the server world back to end-of-(replay_start - 1) via the
 *        action_log's prior-state captures (see {@link RewindEngine}).
 *      - Replays forward `[replay_start, current_frame]`. For each frame `f`:
 *        - Read historical actions out of `action_log[f]` BEFORE
 *          `begin_frame(f)` recycles the buffer.
 *        - Append pending entries for `f`.
 *        - Stable-sort the merged list by `sender_id` (so multi-client order
 *          is deterministic across peers — relies on per-record sender_id in
 *          the action log).
 *        - `executor.execute` each in sorted order, then run the user-
 *          supplied local sim via {@link onLocalSim}.
 *      - Clear pending.
 *
 * Net effect: a client action tagged at client tick K lands on the server as
 * if applied against end-of-K-1 server state, regardless of arrival timing
 * or order. Both peers compute identical world states for identical inputs.
 *
 * The user wires this orchestrator up by:
 *   1. Constructing with a world, replication setup, and (typically) an
 *      {@link OwnerAwareScope} filter so client-owned-entity actions are
 *      not echoed back.
 *   2. Calling {@link connect_peer} for each connected client.
 *   3. Subscribing to {@link onLocalSim} for per-frame server-side game logic
 *      (e.g. clamps, physics, collision) and {@link onTickComplete} for
 *      end-of-tick work (e.g. sending AUTH_STATE).
 *   4. Calling {@link tick} once per server frame.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2025
 */
export class ServerAuthoritativeServer {
    /**
     * @param {{
     *   world: EntityComponentDataset,
     *   binary_registry: BinarySerializationRegistry,
     *   replicated_components: Function[],
     *   action_classes: Function[],
     *   scope_filter?: object,
     *   frame_capacity?: number,
     *   initial_buffer_size?: number,
     *   simulation_delay_ticks?: number,
     * }} options
     *
     * `simulation_delay_ticks`: server-side input buffer (Overwatch-style).
     * When > 0, {@link tick}(wall_frame) simulates
     * `sim_frame = wall_frame - simulation_delay_ticks`. Pending actions
     * tagged for `> sim_frame` stay queued and apply when `sim_frame`
     * catches up — most client actions land before the server needs
     * them, so rollback rarely fires. Costs N ticks of perceived
     * input-to-feedback latency (client prediction hides it). Default 0
     * reproduces pre-feature behavior.
     */
    constructor({ world, binary_registry, replicated_components, action_classes, scope_filter, frame_capacity, initial_buffer_size, simulation_delay_ticks, }: {
        world: EntityComponentDataset;
        binary_registry: BinarySerializationRegistry;
        replicated_components: Function[];
        action_classes: Function[];
        scope_filter?: object;
        frame_capacity?: number;
        initial_buffer_size?: number;
        simulation_delay_ticks?: number;
    });
    /** @type {NetworkPeer} */
    peer: NetworkPeer;
    /** @type {EntityComponentDataset} */
    world: EntityComponentDataset;
    /** @type {SimActionExecutor} */
    executor: SimActionExecutor;
    /** @type {ReplicationSlotTable} */
    slot_table: ReplicationSlotTable;
    /** @type {ActionLog} */
    action_log: ActionLog;
    /** @type {SimActionRegistry} */
    action_registry: SimActionRegistry;
    /** @type {ReplicatedComponentRegistry} */
    component_registry: ReplicatedComponentRegistry;
    /** @type {RewindEngine} */
    rewind_engine: RewindEngine;
    /**
     * Highest client-tagged frame received (across all peers).
     * RECEIPT semantic — under `simulation_delay_ticks > 0` this
     * may be ahead of {@link current_sim_frame}. Tag AUTH_STATE
     * with `current_sim_frame`, not this.
     * @type {number}
     */
    last_client_frame_processed: number;
    /**
     * Number of ticks the server's simulation lags behind the caller's
     * wall frame. See constructor doc.
     * @type {number}
     */
    simulation_delay_ticks: number;
    /**
     * Most recently simulated frame. `-1` during warmup
     * (`wall_frame < simulation_delay_ticks`), advances by 1 per
     * `tick()` after.
     * @type {number}
     */
    current_sim_frame: number;
    /**
     * Fires once per frame during the replay loop, AFTER all merged
     * actions for that frame have been applied and BEFORE the action_log
     * frame is closed. Use this for server-authoritative local sim
     * (clamps, collision, AI step, etc.). The current world state
     * reflects all inputs for this frame; the local sim should be
     * idempotent under repeated application (because it may run many
     * times under rollback).
     *
     * Args: `(frame_number)`.
     * @type {Signal}
     */
    onLocalSim: Signal;
    /**
     * Fires after `tick()` completes (pending drained, all frames in the
     * replay window applied). Use for end-of-tick work: sending
     * AUTH_STATE, recording diagnostics, etc.
     *
     * Args: `(current_frame)`.
     * @type {Signal}
     */
    onTickComplete: Signal;
    /**
     * Fired when a tick triggers an actual rewind (i.e. the replay
     * window includes already-committed frames). Args:
     *   `(committed_top, replay_target, depth)` where depth is
     *   `committed_top - replay_target` (number of frames undone).
     *
     * Diagnostic: counts rollbacks and characterizes how deep they
     * went, which directly maps to how late client actions arrived.
     * Tick paths that ran without a rewind (steady-state, no pending
     * for past frames) do NOT fire this.
     * @type {Signal}
     */
    onRewind: Signal;
    /**
     * Connect a client peer over a transport. Subsequent action packets from
     * this peer will be buffered in the pending log via the deferral hook
     * and consumed on the next `tick()`.
     *
     * @param {number} peer_id
     * @param {object} transport
     */
    connect_peer(peer_id: number, transport: object): void;
    /**
     * Disconnect a previously-connected peer.
     * @param {number} peer_id
     */
    disconnect_peer(peer_id: number): void;
    /**
     * Forward to {@link NetworkPeer#send_auth_state}. Typically called from
     * an {@link onTickComplete} subscriber.
     *
     * @param {number} peer_id
     * @param {number} frame_number
     * @param {number} network_id
     * @param {(buf: BinaryBuffer) => void} write_fn
     */
    send_auth_state(peer_id: number, frame_number: number, network_id: number, write_fn: (buf: BinaryBuffer) => void): void;
    /**
     * Channel accessor for the user's manual packet plumbing (e.g. sending
     * empty ACK packets in the prototype). Most callers won't need this.
     * @param {number} peer_id
     */
    channel_for(peer_id: number): import("../transport/Channel.js").Channel;
    /**
     * Send the current buffer-depth observation for one peer to that peer.
     * Convenience wrapper around {@link NetworkPeer#send_time_dilation_feedback}
     * that pulls the depth from {@link buffer_depth_for_peer}. Typically
     * invoked once per tick (or every few ticks) from an
     * {@link onTickComplete} subscriber.
     *
     * @param {number} peer_id
     */
    send_time_dilation_feedback(peer_id: number): void;
    /**
     * Drive the rollback flow for one tick.
     *
     * With `simulation_delay_ticks = 0` (default), simulates the caller's
     * `wall_frame` and drains pending. With `> 0`, simulates
     * `sim_frame = wall_frame - simulation_delay_ticks` and holds
     * `frame > sim_frame` pending until the sim catches up. Warmup
     * (`sim_frame < 0`) is a no-op; `onTickComplete` does not fire.
     *
     * `onTickComplete` fires with `sim_frame` (not `wall_frame`).
     *
     * @param {number} current_frame the caller's wall frame
     */
    tick(current_frame: number): void;
    /**
     * Current input-buffer depth for a peer: `max_received_frame - current_sim_frame`.
     * Positive ⇒ peer is sending ahead of sim (good); zero/negative ⇒
     * peer is falling behind. Returns 0 if no inputs from this peer.
     * During warmup returns the count of received frames.
     *
     * @param {number} peer_id
     * @returns {number}
     */
    buffer_depth_for_peer(peer_id: number): number;
    #private;
}
import { NetworkPeer } from "./NetworkPeer.js";
import { RewindEngine } from "../sim/RewindEngine.js";
import Signal from "../../../core/events/signal/Signal.js";
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
//# sourceMappingURL=ServerAuthoritativeServer.d.ts.map