import type { LodBand, LodSchedulerState } from "../world/lod.js"; /** * Simulation culling is a SEPARATE, opt-in system from render culling. Render culling only * decides what is drawn; this decides whether a low-priority off-screen entity updates this * tick. It is disabled by default and never throttles a protected entity — physics-critical, * networking-critical, audio-critical, scripted, or explicitly-active entities always update. * Gameplay correctness must never depend on an entity being on-screen, so opt in only where * skipping updates is provably safe. */ export interface SimulationCullingOptions { /** Off by default. */ readonly enabled?: boolean; /** Distance bands → update interval (seconds). Nearer bands update every tick; far bands throttle. */ readonly bands?: readonly LodBand[]; /** Interval for entities beyond the last band. null = never throttle (still update). Default null. */ readonly beyondInterval?: number | null; /** Return true for entities that must never be throttled (physics/net/audio/scripted/active). */ readonly isProtected?: (id: string) => boolean; } export interface SimulationDecision { /** Whether the entity should run its update this tick. */ update: boolean; /** Seconds of accumulated time delivered when `update` is true (for catch-up integration). */ elapsed: number; } /** Plain JSON state of a {@link SimulationCuller}: the enabled flag and each id's throttle accumulator. */ export interface SimulationCullerState { enabled: boolean; scheduler: LodSchedulerState; } export interface SimulationCuller { enabled(): boolean; setEnabled(value: boolean): void; /** Decide whether `id` at `distance` from the nearest camera updates this tick. */ step(id: string, distance: number, dt: number): SimulationDecision; forget(id: string): void; clear(): void; snapshot(): SimulationCullerState; restore(next: SimulationCullerState): void; } export declare function createSimulationCuller(options?: SimulationCullingOptions): SimulationCuller;