import type { Schema } from "../Schema.js"; import { TypeContext } from "../types/TypeContext.js"; import type { Iterator } from "../encoding/decode.js"; import { Root } from "./Root.js"; import { type StateView } from "./StateView.js"; export declare class Encoder { /** * Per-encoder shared output buffer size. The encoder auto-grows on * overflow and logs a one-time warning suggesting a higher value, so * the default just needs to comfortably cover typical room state. * * Sized to fit ~100 items in a `MapSchema<{x,y,z}>` keyed by * `nanoid(9)` (~4.5 KB worst-case full encode, float64-heavy) with * ~3-4× headroom for surrounding state (player list, world refs, * etc.). Raise per app via `Encoder.BUFFER_SIZE = N * 1024` before * constructing any Encoder. */ static BUFFER_SIZE: number; sharedBuffer: Uint8Array; context: TypeContext; state: T; root: Root; constructor(state: T, root?: Root); protected setState(state: T): void; private _encodeCtx; /** * Monotonic counter bumped at the start of every `encodeFullSync` * call. The new value is copied to `ctx.gen` and stamped into every * tree the walk touches (`tree._fullSyncGen = ctx.gen`); subsequent * revisits of the same tree detect the equality and return early. */ private _fullSyncGen; encode(it?: Iterator, view?: StateView, buffer?: Uint8Array, initialOffset?: number): Uint8Array; /** * Per-tick encode of the UNRELIABLE channel. Walks `root.unreliableChanges` * and emits each tree's `unreliableRecorder`. Safe to call at a different * cadence than `encode()` (e.g. 60Hz vs 20Hz) — the two channels are * fully independent. */ encodeUnreliable(it?: Iterator, view?: StateView, buffer?: Uint8Array, initialOffset?: number): Uint8Array; private _encodeChannel; /** * Structural DFS walker for full-sync (encodeAll / encodeAllView). * Visits each ChangeTree in DFS preorder starting from the state root, * emitting ADD operations for every currently-populated index via * {@link ChangeTree.forEachLive}. */ private encodeFullSync; private _resizeBuffer; encodeAll(it?: Iterator, buffer?: Uint8Array): Uint8Array; encodeAllView(view: StateView, sharedOffset: number, it: Iterator, bytes?: Uint8Array): Uint8Array; /** Grow `buffer` to keep BUFFER_SIZE free bytes past `offset`, preserving `[0, offset)`. */ protected ensureCapacity(buffer: Uint8Array, offset: number): Uint8Array; encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes?: Uint8Array): Uint8Array; /** * Per-view unreliable encode. Walks `root.unreliableChanges` and emits * only filtered fields visible to this view. Unlike `encodeView`, this * doesn't emit `view.changes` entries — those are used only for * reliable view bootstrap (membership ADDs) and are consumed by * `encodeView` on the reliable channel. */ encodeUnreliableView(view: StateView, sharedOffset: number, it: Iterator, bytes?: Uint8Array): Uint8Array; /** * Broadcast-mode counterpart to `_emitStreamPriority`. Runs when NO * StateViews are registered — streams fall back to broadcast mode * where up to `maxPerTick` pending ADDs per stream emit to ALL clients * each shared tick. DELETEs always flush (no cap). * * Emits directly to the shared-encode buffer: stream & element trees * are `isFiltered=true` so the main loop would otherwise skip them. * Runs AFTER the main loop so state / parent refs are already encoded * — stream ADD ops reference element refIds, which must be decodable. */ private _emitStreamBroadcast; /** * Walk every registered stream, pick up to `maxPerTick` positions from * this view's pending backlog (priority-sorted when the view supplies a * `streamPriority` callback), and hand each element to `view.add()`. * `view.add()` seeds `view.changes` so the subsequent drain emits both * the stream-link (position → refId) and the element's field data. * * Designed to run at the very top of `encodeView`, BEFORE the * view.changes drain loop. */ private _emitStreamPriority; discardChanges(): void; discardUnreliableChanges(): void; tryEncodeTypeId(bytes: Uint8Array, baseType: typeof Schema, targetType: typeof Schema, it: Iterator): void; /** * True when the next `encode()` / `encodeView()` has something to send, * including a stream backlog still draining under `maxPerTick` while * the rest of the state is idle. */ get hasChanges(): boolean; private get _isStreamBroadcastMode(); private _hasStreamBacklog; get hasUnreliableChanges(): boolean; }