import type { LiveRoom } from './EditorMapReader'; export type Bounds = { minX: number; maxX: number; minY: number; maxY: number; }; /** Window that materialises everything — the state before the renderer pushes one. */ export declare const INFINITE_BOUNDS: Bounds; /** * Uniform spatial hash over one plane's rooms, supporting in-place updates. * * The renderer's own `PlaneIndex` (see `mudlet-map-renderer/bigmap`) is a * counting-sort over immutable typed arrays — rebuilding it costs O(plane), * which is fine for a read-only skeleton but not here, where a drag moves rooms * on every pointer event. This variant trades the compact layout for O(1) * add/remove/move: each room remembers the cell it was filed under, so * {@link update} re-files it without the caller tracking its old coordinates. */ export declare class PlaneRoomIndex { private readonly cells; /** Cell each room currently sits in, by room id. */ private readonly filed; private revision; constructor(rooms: readonly LiveRoom[]); /** Bumped whenever membership or any room's cell changes — cache key for query results. */ getRevision(): number; add(room: LiveRoom): void; remove(room: LiveRoom): void; /** * Re-file `room` after its coordinates changed. Cheap no-op while a drag stays * inside one cell, which is the common case. */ update(room: LiveRoom): void; /** Every room whose centre lies inside `b`. Exact — each candidate is bounds-tested. */ forEachInBounds(b: Bounds, fn: (room: LiveRoom) => void): void; collectInBounds(b: Bounds): LiveRoom[]; /** * Cheap UPPER BOUND on the rooms inside `b`: whole-cell occupancy, no per-room * test. Edge cells contribute rooms that are actually outside, so this must * not be used where an exact count matters. */ countInBounds(b: Bounds): number; /** * Buckets that overlap `b`. Walking the cell rectangle is the fast path, but * an unbounded (or simply very zoomed-out) window can span more cells than the * plane has occupied ones — then iterating occupancy is strictly cheaper. */ private bucketsFor; }