/**
 * Client-side orchestrator for the predict-reconcile model.
 *
 * Encapsulates the algorithm previously inlined in
 * `app/src/prototype/network_prototype_prediction.js`:
 *
 *  - Per tick: sample input, store it in the {@link InputRing}, fire
 *    {@link onPredict} so the user's game code can execute SimAction(s)
 *    representing the input. The action gets recorded into the local
 *    action_log via the executor (capturing prior-state for later rewind),
 *    and goes out over the action stream when `peer.end_tick` flushes it.
 *
 *  - On AUTH_STATE arrival: rewind the world to end-of-(server_frame - 1)
 *    via the {@link RewindEngine}, deserialize the server's authoritative
 *    state bytes via {@link onApplyAuthState}, then replay forward by
 *    firing {@link onReplay} for every frame in the InputRing between
 *    `server_frame + 1` and the client's current frame. The user's
 *    {@link onReplay} handler re-executes the same SimActions the original
 *    predict path produced.
 *
 *  - A no-op short-circuit is built in: before doing the rewind+replay, the
 *    orchestrator gives the user a chance to compute what the replay WOULD
 *    produce via {@link onComputeExpected}; if that matches the current
 *    local state within a tolerance, the rewind is skipped entirely. This
 *    keeps the steady-state reconciliation loop from oscillating.
 *
 * The orchestrator does NOT bake in input encoding — the user provides
 * serialize/deserialize/apply hooks. This keeps `MovePlayerAction` (and
 * any other input action shape) decoupled from the orchestrator.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2025
 */
