import type { SceneEntity } from "../scene/entityStore.js"; import type { StatValueMap } from "../scene/entityStats.js"; import type { WorldSnapshot } from "./worldSnapshot.js"; /** * A revision-stamped delta over a {@link WorldSnapshot}. The host sends one per tick to each client, carrying * only what changed since that client's last acknowledged revision — entity/stat/store deltas plus whole * snapshots of any other opted-in module (feed, leaderboard, chat, …) that changed. Fold it onto a prior * baseline with {@link applyWorldDiff}. */ export interface WorldDiff { revision: number; /** * The revision this diff was computed against — `sinceRevision` echoed back. A {@link WorldMirror} only applies * a diff whose `baseRevision` matches its own current revision exactly; a mismatch means frames were skipped and * the mirror must resync from a fresh baseline instead of silently drifting. Absent on a diff built by an older * producer — treated as legacy and always applied, matching pre-revision-checking behavior. */ baseRevision?: number; entities: readonly SceneEntity[]; removedEntities: readonly string[]; stats: Record; removedStats: readonly string[]; store: readonly (readonly [string, unknown])[]; removedStore: readonly string[]; /** Changed whole-module snapshots keyed by module name — everything a client can't reconstruct from deltas. */ modules: WorldSnapshot; /** Module keys present in a prior baseline that no longer exist — a client drops them wholesale on apply. */ removedModules: readonly string[]; } /** * Optional acceleration for {@link createWorldReplicator}: a monotone world-dirty counter (aggregated from * each {@link SnapshotModule.version}). When it hasn't advanced since the last commit nothing mutated, so the * replicator skips re-reading and re-serializing the whole world — the change-detection short-circuit item #28 * asks for. Omit it (or pass a snapshot-only source) to keep the original full-re-serialize-per-commit behavior. */ export interface WorldReplicatorOptions { worldVersion?: () => number; /** Cursor loaded with a persisted baseline; new commits continue above it. Default `0`. */ initialRevision?: number; } /** * Turns successive full {@link WorldSnapshot}s into per-client {@link WorldDiff}s. Each `commit()` re-reads the * world, stamps every item that changed with the new revision, and remembers removals; `diff(sinceRevision)` * then replays exactly the items stamped after that revision. Everything the tracker holds is JSON — the same * shape that rides the wire — so a diff is inherently serializable. Change-detection is a full re-serialize per * commit unless {@link WorldReplicatorOptions.worldVersion} lets an unchanged tick short-circuit before it. * @internal */ export declare function createWorldReplicator(takeSnapshot: () => WorldSnapshot, options?: WorldReplicatorOptions): { commit: () => number; diff: (sinceRevision: number) => WorldDiff; revision: () => number; }; /** The stateful diff tracker returned by {@link createWorldReplicator}: `commit()`, `diff(sinceRevision)`, `revision()`. */ export type WorldReplicator = ReturnType; /** * Diff two full {@link WorldSnapshot}s directly, stamping the result at `revision` — the stateless counterpart of * {@link createWorldReplicator} for hosts that persist snapshots rather than keep a live tracker (Convex reconstructs * per invocation). `applyWorldDiff(prev, diffSnapshots(prev, next, r))` reproduces `next`. `baseRevision`, when the * caller knows the revision `prev` was stamped at, lets a {@link WorldMirror} verify continuity the same way a * `createWorldReplicator` diff does; omitted, the diff is legacy/always-apply. * @internal */ export declare function diffSnapshots(prev: WorldSnapshot, next: WorldSnapshot, revision: number, baseRevision?: number): WorldDiff; /** * Fold a {@link WorldDiff} onto a prior {@link WorldSnapshot} baseline, returning the next full snapshot — the * client-side inverse of {@link createWorldReplicator}. Pure data in, pure data out: upserts changed entities, * stats and store keys, drops the removed ones, and replaces changed module snapshots wholesale. * @internal */ export declare function applyWorldDiff(baseline: WorldSnapshot, diff: WorldDiff): WorldSnapshot;