export class ServerAuthoritativeClient {
    /**
     * @param {{
     *   world: EntityComponentDataset,
     *   binary_registry: BinarySerializationRegistry,
     *   replicated_components: Function[],
     *   action_classes: Function[],
     *   scope_filter?: object,
     *   frame_capacity?: number,
     *   initial_buffer_size?: number,
     *   input_ring_capacity?: number,
     *   input_byte_size?: number,
     *   reconcile_epsilon?: number,
     *   time_dilation?: TimeDilation,
     * }} options
     *
     * `time_dilation`: optional pre-configured {@link TimeDilation}.
     * On TIME_DILATION feedback the client recomputes
     * {@link dilation_factor} for the caller to scale its tick cadence.
     * Defaults to a stock instance; `dilation_factor` is 1.0 until the
     * first feedback arrives.
     */
    constructor({ world, binary_registry, replicated_components, action_classes, scope_filter, frame_capacity, initial_buffer_size, input_ring_capacity, input_byte_size, reconcile_epsilon, time_dilation, }: {
        world: EntityComponentDataset;
        binary_registry: BinarySerializationRegistry;
        replicated_components: Function[];
        action_classes: Function[];
        scope_filter?: object;
        frame_capacity?: number;
        initial_buffer_size?: number;
        input_ring_capacity?: number;
        input_byte_size?: number;
        reconcile_epsilon?: number;
        time_dilation?: TimeDilation;
    });
    /** @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;
    /**
     * Per-frame input ring. Sized to hold roughly 2× RTT_in_frames of
     * history so reconciliation can always find the inputs to replay.
     * @type {InputRing}
     */
    input_ring: InputRing;
    /** @type {RewindEngine} */
    rewind_engine: RewindEngine;
    /**
     * Tolerance for the no-op reconciliation short-circuit. If the user's
     * {@link onComputeExpected} returns a state that matches the local
     * state to within this epsilon, the rewind+replay is skipped.
     * @type {number}
     */
    reconcile_epsilon: number;
    /** @type {number} */
    reconcile_count: number;
    /** @type {number} */
    replay_frame_count: number;
    /**
     * Adaptive tick-rate controller. Server sends observed input-buffer
     * depth via the TIME_DILATION packet; this maps it to a tick-period
     * multiplier {@link dilation_factor}.
     * @type {TimeDilation}
     */
    time_dilation: TimeDilation;
    /**
     * Most recent buffer depth reported by the server. -1 before any
     * feedback has arrived.
     * @type {number}
     */
    last_buffer_depth: number;
    /**
     * Tick-period multiplier from the latest TIME_DILATION feedback.
     * `< 1.0` ⇒ caller should run faster, `> 1.0` ⇒ slower. 1.0 until
     * the first feedback arrives.
     *
     *   scheduled_tick_period_ms = TICK_PERIOD_MS * client.dilation_factor;
     *
     * @type {number}
     */
    dilation_factor: number;
    /**
     * Fires once per tick during prediction. Args: `(frame_number,
     * input_writer)` where `input_writer(write_fn)` records the input
     * bytes into the InputRing. The user's handler should:
     *   1. Sample input.
     *   2. Write input bytes via `input_writer(buf => buf.writeXxx(...))`.
     *   3. Execute SimAction(s) representing the input via
     *      `client.executor.execute(action)`.
     * @type {Signal}
     */
    onPredict: Signal;
    /**
     * Fires once per frame during reconciliation replay. Args:
     * `(frame_number, input_reader)` where `input_reader` is a
     * BinaryBuffer positioned at the start of that frame's stored
     * input bytes (or `null` if the frame's input wasn't recorded —
     * the handler must short-circuit in that case). The user's handler
     * should re-execute the SAME SimAction(s) that the predict handler
     * produced for the input.
     * @type {Signal}
     */
    onReplay: Signal;
    /**
     * Fires when AUTH_STATE arrives, BEFORE the rewind+replay is
     * decided. Args: `(server_frame, network_id, buffer)`.
     *
     * The handler should peek at the server's bytes (the buffer is
     * positioned at the start of the auth payload; the handler may
     * advance and restore `buffer.position`) and compute what the
     * client's predicted state at the *current* frame WOULD be if a
     * full rewind+replay were performed, returning a 1D scalar or
     * `null` to skip the short-circuit. The orchestrator compares
     * the returned value to {@link onMeasureCurrent}'s return value
     * and short-circuits the rewind if they match within
     * {@link reconcile_epsilon}.
     *
     * Game code that doesn't want the optimization can simply not
     * subscribe to this; the rewind+replay then runs unconditionally.
     *
     * @type {Signal}
     */
    onComputeExpected: Signal;
    /**
     * Fires alongside {@link onComputeExpected} to measure the current
     * local state for comparison. Args: `(network_id)`. Returns a
     * scalar.
     * @type {Signal}
     */
    onMeasureCurrent: Signal;
    /**
     * Fires inside __handle_auth_state AFTER the no-op short-circuit
     * decided a rewind is needed but BEFORE the rewind starts.
     * Args: `(server_frame, network_id)`. Used by higher-level wiring
     * (e.g. {@link NetworkSession}) to bring the live world into
     * canonical form before `RewindEngine.rewind_to` reads it.
     * @type {Signal}
     */
    onBeforeReconcile: Signal;
    /**
     * Fires on AUTH_STATE arrival, after the no-op check decided to
     * actually do the rewind+replay. Args: `(server_frame,
     * network_id, buffer)` where buffer is positioned at the auth
     * payload bytes. The handler should deserialize the bytes into
     * the world (the rewind has already happened; the buffer's bytes
     * ARE the new authoritative state at server_frame).
     * @type {Signal}
     */
    onApplyAuthState: Signal;
    /**
     * Fires after each completed reconciliation (rewind + apply + replay).
     * Diagnostic. Args: `(server_frame, replay_count)`.
     * @type {Signal}
     */
    onReconcileComplete: Signal;
    /**
     * Connect to a server peer over a transport.
     * @param {number} peer_id
     * @param {object} transport
     */
    connect_to_server(peer_id: number, transport: object): void;
    /**
     * Disconnect from a server peer.
     * @param {number} peer_id
     */
    disconnect_from_server(peer_id: number): void;
    /** Channel accessor for manual packet plumbing.
     * @param {number} peer_id */
    channel_for(peer_id: number): import("../transport/Channel.js").Channel;
    /**
     * Run one client-side prediction tick.
     *
     * 1. Open action_log frame.
     * 2. Fire {@link onPredict} so the user samples input, records it in the
     *    InputRing, and executes SimAction(s).
     * 3. Close action_log frame (this flushes the action stream to all
     *    connected peers via `peer.end_tick`).
     *
     * @param {number} current_frame
     */
    tick(current_frame: number): void;
    /**
     * Whether the InputRing has stored input bytes for the given frame.
     * Useful in {@link onReplay} handlers that need to short-circuit
     * frames with no recorded input.
     *
     * @param {number} frame
     * @returns {boolean}
     */
    has_input_for(frame: number): boolean;
    /**
     * Read-only access to the InputRing buffer for a given frame. Position
     * is reset to 0 by the call.
     *
     * @param {number} frame
     * @returns {BinaryBuffer}
     */
    input_for(frame: number): BinaryBuffer;
    /**
     * Helper for the {@link onComputeExpected} handler: stash the
     * computed scalar so the orchestrator can read it. Called inside the
     * handler.
     * @param {number} value
     */
    set_expected(value: number): void;
    /**
     * Helper for the {@link onMeasureCurrent} handler: stash the measured
     * scalar so the orchestrator can read it. Called inside the handler.
     * @param {number} value
     */
    set_measured(value: number): void;
    #private;
}
import { NetworkPeer } from "./NetworkPeer.js";
import { InputRing } from "../state/InputRing.js";
import { RewindEngine } from "../sim/RewindEngine.js";
import { TimeDilation } from "../time/TimeDilation.js";
import Signal from "../../../core/events/signal/Signal.js";
//# sourceMappingURL=ServerAuthoritativeClient.d.ts.map