@carverjs/multiplayer 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +154 -0
  2. package/dist/InputBuffer-J6XT_Tt0.d.mts +61 -0
  3. package/dist/InputBuffer-V7XfHbc6.d.ts +61 -0
  4. package/dist/{NetworkManager-nvVAOr1O.d.ts → NetworkManager-D-DxFgdM.d.mts} +66 -14
  5. package/dist/{NetworkManager-DrKM2tEx.d.mts → NetworkManager-DH9uGVMg.d.ts} +66 -14
  6. package/dist/{chunk-UD6FDZMX.mjs → chunk-GOTAQDBJ.mjs} +47 -4
  7. package/dist/chunk-GOTAQDBJ.mjs.map +1 -0
  8. package/dist/{chunk-3KT73N2S.mjs → chunk-LPNEP2VH.mjs} +0 -0
  9. package/dist/chunk-LPNEP2VH.mjs.map +1 -0
  10. package/dist/{chunk-EO3YNPRQ.mjs → chunk-Q25TJEY4.mjs} +494 -204
  11. package/dist/chunk-Q25TJEY4.mjs.map +1 -0
  12. package/dist/{firebase-CPu87KA0.d.ts → firebase-B5MgLlHk.d.ts} +6 -1
  13. package/dist/{firebase-PE6MxGdJ.d.mts → firebase-GrbVrNgs.d.mts} +6 -1
  14. package/dist/index.d.mts +27 -6
  15. package/dist/index.d.ts +27 -6
  16. package/dist/index.js +821 -258
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +172 -37
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/strategy.d.mts +2 -2
  21. package/dist/strategy.d.ts +2 -2
  22. package/dist/strategy.js +46 -3
  23. package/dist/strategy.js.map +1 -1
  24. package/dist/strategy.mjs +1 -1
  25. package/dist/sync.d.mts +134 -50
  26. package/dist/sync.d.ts +134 -50
  27. package/dist/sync.js +499 -205
  28. package/dist/sync.js.map +1 -1
  29. package/dist/sync.mjs +15 -3
  30. package/dist/transport.d.mts +0 -0
  31. package/dist/transport.d.ts +0 -0
  32. package/dist/transport.js +0 -0
  33. package/dist/transport.js.map +1 -1
  34. package/dist/transport.mjs +2 -2
  35. package/dist/{types-5LHBOW08.d.mts → types-hNfCIBzj.d.mts} +7 -0
  36. package/dist/{types-5LHBOW08.d.ts → types-hNfCIBzj.d.ts} +7 -0
  37. package/dist/types.d.mts +2 -2
  38. package/dist/types.d.ts +2 -2
  39. package/dist/types.js.map +1 -1
  40. package/package.json +26 -5
  41. package/dist/chunk-3KT73N2S.mjs.map +0 -1
  42. package/dist/chunk-EO3YNPRQ.mjs.map +0 -1
  43. package/dist/chunk-UD6FDZMX.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/MultiplayerProvider.ts","../src/core/TickKeeper.ts","../src/core/codec.ts","../src/core/NetworkManager.ts","../src/core/MultiplayerContext.ts","../src/components/MultiplayerBridge.ts","../src/hooks/useRoom.ts","../src/hooks/useLobby.ts","../src/hooks/usePlayers.ts","../src/hooks/useHost.ts","../src/hooks/useMultiplayer.ts","../src/core/NetworkSimulator.ts","../src/hooks/useNetworkEvents.ts","../src/hooks/useNetworkState.ts","../src/core/DebugOverlay.ts","../src/core/InterestManager.ts"],"sourcesContent":["import { createElement, useRef, useEffect } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { StrategyConfig } from \"../transport/strategy/types\";\nimport { MqttStrategy } from \"../transport/strategy/mqtt\";\nimport { FirebaseStrategy } from \"../transport/strategy/firebase\";\nimport { NetworkManager } from \"../core/NetworkManager\";\nimport { MultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { MultiplayerContextValue } from \"../core/MultiplayerContext\";\nimport type { SignalingStrategy } from \"../transport/strategy/types\";\n\nexport interface MultiplayerProviderProps {\n /**\n * Unique application identifier. Used to namespace rooms across the\n * signaling network so different games don't interfere.\n */\n appId: string;\n /**\n * Signaling strategy configuration. Defaults to MQTT (free public brokers).\n *\n * ```tsx\n * // Free (MQTT, zero config)\n * <MultiplayerProvider appId=\"my-game\">\n *\n * // Firebase (your own project)\n * <MultiplayerProvider\n * appId=\"my-game\"\n * strategy={{ type: 'firebase', databaseURL: 'https://my-project.firebaseio.com' }}\n * >\n * ```\n */\n strategy?: StrategyConfig;\n /**\n * ICE servers (STUN + TURN). Defaults to public Google/Cloudflare STUN.\n *\n * To add your own TURN server (e.g. Cloudflare TURN):\n * ```tsx\n * <MultiplayerProvider\n * appId=\"my-game\"\n * iceServers={[\n * { urls: 'stun:stun.cloudflare.com:3478' },\n * { urls: 'turn:turn.cloudflare.com:3478', username: '...', credential: '...' },\n * ]}\n * >\n * ```\n */\n iceServers?: RTCIceServer[];\n children: ReactNode;\n}\n\nfunction createStrategy(appId: string, config?: StrategyConfig): SignalingStrategy {\n if (!config || config.type === 'mqtt') {\n return new MqttStrategy(appId, config ?? { type: 'mqtt' });\n }\n if (config.type === 'firebase') {\n return new FirebaseStrategy(appId, config);\n }\n throw new Error(`Unknown strategy type: ${(config as any).type}`);\n}\n\nexport function MultiplayerProvider({\n appId,\n strategy: strategyConfig,\n iceServers,\n children,\n}: MultiplayerProviderProps) {\n const managerRef = useRef<NetworkManager | null>(null);\n const strategyRef = useRef<SignalingStrategy | null>(null);\n\n if (!managerRef.current) {\n managerRef.current = new NetworkManager();\n }\n if (!strategyRef.current) {\n strategyRef.current = createStrategy(appId, strategyConfig);\n }\n\n useEffect(() => {\n return () => {\n strategyRef.current?.destroy();\n strategyRef.current = null;\n managerRef.current?.destroy();\n managerRef.current = null;\n };\n }, []);\n\n const value: MultiplayerContextValue = {\n appId,\n strategy: strategyRef.current,\n iceServers,\n networkManager: managerRef.current,\n };\n\n return createElement(MultiplayerContext.Provider, { value }, children);\n}\n","/**\n * Accumulator-based fixed timestep with drift-aware time dilation.\n * Adapted from lumbernet's LumberTickKeeper.\n */\nexport class TickKeeper {\n private _tickRate: number;\n private _tickDelta: number;\n private _accumulator = 0;\n private _tick = 0;\n private _serverTick = 0;\n private _alpha = 0;\n private _timeScale = 1;\n\n // Drift correction zones\n private static readonly DRIFT_BEHIND_THRESHOLD = -5;\n private static readonly DRIFT_AHEAD_THRESHOLD = 5;\n private static readonly SPEED_UP_SCALE = 1.5;\n private static readonly SLOW_DOWN_SCALE = 0.1;\n private static readonly NORMAL_SCALE = 1.0;\n\n constructor(tickRate = 60) {\n this._tickRate = tickRate;\n this._tickDelta = 1 / tickRate;\n }\n\n get tick(): number {\n return this._tick;\n }\n\n get serverTick(): number {\n return this._serverTick;\n }\n\n get tickDelta(): number {\n return this._tickDelta;\n }\n\n get tickRate(): number {\n return this._tickRate;\n }\n\n /** Interpolation alpha for rendering between ticks (0-1) */\n get alpha(): number {\n return this._alpha;\n }\n\n /** Current time scale (affected by drift correction) */\n get timeScale(): number {\n return this._timeScale;\n }\n\n /** Ticks ahead of server (positive = ahead, negative = behind) */\n get drift(): number {\n return this._tick - this._serverTick;\n }\n\n /** Update server tick from received snapshot */\n setServerTick(serverTick: number): void {\n this._serverTick = serverTick;\n this._updateDriftCorrection();\n }\n\n /**\n * Accumulate time and return the number of fixed ticks to process.\n * Call this once per render frame with the raw frame delta.\n */\n update(rawDelta: number): number {\n // Cap delta to prevent spiral-of-death (e.g., after tab switch)\n const maxDelta = this._tickDelta * 8;\n const delta = Math.min(rawDelta, maxDelta) * this._timeScale;\n\n this._accumulator += delta;\n\n let ticksThisFrame = 0;\n while (this._accumulator >= this._tickDelta) {\n this._accumulator -= this._tickDelta;\n this._tick++;\n ticksThisFrame++;\n }\n\n // Compute interpolation alpha\n this._alpha = this._accumulator / this._tickDelta;\n\n return ticksThisFrame;\n }\n\n /** Reset to initial state */\n reset(): void {\n this._accumulator = 0;\n this._tick = 0;\n this._serverTick = 0;\n this._alpha = 0;\n this._timeScale = 1;\n }\n\n /** Set tick rate (updates tickDelta accordingly) */\n setTickRate(rate: number): void {\n this._tickRate = rate;\n this._tickDelta = 1 / rate;\n }\n\n private _updateDriftCorrection(): void {\n const drift = this.drift;\n if (drift < TickKeeper.DRIFT_BEHIND_THRESHOLD) {\n // Too far behind server -- speed up\n this._timeScale = TickKeeper.SPEED_UP_SCALE;\n } else if (drift > TickKeeper.DRIFT_AHEAD_THRESHOLD) {\n // Too far ahead of server -- slow down\n this._timeScale = TickKeeper.SLOW_DOWN_SCALE;\n } else {\n // Healthy zone\n this._timeScale = TickKeeper.NORMAL_SCALE;\n }\n }\n}\n","import { pack, unpack } from \"msgpackr\";\nimport type { EntityState, EntityState2D, EntityState3D } from \"../types\";\n\n/** Configuration for delta thresholds */\nexport interface DeltaThresholds {\n position: number;\n rotation: number;\n velocity: number;\n custom: 'strict' | number;\n}\n\n/** Quantization config: number of decimal places to keep */\nexport interface QuantizeConfig {\n position?: number;\n rotation?: number;\n velocity?: number;\n}\n\nconst DEFAULT_THRESHOLDS: DeltaThresholds = {\n position: 0.01,\n rotation: 0.001,\n velocity: 0.05,\n custom: 'strict',\n};\n\n/**\n * Snapshot ring buffer: stores recent snapshots for delta computation.\n */\nexport class SnapshotBuffer {\n private _buffer: Map<number, Map<string, EntityState>>; // tick -> (entityId -> state)\n private _capacity: number;\n\n constructor(capacity = 120) {\n this._capacity = capacity;\n this._buffer = new Map();\n }\n\n /** Store a snapshot at the given tick */\n store(tick: number, entities: Map<string, EntityState>): void {\n this._buffer.set(tick, entities);\n // Evict old entries by iterating actual keys (handles non-contiguous ticks)\n if (this._buffer.size > this._capacity) {\n const sortedTicks = Array.from(this._buffer.keys()).sort((a, b) => a - b);\n const toRemove = sortedTicks.length - this._capacity;\n for (let i = 0; i < toRemove; i++) {\n this._buffer.delete(sortedTicks[i]);\n }\n }\n }\n\n /** Get a snapshot at the given tick */\n get(tick: number): Map<string, EntityState> | undefined {\n return this._buffer.get(tick);\n }\n\n /** Clear all stored snapshots */\n clear(): void {\n this._buffer.clear();\n }\n}\n\n/**\n * Codec handles serialization and delta compression for network state.\n */\nexport class Codec {\n private _thresholds: DeltaThresholds;\n private _quantize: QuantizeConfig | undefined;\n private _is2D: boolean;\n\n constructor(options?: {\n thresholds?: Partial<DeltaThresholds>;\n quantize?: QuantizeConfig;\n is2D?: boolean;\n }) {\n this._thresholds = { ...DEFAULT_THRESHOLDS, ...options?.thresholds };\n this._quantize = options?.quantize;\n this._is2D = options?.is2D ?? false;\n }\n\n /** Serialize entity states to binary (msgpackr) */\n serialize(entities: EntityState[]): Uint8Array {\n const quantized = this._quantize ? entities.map(e => this._quantizeEntity(e)) : entities;\n return pack(quantized);\n }\n\n /** Deserialize binary to entity states */\n deserialize(data: Uint8Array): EntityState[] {\n return unpack(data) as EntityState[];\n }\n\n /**\n * Compute delta: only include entities that changed beyond thresholds\n * since the baseline snapshot.\n * Returns null if nothing changed.\n */\n computeDelta(\n current: Map<string, EntityState>,\n baseline: Map<string, EntityState> | undefined,\n ): EntityState[] | null {\n // No baseline = keyframe (send everything)\n if (!baseline) {\n return Array.from(current.values());\n }\n\n const changed: EntityState[] = [];\n for (const [id, entity] of current) {\n const prev = baseline.get(id);\n if (!prev || this._hasChanged(entity, prev)) {\n changed.push(entity);\n }\n }\n\n // Include removed entities as tombstones (entities in baseline but not in current)\n // Tombstones are indicated by entities with only an id field\n for (const id of baseline.keys()) {\n if (!current.has(id)) {\n // Tombstone: minimal entity state signaling removal\n if (this._is2D) {\n changed.push({ id, x: 0, y: 0, a: 0, vx: 0, vy: 0, va: 0, c: { __removed: true } } as EntityState2D);\n } else {\n changed.push({ id, x: 0, y: 0, z: 0, qx: 0, qy: 0, qz: 0, qw: 1, vx: 0, vy: 0, vz: 0, wx: 0, wy: 0, wz: 0, c: { __removed: true } } as EntityState3D);\n }\n }\n }\n\n return changed.length > 0 ? changed : null;\n }\n\n /** Serialize a delta snapshot packet */\n serializeDelta(\n tick: number,\n baseTick: number,\n current: Map<string, EntityState>,\n baseline: Map<string, EntityState> | undefined,\n ): Uint8Array | null {\n const delta = this.computeDelta(current, baseline);\n if (!delta) return null;\n\n const packet = {\n t: tick,\n b: baseline ? baseTick : -1, // -1 = keyframe\n s: this.serialize(delta),\n };\n\n return pack(packet);\n }\n\n /** Deserialize a snapshot packet */\n deserializePacket(data: Uint8Array): { tick: number; baseTick: number; entities: EntityState[] } {\n const packet = unpack(data) as { t: number; b: number; s: Uint8Array };\n return {\n tick: packet.t,\n baseTick: packet.b,\n entities: this.deserialize(packet.s),\n };\n }\n\n private _hasChanged(current: EntityState, prev: EntityState): boolean {\n const t = this._thresholds;\n\n // Position\n if (Math.abs(current.x - prev.x) > t.position) return true;\n if (Math.abs(current.y - prev.y) > t.position) return true;\n\n if ('z' in current && 'z' in prev) {\n // 3D\n const c = current as EntityState3D;\n const p = prev as EntityState3D;\n if (Math.abs(c.z - p.z) > t.position) return true;\n\n // Rotation (quaternion)\n if (Math.abs(c.qx - p.qx) > t.rotation) return true;\n if (Math.abs(c.qy - p.qy) > t.rotation) return true;\n if (Math.abs(c.qz - p.qz) > t.rotation) return true;\n if (Math.abs(c.qw - p.qw) > t.rotation) return true;\n\n // Velocity\n if (Math.abs(c.vx - p.vx) > t.velocity) return true;\n if (Math.abs(c.vy - p.vy) > t.velocity) return true;\n if (Math.abs(c.vz - p.vz) > t.velocity) return true;\n\n // Angular velocity\n if (Math.abs(c.wx - p.wx) > t.velocity) return true;\n if (Math.abs(c.wy - p.wy) > t.velocity) return true;\n if (Math.abs(c.wz - p.wz) > t.velocity) return true;\n } else {\n // 2D\n const c = current as EntityState2D;\n const p = prev as EntityState2D;\n\n // Rotation\n if (Math.abs(c.a - p.a) > t.rotation) return true;\n\n // Velocity\n if (Math.abs(c.vx - p.vx) > t.velocity) return true;\n if (Math.abs(c.vy - p.vy) > t.velocity) return true;\n\n // Angular velocity\n if (Math.abs(c.va - p.va) > t.velocity) return true;\n }\n\n // Custom properties\n if (current.c || prev.c) {\n const cc = current.c ?? {};\n const pc = prev.c ?? {};\n const allKeys = new Set([...Object.keys(cc), ...Object.keys(pc)]);\n for (const key of allKeys) {\n if (t.custom === 'strict') {\n if (cc[key] !== pc[key]) return true;\n } else {\n const diff = typeof cc[key] === 'number' && typeof pc[key] === 'number'\n ? Math.abs((cc[key] as number) - (pc[key] as number))\n : cc[key] === pc[key] ? 0 : 1;\n if (diff > t.custom) return true;\n }\n }\n }\n\n return false;\n }\n\n private _quantizeEntity(entity: EntityState): EntityState {\n const q = this._quantize!;\n const result = { ...entity };\n\n if (q.position !== undefined) {\n const m = Math.pow(10, q.position);\n result.x = Math.round(result.x * m) / m;\n result.y = Math.round(result.y * m) / m;\n if ('z' in result) {\n (result as EntityState3D).z = Math.round((result as EntityState3D).z * m) / m;\n }\n }\n\n if (q.rotation !== undefined) {\n const m = Math.pow(10, q.rotation);\n if ('a' in result) {\n (result as EntityState2D).a = Math.round((result as EntityState2D).a * m) / m;\n } else if ('qx' in result) {\n const r = result as EntityState3D;\n r.qx = Math.round(r.qx * m) / m;\n r.qy = Math.round(r.qy * m) / m;\n r.qz = Math.round(r.qz * m) / m;\n r.qw = Math.round(r.qw * m) / m;\n }\n }\n\n if (q.velocity !== undefined) {\n const m = Math.pow(10, q.velocity);\n result.vx = Math.round(result.vx * m) / m;\n result.vy = Math.round(result.vy * m) / m;\n if ('vz' in result) {\n const r = result as EntityState3D;\n r.vz = Math.round(r.vz * m) / m;\n r.wx = Math.round(r.wx * m) / m;\n r.wy = Math.round(r.wy * m) / m;\n r.wz = Math.round(r.wz * m) / m;\n }\n if ('va' in result) {\n (result as EntityState2D).va = Math.round((result as EntityState2D).va * m) / m;\n }\n }\n\n return result;\n }\n}\n","import type {\n CarverTransport,\n ConnectionState,\n CarverMultiplayerError,\n UseMultiplayerOptions,\n Player,\n Room,\n SyncMode,\n NetworkQuality,\n} from \"../types\";\nimport { TickKeeper } from \"./TickKeeper\";\nimport { Codec, SnapshotBuffer } from \"./codec\";\n\n/**\n * Central orchestrator for the multiplayer system.\n * Holds references to the active transport, sync engine, room state, and codec.\n * One instance per MultiplayerProvider.\n */\nexport class NetworkManager {\n // Transport\n private _transport: CarverTransport | null = null;\n private _connectionState: ConnectionState = 'disconnected';\n\n // Room state\n private _room: Room | null = null;\n private _players = new Map<string, Player>();\n\n // Sync state\n private _syncMode: SyncMode = 'snapshot';\n private _tickKeeper: TickKeeper;\n private _codec: Codec;\n private _snapshotBuffer: SnapshotBuffer;\n private _networkQuality: NetworkQuality = 'good';\n\n // Options\n private _options: UseMultiplayerOptions;\n\n // Change listeners\n private _connectionListeners: ((state: ConnectionState) => void)[] = [];\n private _playerListeners: (() => void)[] = [];\n private _roomListeners: (() => void)[] = [];\n private _errorListeners: ((error: CarverMultiplayerError) => void)[] = [];\n\n constructor(options: UseMultiplayerOptions = {}) {\n this._options = options;\n this._syncMode = options.mode ?? 'snapshot';\n this._tickKeeper = new TickKeeper(options.tickRate ?? 60);\n this._codec = new Codec({\n thresholds: options.deltaThresholds,\n quantize: options.quantize,\n });\n this._snapshotBuffer = new SnapshotBuffer();\n }\n\n // -- Getters --\n\n get transport(): CarverTransport | null {\n return this._transport;\n }\n\n get connectionState(): ConnectionState {\n return this._connectionState;\n }\n\n get room(): Room | null {\n return this._room;\n }\n\n get players(): Map<string, Player> {\n return this._players;\n }\n\n get selfId(): string | null {\n return this._transport?.peerId || null;\n }\n\n get isHost(): boolean {\n return this._transport?.isHost ?? false;\n }\n\n get hostId(): string | null {\n return this._transport?.hostId ?? null;\n }\n\n get syncMode(): SyncMode {\n return this._syncMode;\n }\n\n get tickKeeper(): TickKeeper {\n return this._tickKeeper;\n }\n\n get codec(): Codec {\n return this._codec;\n }\n\n get snapshotBuffer(): SnapshotBuffer {\n return this._snapshotBuffer;\n }\n\n get networkQuality(): NetworkQuality {\n return this._networkQuality;\n }\n\n get options(): UseMultiplayerOptions {\n return this._options;\n }\n\n // -- Transport management --\n\n setTransport(transport: CarverTransport): void {\n this._transport = transport;\n\n transport.onPeerJoin((peerId) => {\n // Add a player entry if not already present\n if (!this._players.has(peerId)) {\n this._players.set(peerId, {\n peerId,\n displayName: `Player-${peerId.slice(0, 4)}`,\n isHost: peerId === transport.hostId,\n isSelf: false,\n isReady: false,\n isConnected: true,\n metadata: {},\n latencyMs: 0,\n joinedAt: Date.now(),\n });\n }\n this._notifyPlayerListeners();\n });\n\n transport.onPeerUpdated((player) => {\n this._players.set(player.peerId, {\n ...player,\n isSelf: player.peerId === this.selfId,\n });\n this._notifyPlayerListeners();\n });\n\n transport.onPeerLeave((peerId) => {\n this._players.delete(peerId);\n this._notifyPlayerListeners();\n });\n\n transport.onHostChanged((_newHostId) => {\n this._notifyRoomListeners();\n });\n }\n\n // -- Connection state --\n\n setConnectionState(state: ConnectionState): void {\n this._connectionState = state;\n for (const listener of this._connectionListeners) listener(state);\n }\n\n onConnectionStateChange(cb: (state: ConnectionState) => void): () => void {\n this._connectionListeners.push(cb);\n return () => {\n const idx = this._connectionListeners.indexOf(cb);\n if (idx >= 0) this._connectionListeners.splice(idx, 1);\n };\n }\n\n // -- Room state --\n\n setRoom(room: Room): void {\n this._room = room;\n this._notifyRoomListeners();\n }\n\n onRoomChange(cb: () => void): () => void {\n this._roomListeners.push(cb);\n return () => {\n const idx = this._roomListeners.indexOf(cb);\n if (idx >= 0) this._roomListeners.splice(idx, 1);\n };\n }\n\n // -- Players --\n\n setPlayers(players: Player[]): void {\n this._players.clear();\n for (const p of players) {\n this._players.set(p.peerId, p);\n }\n this._notifyPlayerListeners();\n }\n\n updatePlayer(player: Player): void {\n this._players.set(player.peerId, player);\n this._notifyPlayerListeners();\n }\n\n removePlayer(peerId: string): void {\n this._players.delete(peerId);\n this._notifyPlayerListeners();\n }\n\n onPlayersChange(cb: () => void): () => void {\n this._playerListeners.push(cb);\n return () => {\n const idx = this._playerListeners.indexOf(cb);\n if (idx >= 0) this._playerListeners.splice(idx, 1);\n };\n }\n\n // -- Errors --\n\n emitError(error: CarverMultiplayerError): void {\n for (const listener of this._errorListeners) listener(error);\n }\n\n onError(cb: (error: CarverMultiplayerError) => void): () => void {\n this._errorListeners.push(cb);\n return () => {\n const idx = this._errorListeners.indexOf(cb);\n if (idx >= 0) this._errorListeners.splice(idx, 1);\n };\n }\n\n // -- Network quality --\n\n setNetworkQuality(quality: NetworkQuality): void {\n this._networkQuality = quality;\n }\n\n // -- Sync options --\n\n updateOptions(options: UseMultiplayerOptions): void {\n this._options = options;\n if (options.mode) this._syncMode = options.mode;\n if (options.tickRate) this._tickKeeper.setTickRate(options.tickRate);\n if (options.deltaThresholds || options.quantize) {\n this._codec = new Codec({\n thresholds: options.deltaThresholds,\n quantize: options.quantize,\n });\n }\n }\n\n // -- Cleanup --\n\n destroy(): void {\n this._transport?.disconnect();\n this._transport = null;\n this._connectionState = 'disconnected';\n this._room = null;\n this._players.clear();\n this._tickKeeper.reset();\n this._snapshotBuffer.clear();\n this._connectionListeners = [];\n this._playerListeners = [];\n this._roomListeners = [];\n this._errorListeners = [];\n }\n\n // -- Private --\n\n private _notifyPlayerListeners(): void {\n for (const listener of this._playerListeners) listener();\n }\n\n private _notifyRoomListeners(): void {\n for (const listener of this._roomListeners) listener();\n }\n}\n","import { createContext, useContext } from \"react\";\nimport type { SignalingStrategy } from \"../transport/strategy/types\";\nimport type { NetworkManager } from \"./NetworkManager\";\n\nexport interface MultiplayerContextValue {\n appId: string;\n strategy: SignalingStrategy;\n iceServers?: RTCIceServer[];\n networkManager: NetworkManager;\n}\n\nexport const MultiplayerContext = createContext<MultiplayerContextValue | null>(null);\n\nexport function useMultiplayerContext(): MultiplayerContextValue {\n const ctx = useContext(MultiplayerContext);\n if (!ctx) {\n throw new Error(\"useMultiplayerContext must be used inside a <MultiplayerProvider>.\");\n }\n return ctx;\n}\n","import { createElement, useContext } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { MultiplayerContext } from \"../core/MultiplayerContext\";\n\nexport interface MultiplayerBridgeProps {\n children: ReactNode;\n}\n\n/**\n * Bridges the MultiplayerContext from the parent React tree into an R3F Canvas.\n *\n * R3F's `<Canvas>` uses a separate React reconciler, so React contexts from the\n * parent tree are not automatically available inside the Canvas. This component\n * reads the MultiplayerContext value from the parent tree and re-provides it\n * inside the Canvas, making all CarverJS multiplayer hooks work seamlessly.\n *\n * Place `<MultiplayerBridge>` as a direct child of `<Game>`, wrapping `<World>`\n * and all scene content that uses multiplayer hooks.\n *\n * @example\n * ```tsx\n * <MultiplayerProvider appId=\"my-game\">\n * <Game mode=\"2d\">\n * <MultiplayerBridge>\n * <World>\n * <MyScene />\n * </World>\n * </MultiplayerBridge>\n * </Game>\n * </MultiplayerProvider>\n * ```\n */\nexport function MultiplayerBridge({ children }: MultiplayerBridgeProps) {\n const ctx = useContext(MultiplayerContext);\n if (!ctx) return createElement(\"group\", null, children);\n return createElement(MultiplayerContext.Provider, { value: ctx }, children);\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport { WebRTCTransport } from \"../transport/webrtc/WebRTCTransport\";\nimport type {\n ConnectionState,\n CarverMultiplayerError,\n CarverTransport,\n UseRoomOptions,\n Room,\n} from \"../types\";\n\nexport interface UseRoomReturn {\n roomId: string | null;\n connectionState: ConnectionState;\n isHost: boolean;\n hostId: string | null;\n selfId: string | null;\n room: Room | null;\n error: CarverMultiplayerError | null;\n join: (roomId: string, options?: { password?: string }) => Promise<void>;\n leave: () => void;\n setReady: (ready: boolean) => void;\n setMetadata: (meta: Record<string, unknown>) => void;\n setRoomMetadata: (meta: Record<string, unknown>) => void;\n transport: CarverTransport | null;\n}\n\nexport function useRoom(roomId?: string, options?: UseRoomOptions): UseRoomReturn {\n const { strategy, iceServers, networkManager } = useMultiplayerContext();\n const [connectionState, setConnectionState] = useState<ConnectionState>('disconnected');\n const [isHost, setIsHost] = useState(false);\n const [hostId, setHostId] = useState<string | null>(null);\n const [selfId, setSelfId] = useState<string | null>(null);\n const [currentRoomId, setCurrentRoomId] = useState<string | null>(null);\n const [error, setError] = useState<CarverMultiplayerError | null>(null);\n const [transport, setTransport] = useState<CarverTransport | null>(null);\n const [room, setRoom] = useState<Room | null>(null);\n const reconnectAttemptsRef = useRef(0);\n const maxReconnectAttempts = options?.reconnectAttempts ?? 3;\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // Create transport based on options\n const createTransport = useCallback((): CarverTransport => {\n const opt = optionsRef.current;\n // Allow fully custom transport instances\n if (opt?.transport && typeof opt.transport === 'object' && 'connect' in opt.transport) {\n return opt.transport as CarverTransport;\n }\n // Default: WebRTC with shared strategy and configurable ICE servers\n const servers = opt?.iceServers ?? iceServers;\n const policy = opt?.privacy === 'relay' ? 'relay' as const : 'all' as const;\n return new WebRTCTransport(strategy, servers, policy);\n }, [strategy, iceServers]);\n\n // Track transport ref for cleanup\n const transportRef = useRef<CarverTransport | null>(null);\n\n const doJoin = useCallback(async (targetRoomId: string, joinOptions?: { password?: string }) => {\n // Disconnect any existing transport (handles StrictMode re-mount)\n if (transportRef.current) {\n transportRef.current.disconnect();\n transportRef.current = null;\n }\n\n const t = createTransport();\n transportRef.current = t;\n\n try {\n setError(null);\n setConnectionState('connecting');\n networkManager.setConnectionState('connecting');\n setTransport(t);\n networkManager.setTransport(t);\n\n // Setup transport event listeners\n t.onPeerJoin(() => {\n // Player list updates handled by NetworkManager\n });\n\n t.onPeerLeave(() => {\n // Player list updates handled by NetworkManager\n });\n\n t.onHostChanged((newHostId) => {\n setHostId(newHostId);\n setIsHost(t.peerId === newHostId);\n optionsRef.current?.onHostMigration?.(newHostId);\n });\n\n // Listen for room updates\n if ('onRoomUpdated' in t && typeof (t as any).onRoomUpdated === 'function') {\n (t as any).onRoomUpdated((updatedRoom: Room) => {\n networkManager.setRoom(updatedRoom);\n });\n }\n\n await t.connect(targetRoomId, {\n displayName: optionsRef.current?.displayName,\n playerMetadata: optionsRef.current?.playerMetadata,\n password: joinOptions?.password ?? optionsRef.current?.password,\n iceServers: optionsRef.current?.iceServers,\n iceTransportPolicy: optionsRef.current?.privacy === 'relay' ? 'relay' : 'all',\n });\n\n // If this transport was replaced by a StrictMode re-mount, bail out\n if (transportRef.current !== t) return;\n\n setCurrentRoomId(targetRoomId);\n setSelfId(t.peerId);\n setHostId(t.hostId);\n setIsHost(t.isHost);\n setConnectionState('connected');\n networkManager.setConnectionState('connected');\n\n // Populate NetworkManager with initial room state and players\n if (t.room) {\n networkManager.setRoom(t.room);\n }\n if (t.initialPlayers) {\n const players = t.initialPlayers.map((p) => ({\n ...p,\n isSelf: p.peerId === t.peerId,\n }));\n networkManager.setPlayers(players);\n }\n\n reconnectAttemptsRef.current = 0;\n optionsRef.current?.onConnected?.();\n } catch (err) {\n // If this transport was replaced, ignore\n if (transportRef.current !== t) return;\n\n const carverError: CarverMultiplayerError = {\n code: 'CONNECTION_FAILED',\n message: err instanceof Error ? err.message : 'Connection failed',\n recoverable: reconnectAttemptsRef.current < maxReconnectAttempts,\n };\n setError(carverError);\n networkManager.emitError(carverError);\n setConnectionState('disconnected');\n networkManager.setConnectionState('disconnected');\n optionsRef.current?.onError?.(carverError);\n }\n }, [createTransport, networkManager, maxReconnectAttempts]);\n\n const leave = useCallback(() => {\n if (transportRef.current) {\n transportRef.current.disconnect();\n transportRef.current = null;\n }\n setTransport(null);\n setConnectionState('disconnected');\n setCurrentRoomId(null);\n setSelfId(null);\n setHostId(null);\n setIsHost(false);\n setError(null);\n networkManager.setConnectionState('disconnected');\n optionsRef.current?.onDisconnected?.('user_left');\n }, [networkManager]);\n\n const setReady = useCallback((ready: boolean) => {\n transport?.setReady?.(ready);\n // Optimistic self-update so local UI responds immediately\n const selfPlayer = networkManager.players.get(transport?.peerId ?? '');\n if (selfPlayer) {\n networkManager.updatePlayer({ ...selfPlayer, isReady: ready });\n }\n }, [transport, networkManager]);\n\n const setMetadata = useCallback((meta: Record<string, unknown>) => {\n transport?.setMetadata?.(meta);\n }, [transport]);\n\n const setRoomMetadata = useCallback((meta: Record<string, unknown>) => {\n transport?.setRoomMetadata?.(meta);\n }, [transport]);\n\n // Auto-join if roomId is provided\n useEffect(() => {\n if (roomId) {\n doJoin(roomId);\n }\n return () => {\n if (transportRef.current) {\n transportRef.current.disconnect();\n transportRef.current = null;\n }\n };\n }, [roomId, doJoin]);\n\n // Listen for room updates\n useEffect(() => {\n const unsub = networkManager.onRoomChange(() => {\n setRoom(networkManager.room);\n });\n setRoom(networkManager.room);\n return unsub;\n }, [networkManager]);\n\n return {\n roomId: currentRoomId,\n connectionState,\n isHost,\n hostId,\n selfId,\n room,\n error,\n join: doJoin,\n leave,\n setReady,\n setMetadata,\n setRoomMetadata,\n transport,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { Room, RoomConfig, UseLobbyOptions, CarverMultiplayerError } from \"../types\";\nimport type { RoomAnnouncement } from \"../transport/strategy/types\";\n\nexport interface UseLobbyReturn {\n rooms: Room[];\n isLoading: boolean;\n error: CarverMultiplayerError | null;\n refresh: () => void;\n createRoom: (config: RoomConfig) => Promise<string>;\n}\n\n/** Convert a RoomAnnouncement (from strategy) to a Room (public API type) */\nfunction announcementToRoom(ann: RoomAnnouncement): Room {\n return {\n id: ann.roomId,\n name: ann.name,\n hostId: ann.hostId,\n playerCount: ann.playerCount,\n maxPlayers: ann.maxPlayers,\n gameMode: ann.gameMode,\n isPrivate: ann.isPrivate,\n metadata: ann.metadata,\n createdAt: ann.createdAt,\n state: 'lobby',\n };\n}\n\nexport function useLobby(options?: UseLobbyOptions): UseLobbyReturn {\n const { strategy } = useMultiplayerContext();\n const [rooms, setRooms] = useState<Room[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<CarverMultiplayerError | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // Filter rooms based on options\n const filterRooms = useCallback((roomList: Room[]): Room[] => {\n const filter = optionsRef.current?.filter;\n if (!filter) return roomList;\n return roomList.filter((room) => {\n if (filter.maxPlayers !== undefined && room.maxPlayers > filter.maxPlayers) return false;\n if (filter.gameMode !== undefined && room.gameMode !== filter.gameMode) return false;\n if (filter.hasPassword !== undefined && room.isPrivate !== filter.hasPassword) return false;\n return true;\n });\n }, []);\n\n // Subscribe to lobby via strategy\n useEffect(() => {\n setIsLoading(true);\n setError(null);\n\n const unsub = strategy.subscribeToLobby((announcements: RoomAnnouncement[]) => {\n const converted = announcements.map(announcementToRoom);\n setRooms(filterRooms(converted));\n setIsLoading(false);\n });\n\n // After a short timeout, if we haven't received any data, stop loading\n const timeout = setTimeout(() => setIsLoading(false), 3000);\n\n return () => {\n unsub();\n clearTimeout(timeout);\n };\n }, [strategy, filterRooms]);\n\n const refresh = useCallback(() => {\n // With MQTT/Firebase, the lobby is live-updating.\n // Refresh is a no-op since we're subscribed to real-time updates.\n // But we reset loading to give visual feedback.\n setIsLoading(true);\n setTimeout(() => setIsLoading(false), 1000);\n }, []);\n\n const createRoom = useCallback(async (config: RoomConfig): Promise<string> => {\n // In serverless mode, \"creating a room\" just means announcing it.\n // The room ID is generated locally. The actual room is established\n // when the first peer joins via useRoom.\n const roomId = `${config.name.toLowerCase().replace(/\\s+/g, '-')}-${Date.now().toString(36)}`;\n\n const announcement: RoomAnnouncement = {\n roomId,\n name: config.name,\n hostId: strategy.selfId,\n playerCount: 0,\n maxPlayers: config.maxPlayers ?? 8,\n gameMode: config.metadata?.gameMode as string | undefined,\n isPrivate: config.isPrivate ?? false,\n metadata: config.metadata ?? {},\n createdAt: Date.now(),\n lastSeen: Date.now(),\n };\n\n strategy.announceRoom(announcement);\n return roomId;\n }, [strategy]);\n\n return {\n rooms,\n isLoading,\n error,\n refresh,\n createRoom,\n };\n}\n","import { useState, useEffect, useCallback } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { Player } from \"../types\";\n\nexport interface UsePlayersReturn {\n players: Player[];\n self: Player | null;\n host: Player | null;\n count: number;\n allReady: boolean;\n getPlayer: (peerId: string) => Player | undefined;\n}\n\nexport function usePlayers(): UsePlayersReturn {\n const { networkManager } = useMultiplayerContext();\n const [players, setPlayers] = useState<Player[]>([]);\n const [, setVersion] = useState(0);\n\n useEffect(() => {\n const unsubscribe = networkManager.onPlayersChange(() => {\n setPlayers(Array.from(networkManager.players.values()));\n setVersion((v) => v + 1);\n });\n\n // Initialize with current players\n setPlayers(Array.from(networkManager.players.values()));\n\n return unsubscribe;\n }, [networkManager]);\n\n const self = players.find((p) => p.isSelf) ?? null;\n const host = players.find((p) => p.isHost) ?? null;\n const allReady = players.length > 0 && players.every((p) => p.isReady);\n\n const getPlayer = useCallback(\n (peerId: string) => players.find((p) => p.peerId === peerId),\n [players]\n );\n\n return {\n players,\n self,\n host,\n count: players.length,\n allReady,\n getPlayer,\n };\n}\n","import { useCallback } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { RoomState } from \"../types\";\n\nexport interface UseHostReturn {\n kick: (peerId: string, reason?: string) => void;\n transferHost: (peerId: string) => void;\n setRoomState: (state: RoomState) => void;\n setMaxPlayers: (n: number) => void;\n lockRoom: () => void;\n unlockRoom: () => void;\n}\n\nexport function useHost(): UseHostReturn {\n const { networkManager } = useMultiplayerContext();\n\n const getTransport = useCallback(() => {\n const transport = networkManager.transport;\n if (!transport || !networkManager.isHost) return null;\n return transport;\n }, [networkManager]);\n\n const kick = useCallback((peerId: string, reason?: string) => {\n getTransport()?.kick?.(peerId, reason);\n }, [getTransport]);\n\n const transferHost = useCallback((peerId: string) => {\n getTransport()?.transferHost?.(peerId);\n }, [getTransport]);\n\n const setRoomState = useCallback((state: RoomState) => {\n getTransport()?.setRoomState?.(state);\n }, [getTransport]);\n\n const setMaxPlayers = useCallback((n: number) => {\n getTransport()?.setMaxPlayers?.(n);\n }, [getTransport]);\n\n const lockRoom = useCallback(() => {\n getTransport()?.lockRoom?.();\n }, [getTransport]);\n\n const unlockRoom = useCallback(() => {\n getTransport()?.unlockRoom?.();\n }, [getTransport]);\n\n return {\n kick,\n transferHost,\n setRoomState,\n setMaxPlayers,\n lockRoom,\n unlockRoom,\n };\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport { useFrame } from \"@react-three/fiber\";\nimport { getActorRegistry } from \"@carverjs/core/systems\";\nimport type { ActorRef, NetworkedConfig } from \"@carverjs/core/types\";\nimport type {\n UseMultiplayerOptions,\n NetworkQuality,\n SyncMode,\n EntityState,\n EntityState2D,\n EntityState3D,\n} from \"../types\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport { EventSync } from \"../sync/EventSync\";\nimport { SnapshotSync } from \"../sync/SnapshotSync\";\nimport type { SnapshotSyncOptions } from \"../sync/SnapshotSync\";\nimport { PredictionSync } from \"../sync/PredictionSync\";\nimport { NetworkSimulator } from \"../core/NetworkSimulator\";\n\n// ── Return type ──\n\nexport interface UseMultiplayerReturn {\n isActive: boolean;\n networkQuality: NetworkQuality;\n tick: number;\n serverTick: number;\n drift: number;\n syncEngine: SyncMode;\n}\n\n// ── Helpers: read / write actor state ──\n\nconst Z_THRESHOLD = 0.01;\n\nfunction detect2D(actors: Map<string, ActorRef>): boolean {\n for (const [, ref] of actors) {\n if (Math.abs(ref.object3D.position.z) > Z_THRESHOLD) return false;\n }\n return true;\n}\n\nfunction readEntityState2D(ref: ActorRef): EntityState2D {\n const pos = ref.object3D.position;\n const rot = ref.object3D.rotation;\n const rb = ref.rigidBody;\n\n let vx = 0;\n let vy = 0;\n let va = 0;\n\n if (rb) {\n try {\n const lv = rb.linvel();\n vx = lv.x;\n vy = lv.y;\n } catch { /* rigid body may not support linvel */ }\n try {\n const av = rb.angvel();\n // 2D angular velocity is a scalar in Rapier 2D, but in 3D mode it's a vec3\n va = typeof av === \"number\" ? av : (av?.z ?? 0);\n } catch { /* rigid body may not support angvel */ }\n }\n\n const nc = ref.userData.networked as NetworkedConfig | undefined;\n const custom = nc?.custom;\n\n return {\n id: ref.id,\n x: pos.x,\n y: pos.y,\n a: rot.z,\n vx,\n vy,\n va,\n ...(custom ? { c: custom } : {}),\n };\n}\n\nfunction readEntityState3D(ref: ActorRef): EntityState3D {\n const pos = ref.object3D.position;\n const quat = ref.object3D.quaternion;\n const rb = ref.rigidBody;\n\n let vx = 0;\n let vy = 0;\n let vz = 0;\n let wx = 0;\n let wy = 0;\n let wz = 0;\n\n if (rb) {\n try {\n const lv = rb.linvel();\n vx = lv.x;\n vy = lv.y;\n vz = lv.z ?? 0;\n } catch { /* no linvel */ }\n try {\n const av = rb.angvel();\n wx = av.x ?? 0;\n wy = av.y ?? 0;\n wz = av.z ?? 0;\n } catch { /* no angvel */ }\n }\n\n const nc = ref.userData.networked as NetworkedConfig | undefined;\n const custom = nc?.custom;\n\n return {\n id: ref.id,\n x: pos.x,\n y: pos.y,\n z: pos.z,\n qx: quat.x,\n qy: quat.y,\n qz: quat.z,\n qw: quat.w,\n vx,\n vy,\n vz,\n wx,\n wy,\n wz,\n ...(custom ? { c: custom } : {}),\n };\n}\n\nfunction buildEntityMap(\n actors: Map<string, ActorRef>,\n is2D: boolean,\n): Map<string, EntityState> {\n const entities = new Map<string, EntityState>();\n for (const [id, ref] of actors) {\n const nc = ref.userData.networked as NetworkedConfig | undefined;\n if (nc && nc.sync === false) continue;\n entities.set(id, is2D ? readEntityState2D(ref) : readEntityState3D(ref));\n }\n return entities;\n}\n\nfunction applyState2D(ref: ActorRef, state: EntityState2D): void {\n ref.object3D.position.set(state.x, state.y, 0);\n ref.object3D.rotation.z = state.a;\n\n if (ref.rigidBody) {\n try {\n if (typeof ref.rigidBody.setTranslation === \"function\") {\n ref.rigidBody.setTranslation({ x: state.x, y: state.y }, true);\n }\n if (typeof ref.rigidBody.setRotation === \"function\") {\n ref.rigidBody.setRotation(state.a, true);\n }\n } catch { /* kinematic API may not be available */ }\n }\n}\n\nfunction applyState3D(ref: ActorRef, state: EntityState3D): void {\n ref.object3D.position.set(state.x, state.y, state.z);\n ref.object3D.quaternion.set(state.qx, state.qy, state.qz, state.qw);\n\n if (ref.rigidBody) {\n try {\n if (typeof ref.rigidBody.setTranslation === \"function\") {\n ref.rigidBody.setTranslation({ x: state.x, y: state.y, z: state.z }, true);\n }\n if (typeof ref.rigidBody.setRotation === \"function\") {\n ref.rigidBody.setRotation(\n { x: state.qx, y: state.qy, z: state.qz, w: state.qw },\n true,\n );\n }\n } catch { /* kinematic API may not be available */ }\n }\n}\n\nfunction applyEntityState(\n ref: ActorRef,\n state: EntityState,\n is2D: boolean,\n): void {\n if (is2D) {\n applyState2D(ref, state as EntityState2D);\n } else {\n applyState3D(ref, state as EntityState3D);\n }\n}\n\nfunction applyStatesToActors(\n states: Map<string, EntityState>,\n registry: ReturnType<typeof getActorRegistry>,\n is2D: boolean,\n): void {\n for (const [id, state] of states) {\n // Skip tombstones\n if (state.c && (state.c as Record<string, unknown>).__removed) continue;\n\n const ref = registry.get(id);\n if (!ref) continue;\n\n applyEntityState(ref, state, is2D);\n }\n}\n\n// ── Hook ──\n\nexport function useMultiplayer(\n options: UseMultiplayerOptions = {},\n): UseMultiplayerReturn {\n const { networkManager } = useMultiplayerContext();\n const mode: SyncMode = options.mode ?? networkManager.syncMode;\n\n // Refs for sync engines (mutable across renders, don't trigger re-render)\n const eventSyncRef = useRef<EventSync | null>(null);\n const snapshotSyncRef = useRef<SnapshotSync | null>(null);\n const predictionSyncRef = useRef<PredictionSync | null>(null);\n const networkSimulatorRef = useRef<NetworkSimulator | null>(null);\n const is2DRef = useRef<boolean | null>(null);\n\n // Observable state exposed to consumers\n const [isActive, setIsActive] = useState(false);\n const [networkQuality, setNetworkQuality] = useState<NetworkQuality>(\"good\");\n const [tick, setTick] = useState(0);\n const [serverTick, setServerTick] = useState(0);\n const [drift, setDrift] = useState(0);\n\n const actorRegistry = useRef(getActorRegistry());\n\n // Track whether we were the host last frame to detect migration\n const wasHostRef = useRef<boolean | null>(null);\n\n // Build SnapshotSyncOptions from user options\n const buildSnapshotOpts = useCallback((): SnapshotSyncOptions => {\n return {\n broadcastRate: options.broadcastRate,\n keyframeInterval: options.keyframeInterval,\n bufferSize: options.interpolation?.bufferSize,\n interpolationMethod: options.interpolation?.method,\n extrapolateMs: options.interpolation?.extrapolateMs,\n is2D: is2DRef.current ?? true,\n };\n }, [\n options.broadcastRate,\n options.keyframeInterval,\n options.interpolation?.bufferSize,\n options.interpolation?.method,\n options.interpolation?.extrapolateMs,\n ]);\n\n // ── Setup & teardown sync engines ──\n useEffect(() => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n // Setup network simulator if debug options are configured\n const debugOpts = options.debug;\n let simulator: NetworkSimulator | null = null;\n if (debugOpts?.simulatedLatencyMs || debugOpts?.simulatedPacketLoss) {\n simulator = new NetworkSimulator({\n latencyMs: debugOpts.simulatedLatencyMs,\n packetLoss: debugOpts.simulatedPacketLoss,\n });\n networkSimulatorRef.current = simulator;\n\n // Wrap transport.createChannel so all new channels go through the simulator\n const origCreateChannel = transport.createChannel.bind(transport);\n transport.createChannel = <T>(name: string, channelOpts?: import(\"../types\").ChannelOptions) => {\n const ch = origCreateChannel<T>(name, channelOpts);\n const wrappedSend = simulator!.wrapSend(ch.send.bind(ch));\n return { ...ch, send: wrappedSend };\n };\n }\n\n // Always create EventSync (Layer 1) - it's lightweight and useful for all modes\n eventSyncRef.current = new EventSync(transport);\n\n // Create Layer 2 / Layer 3 based on mode\n if (mode === \"snapshot\" || mode === \"prediction\") {\n snapshotSyncRef.current = new SnapshotSync(\n transport,\n networkManager.codec,\n networkManager.snapshotBuffer,\n buildSnapshotOpts(),\n );\n }\n\n if (mode === \"prediction\") {\n predictionSyncRef.current = new PredictionSync(\n transport,\n networkManager.codec,\n networkManager.tickKeeper,\n options.prediction,\n );\n\n // Wire up the physics step callback if provided\n if (options.onPhysicsStep) {\n predictionSyncRef.current.setPhysicsStep(options.onPhysicsStep);\n }\n }\n\n wasHostRef.current = networkManager.isHost;\n setIsActive(true);\n\n // Listen for host migration\n const unsubHostChanged = (() => {\n const onHostChanged = (newHostId: string) => {\n const amNewHost = newHostId === transport.peerId;\n const wasPreviouslyHost = wasHostRef.current;\n wasHostRef.current = amNewHost;\n\n if (amNewHost && !wasPreviouslyHost) {\n // Promoted to host\n snapshotSyncRef.current?.promoteToHost(buildSnapshotOpts());\n } else if (!amNewHost && wasPreviouslyHost) {\n // Demoted to client\n snapshotSyncRef.current?.demoteToClient(buildSnapshotOpts());\n }\n };\n\n transport.onHostChanged(onHostChanged);\n // transport.onHostChanged doesn't return an unsub - we rely on destroy\n return () => {}; // no-op cleanup for this listener\n })();\n\n // Cleanup on unmount or when deps change\n return () => {\n unsubHostChanged();\n eventSyncRef.current?.destroy();\n snapshotSyncRef.current?.destroy();\n predictionSyncRef.current?.destroy();\n networkSimulatorRef.current?.destroy();\n eventSyncRef.current = null;\n snapshotSyncRef.current = null;\n predictionSyncRef.current = null;\n networkSimulatorRef.current = null;\n setIsActive(false);\n };\n }, [networkManager, mode, buildSnapshotOpts, options.prediction, options.onPhysicsStep, options.debug]);\n\n // ── Sync network quality from manager ──\n useEffect(() => {\n const unsub = networkManager.onConnectionStateChange(() => {\n setNetworkQuality(networkManager.networkQuality);\n });\n return unsub;\n }, [networkManager]);\n\n // ── R3F render loop at priority -55 ──\n useFrame((_state: unknown, delta: number) => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n const tickKeeper = networkManager.tickKeeper;\n const isHost = networkManager.isHost;\n\n // Detect 2D/3D on first frame with actors\n if (is2DRef.current === null) {\n const networked = actorRegistry.current.getNetworked();\n if (networked.size > 0) {\n is2DRef.current = detect2D(networked);\n }\n }\n\n const is2D = is2DRef.current ?? true;\n\n // Events-only mode: no per-frame state sync needed\n if (mode === \"events\") return;\n\n // Advance tick accumulator\n const ticksThisFrame = tickKeeper.update(delta);\n\n // ── Fixed-step processing ──\n for (let i = 0; i < ticksThisFrame; i++) {\n const currentTick = tickKeeper.tick - (ticksThisFrame - 1 - i);\n\n if (isHost) {\n // Host: read actor state and broadcast\n const networked = actorRegistry.current.getNetworked();\n const entities = buildEntityMap(networked, is2D);\n\n if (mode === \"snapshot\" || mode === \"prediction\") {\n snapshotSyncRef.current?.hostTick(currentTick, entities, tickKeeper.tickDelta);\n }\n\n if (mode === \"prediction\") {\n predictionSyncRef.current?.hostTick(currentTick, entities, tickKeeper.tickDelta);\n }\n } else {\n // Client in prediction mode: run client tick\n if (mode === \"prediction\" && predictionSyncRef.current) {\n predictionSyncRef.current.clientTick(currentTick);\n }\n }\n }\n\n // ── Render-phase interpolation / smoothing (runs every frame) ──\n if (!isHost) {\n if (mode === \"snapshot\" && snapshotSyncRef.current) {\n // Client interpolation: use performance.now() as render time\n const renderTime = performance.now();\n const interpolated = snapshotSyncRef.current.clientInterpolate(renderTime);\n applyStatesToActors(interpolated, actorRegistry.current, is2D);\n } else if (mode === \"prediction\" && predictionSyncRef.current) {\n // Apply error smoothing on top of predicted state\n const predicted = predictionSyncRef.current.predictedState;\n const smoothed = predictionSyncRef.current.applyErrorSmoothing(predicted);\n applyStatesToActors(smoothed, actorRegistry.current, is2D);\n }\n }\n\n // ── Update observable state (throttled — only when values actually change) ──\n if (ticksThisFrame > 0) {\n const newTick = tickKeeper.tick;\n const newServerTick = tickKeeper.serverTick;\n const newDrift = tickKeeper.drift;\n const newQuality = networkManager.networkQuality;\n setTick((prev) => prev !== newTick ? newTick : prev);\n setServerTick((prev) => prev !== newServerTick ? newServerTick : prev);\n setDrift((prev) => prev !== newDrift ? newDrift : prev);\n setNetworkQuality((prev) => prev !== newQuality ? newQuality : prev);\n }\n }, -55);\n\n return {\n isActive,\n networkQuality,\n tick,\n serverTick,\n drift,\n syncEngine: mode,\n };\n}\n","/* ------------------------------------------------------------------- */\n/* NetworkSimulator – latency / packet-loss / jitter injection layer */\n/* ------------------------------------------------------------------- */\n\nexport interface NetworkSimulatorOptions {\n /** Additional one-way latency in milliseconds (default 0) */\n latencyMs?: number;\n /** Packet drop rate, 0-1 (default 0) */\n packetLoss?: number;\n /** Random jitter +/- milliseconds (default 0) */\n jitterMs?: number;\n}\n\ninterface SimulatorStats {\n sentCount: number;\n droppedCount: number;\n avgLatencyMs: number;\n}\n\nexport class NetworkSimulator {\n private latencyMs: number;\n private packetLoss: number;\n private jitterMs: number;\n\n private sentCount = 0;\n private droppedCount = 0;\n private latencySum = 0; // running sum of applied latencies\n\n /** Active timeout handles so we can cancel them on destroy() */\n private pending: Set<ReturnType<typeof setTimeout>> = new Set();\n\n constructor(options?: NetworkSimulatorOptions) {\n const opts = options ?? {};\n this.latencyMs = opts.latencyMs ?? 0;\n this.packetLoss = opts.packetLoss ?? 0;\n this.jitterMs = opts.jitterMs ?? 0;\n }\n\n /* ---- public API ---- */\n\n /** Update simulation parameters at runtime. */\n setOptions(options: Partial<NetworkSimulatorOptions>): void {\n if (options.latencyMs !== undefined) this.latencyMs = options.latencyMs;\n if (options.packetLoss !== undefined) this.packetLoss = options.packetLoss;\n if (options.jitterMs !== undefined) this.jitterMs = options.jitterMs;\n }\n\n /**\n * Wrap an existing send function so that every call goes through the\n * simulated network conditions (latency, jitter, packet loss).\n */\n wrapSend<T>(\n originalSend: (data: T, target?: string | string[]) => void,\n ): (data: T, target?: string | string[]) => void {\n return (data: T, target?: string | string[]) => {\n /* 1. Packet-loss check */\n if (Math.random() < this.packetLoss) {\n this.droppedCount++;\n return;\n }\n\n this.sentCount++;\n\n /* 2. Compute effective delay */\n const jitter =\n this.jitterMs > 0\n ? Math.random() * 2 * this.jitterMs - this.jitterMs\n : 0;\n const delay = Math.max(0, this.latencyMs + jitter);\n\n /* Track latency for stats */\n this.latencySum += delay;\n\n /* 3. Dispatch */\n if (delay === 0) {\n originalSend(data, target);\n } else {\n const handle = setTimeout(() => {\n this.pending.delete(handle);\n originalSend(data, target);\n }, delay);\n this.pending.add(handle);\n }\n };\n }\n\n /** Current statistics snapshot. */\n get stats(): SimulatorStats {\n return {\n sentCount: this.sentCount,\n droppedCount: this.droppedCount,\n avgLatencyMs:\n this.sentCount > 0 ? this.latencySum / this.sentCount : 0,\n };\n }\n\n /** Cancel all pending delayed sends and clean up. */\n destroy(): void {\n for (const handle of this.pending) {\n clearTimeout(handle);\n }\n this.pending.clear();\n }\n}\n","import { useRef, useEffect, useCallback } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport { EventSync } from \"../sync/EventSync\";\n\nexport interface UseNetworkEventsReturn<T extends { [K in keyof T]: unknown } = Record<string, unknown>> {\n sendEvent: <K extends keyof T & string>(type: K, payload: T[K], target?: string) => void;\n broadcast: <K extends keyof T & string>(type: K, payload: T[K]) => void;\n onEvent: <K extends keyof T & string>(type: K, callback: (data: T[K], peerId: string) => void) => () => void;\n}\n\n/**\n * Layer 1: Typed event-based messaging between peers.\n * Uses a single reliable+ordered channel.\n *\n * @example\n * ```tsx\n * interface MyEvents {\n * 'chat': { message: string };\n * 'turn-end': { playerId: string; action: string };\n * }\n *\n * const { sendEvent, broadcast, onEvent } = useNetworkEvents<MyEvents>();\n *\n * broadcast('chat', { message: 'hello' });\n * onEvent('chat', (data, peerId) => console.log(data.message));\n * ```\n */\ninterface PendingListener {\n type: string;\n callback: (payload: unknown, peerId: string) => void;\n unsub: (() => void) | null;\n}\n\nexport function useNetworkEvents<\n T extends { [K in keyof T]: unknown } = Record<string, unknown>\n>(options?: { hostValidation?: boolean }): UseNetworkEventsReturn<T> {\n const { networkManager } = useMultiplayerContext();\n const eventSyncRef = useRef<EventSync | null>(null);\n const pendingRef = useRef<PendingListener[]>([]);\n const drainedUnsubsRef = useRef<(() => void)[]>([]);\n\n // Initialize EventSync when transport is available\n useEffect(() => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n const eventSync = new EventSync(transport, {\n hostValidation: options?.hostValidation,\n });\n eventSyncRef.current = eventSync;\n\n // Drain pending listener queue\n const unsubs: (() => void)[] = [];\n for (const entry of pendingRef.current) {\n const unsub = eventSync.onEvent(entry.type, entry.callback);\n entry.unsub = unsub;\n unsubs.push(unsub);\n }\n pendingRef.current = [];\n drainedUnsubsRef.current = unsubs;\n\n return () => {\n // Clean up any drained listeners that are still active\n for (const unsub of drainedUnsubsRef.current) {\n unsub();\n }\n drainedUnsubsRef.current = [];\n eventSync.destroy();\n eventSyncRef.current = null;\n };\n }, [networkManager.transport, options?.hostValidation]);\n\n const sendEvent = useCallback(<K extends keyof T & string>(\n type: K,\n payload: T[K],\n target?: string,\n ) => {\n eventSyncRef.current?.sendEvent(type, payload, target);\n }, []);\n\n const broadcast = useCallback(<K extends keyof T & string>(\n type: K,\n payload: T[K],\n ) => {\n eventSyncRef.current?.broadcast(type, payload);\n }, []);\n\n const onEvent = useCallback(<K extends keyof T & string>(\n type: K,\n callback: (data: T[K], peerId: string) => void,\n ): (() => void) => {\n const castCallback = callback as (payload: unknown, peerId: string) => void;\n\n if (eventSyncRef.current) {\n return eventSyncRef.current.onEvent(type, castCallback);\n }\n\n // Buffer the listener until EventSync initializes\n const entry: PendingListener = { type, callback: castCallback, unsub: null };\n pendingRef.current.push(entry);\n\n return () => {\n if (entry.unsub) {\n // Already drained and registered with EventSync -- unsubscribe normally\n entry.unsub();\n drainedUnsubsRef.current = drainedUnsubsRef.current.filter((u) => u !== entry.unsub);\n } else {\n // Still pending -- remove from queue\n pendingRef.current = pendingRef.current.filter((e) => e !== entry);\n }\n };\n }, []);\n\n return { sendEvent, broadcast, onEvent };\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { CarverChannel, EntityState } from \"../types\";\n\n// ── Message protocol ──\n\ninterface NetworkStateMessage {\n action: \"spawn\" | \"despawn\" | \"request-spawn\";\n id: string;\n state?: EntityState | Record<string, unknown>;\n}\n\n// ── Return type ──\n\nexport interface UseNetworkStateReturn {\n /** Host only. Create a networked entity and broadcast its existence to all peers. */\n spawn: (id: string, initialState: EntityState) => void;\n /** Host only. Remove a networked entity and broadcast removal to all peers. */\n despawn: (id: string) => void;\n /** Client sends a spawn request to the host, who validates and spawns if the id is not taken. */\n requestSpawn: (id: string, config: Record<string, unknown>) => void;\n /** Read the current state of a networked entity by id. */\n getState: (id: string) => EntityState | undefined;\n /** Write a partial update to a networked entity. Host-authoritative: only the host may call this. */\n setState: (id: string, partialState: Partial<EntityState>) => void;\n /** Reactive map of all current networked entity states. */\n entities: Map<string, EntityState>;\n}\n\nconst CHANNEL_NAME = \"carver:network-state\";\n\n/**\n * Phase 4.4 – Advanced escape-hatch hook for direct networked entity management.\n *\n * Provides host-authoritative spawn / despawn, client requestSpawn,\n * and direct state read / write over a reliable+ordered data channel.\n */\nexport function useNetworkState(): UseNetworkStateReturn {\n const { networkManager } = useMultiplayerContext();\n\n // Entity state map – drives reactive re-renders.\n const [entities, setEntities] = useState<Map<string, EntityState>>(\n () => new Map(),\n );\n\n // Keep a mutable ref mirror so callbacks always see the latest map\n // without needing to re-create the channel listener on every state change.\n const entitiesRef = useRef<Map<string, EntityState>>(entities);\n entitiesRef.current = entities;\n\n // Channel ref – created once and cleaned up on unmount.\n const channelRef = useRef<CarverChannel<NetworkStateMessage> | null>(null);\n\n // ── Helpers (internal, not exposed) ──\n\n /** Immutably replace the entities map so React picks up the change. */\n const replaceEntities = useCallback(\n (updater: (prev: Map<string, EntityState>) => Map<string, EntityState>) => {\n setEntities((prev) => {\n const next = updater(prev);\n entitiesRef.current = next;\n return next;\n });\n },\n [],\n );\n\n /** Apply a spawn locally and update React state. */\n const applySpawn = useCallback(\n (id: string, state: EntityState) => {\n replaceEntities((prev) => {\n const next = new Map(prev);\n next.set(id, state);\n return next;\n });\n },\n [replaceEntities],\n );\n\n /** Apply a despawn locally and update React state. */\n const applyDespawn = useCallback(\n (id: string) => {\n replaceEntities((prev) => {\n if (!prev.has(id)) return prev; // no-op\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n },\n [replaceEntities],\n );\n\n // ── Channel setup ──\n\n useEffect(() => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n const channel = transport.createChannel<NetworkStateMessage>(CHANNEL_NAME, {\n reliable: true,\n ordered: true,\n });\n channelRef.current = channel;\n\n channel.onReceive((msg: NetworkStateMessage, _peerId: string) => {\n switch (msg.action) {\n // --- Spawn broadcast (sent by host to everyone) ---\n case \"spawn\": {\n if (msg.state) {\n applySpawn(msg.id, msg.state as EntityState);\n }\n break;\n }\n\n // --- Despawn broadcast (sent by host to everyone) ---\n case \"despawn\": {\n applyDespawn(msg.id);\n break;\n }\n\n // --- Request-spawn (client -> host only) ---\n case \"request-spawn\": {\n // Only the host processes spawn requests.\n if (!transport.isHost) break;\n\n // Validate: reject if id already exists.\n if (entitiesRef.current.has(msg.id)) break;\n\n // Build an EntityState from the config the client sent.\n // The config should at minimum contain an id. We merge defaults\n // for a 2D entity so the state is always well-formed.\n const config = (msg.state ?? {}) as Record<string, unknown>;\n const newState: EntityState = {\n id: msg.id,\n x: 0,\n y: 0,\n a: 0,\n vx: 0,\n vy: 0,\n va: 0,\n ...config,\n // Ensure id is authoritative.\n ...(config.id !== undefined ? {} : {}),\n } as EntityState;\n // Force the id to match the message id (authoritative).\n (newState as { id: string }).id = msg.id;\n\n // Apply locally on the host.\n applySpawn(msg.id, newState);\n\n // Broadcast spawn to all peers (including the requester).\n channel.send({ action: \"spawn\", id: msg.id, state: newState });\n break;\n }\n }\n });\n\n return () => {\n channel.close();\n channelRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [networkManager.transport, applySpawn, applyDespawn]);\n\n // ── Public API ──\n\n /**\n * Host only. Creates a networked entity and broadcasts a spawn event to all peers.\n */\n const spawn = useCallback(\n (id: string, initialState: EntityState) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\"[useNetworkState] spawn called before transport is ready.\");\n return;\n }\n if (!transport.isHost) {\n console.warn(\n \"[useNetworkState] spawn is host-only. Use requestSpawn() from a client.\",\n );\n return;\n }\n if (entitiesRef.current.has(id)) {\n console.warn(\n `[useNetworkState] entity \"${id}\" already exists. Ignoring spawn.`,\n );\n return;\n }\n\n // Ensure the id field matches.\n const state: EntityState = { ...initialState, id } as EntityState;\n\n // Apply locally.\n applySpawn(id, state);\n\n // Broadcast to all peers.\n channelRef.current?.send({ action: \"spawn\", id, state });\n },\n [networkManager, applySpawn],\n );\n\n /**\n * Host only. Removes a networked entity and broadcasts a despawn event to all peers.\n */\n const despawn = useCallback(\n (id: string) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\"[useNetworkState] despawn called before transport is ready.\");\n return;\n }\n if (!transport.isHost) {\n console.warn(\"[useNetworkState] despawn is host-only.\");\n return;\n }\n if (!entitiesRef.current.has(id)) {\n console.warn(\n `[useNetworkState] entity \"${id}\" does not exist. Ignoring despawn.`,\n );\n return;\n }\n\n // Apply locally.\n applyDespawn(id);\n\n // Broadcast to all peers.\n channelRef.current?.send({ action: \"despawn\", id });\n },\n [networkManager, applyDespawn],\n );\n\n /**\n * Client sends a spawn request to the host. The host validates the request\n * (no duplicate id) and, if valid, spawns the entity and broadcasts to everyone.\n */\n const requestSpawn = useCallback(\n (id: string, config: Record<string, unknown>) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\n \"[useNetworkState] requestSpawn called before transport is ready.\",\n );\n return;\n }\n\n // If we ARE the host, just handle it inline for convenience.\n if (transport.isHost) {\n if (entitiesRef.current.has(id)) {\n console.warn(\n `[useNetworkState] entity \"${id}\" already exists. Ignoring requestSpawn.`,\n );\n return;\n }\n const newState: EntityState = {\n id,\n x: 0,\n y: 0,\n a: 0,\n vx: 0,\n vy: 0,\n va: 0,\n ...config,\n } as EntityState;\n (newState as { id: string }).id = id;\n applySpawn(id, newState);\n channelRef.current?.send({ action: \"spawn\", id, state: newState });\n return;\n }\n\n // Send request to host.\n channelRef.current?.send(\n { action: \"request-spawn\", id, state: config },\n transport.hostId,\n );\n },\n [networkManager, applySpawn],\n );\n\n /**\n * Read the current state of a networked entity by id.\n */\n const getState = useCallback(\n (id: string): EntityState | undefined => {\n return entitiesRef.current.get(id);\n },\n [],\n );\n\n /**\n * Write a partial update to a networked entity's state.\n * Host-authoritative: only the host may call this.\n */\n const setState = useCallback(\n (id: string, partialState: Partial<EntityState>) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\"[useNetworkState] setState called before transport is ready.\");\n return;\n }\n if (!transport.isHost) {\n console.warn(\"[useNetworkState] setState is host-only.\");\n return;\n }\n\n const existing = entitiesRef.current.get(id);\n if (!existing) {\n console.warn(\n `[useNetworkState] entity \"${id}\" does not exist. Cannot setState.`,\n );\n return;\n }\n\n const updated: EntityState = {\n ...existing,\n ...partialState,\n id, // id is immutable\n } as EntityState;\n\n replaceEntities((prev) => {\n const next = new Map(prev);\n next.set(id, updated);\n return next;\n });\n\n // Broadcast the full updated state so clients stay in sync.\n channelRef.current?.send({ action: \"spawn\", id, state: updated });\n },\n [networkManager, replaceEntities],\n );\n\n return {\n spawn,\n despawn,\n requestSpawn,\n getState,\n setState,\n entities,\n };\n}\n","/* ------------------------------------------------------------------ */\n/* DebugOverlay – DOM-based stats panel for multiplayer diagnostics */\n/* ------------------------------------------------------------------ */\n\nexport interface DebugOverlayOptions {\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n /** Keyboard key used to toggle visibility (default: \"F3\") */\n keyboardToggle?: string;\n}\n\nexport interface DebugStats {\n tick: number;\n serverTick: number;\n drift: number;\n /** Per-peer latency map or a single average value */\n latencyMs: Map<string, number> | number;\n /** Packet-loss rate in the range 0-1 */\n packetLossRate: number;\n /** Inbound bandwidth in bytes / second */\n bandwidthIn: number;\n /** Outbound bandwidth in bytes / second */\n bandwidthOut: number;\n networkQuality: \"good\" | \"degraded\" | \"poor\";\n peerCount: number;\n isHost: boolean;\n syncMode: string;\n}\n\nconst QUALITY_COLORS: Record<string, string> = {\n good: \"#00ff00\",\n degraded: \"#ffff00\",\n poor: \"#ff4444\",\n};\n\nexport class DebugOverlay {\n private el: HTMLDivElement;\n private visible = true;\n private lastHTML = \"\";\n private readonly keyboardToggle: string;\n private readonly handleKey: (e: KeyboardEvent) => void;\n\n constructor(options?: DebugOverlayOptions) {\n const opts = options ?? {};\n this.keyboardToggle = opts.keyboardToggle ?? \"F3\";\n\n /* ---- create container ---- */\n this.el = document.createElement(\"div\");\n\n const pos = opts.position ?? \"top-right\";\n const posStyles = this.positionStyles(pos);\n\n Object.assign(this.el.style, {\n position: \"fixed\",\n ...posStyles,\n background: \"rgba(0,0,0,0.75)\",\n color: \"#00ff00\",\n fontFamily: \"'Courier New', monospace\",\n fontSize: \"11px\",\n padding: \"8px\",\n borderRadius: \"4px\",\n zIndex: \"99999\",\n pointerEvents: \"none\",\n whiteSpace: \"pre\",\n lineHeight: \"1.4\",\n minWidth: \"200px\",\n boxSizing: \"border-box\",\n } as CSSStyleDeclaration);\n\n document.body.appendChild(this.el);\n\n /* ---- keyboard listener ---- */\n this.handleKey = (e: KeyboardEvent) => {\n if (e.key === this.keyboardToggle) {\n e.preventDefault();\n this.toggle();\n }\n };\n window.addEventListener(\"keydown\", this.handleKey);\n }\n\n /* ---- public API ---- */\n\n update(stats: DebugStats): void {\n if (!this.visible) return;\n\n const latencyDisplay = this.formatLatency(stats.latencyMs);\n const qualityColor = QUALITY_COLORS[stats.networkQuality] ?? \"#00ff00\";\n const bwIn = (stats.bandwidthIn / 1024).toFixed(1);\n const bwOut = (stats.bandwidthOut / 1024).toFixed(1);\n const loss = (stats.packetLossRate * 100).toFixed(1);\n\n const html =\n `<b style=\"color:#00ccff\">== NET DEBUG ==</b>\\n` +\n `tick ${stats.tick}\\n` +\n `srv tick ${stats.serverTick}\\n` +\n `drift ${stats.drift}\\n` +\n `latency ${latencyDisplay} ms\\n` +\n `loss ${loss}%\\n` +\n `bw in ${bwIn} KB/s\\n` +\n `bw out ${bwOut} KB/s\\n` +\n `quality <span style=\"color:${qualityColor}\">${stats.networkQuality}</span>\\n` +\n `peers ${stats.peerCount}\\n` +\n `host ${stats.isHost ? \"YES\" : \"NO\"}\\n` +\n `sync ${stats.syncMode}`;\n\n /* Only touch the DOM when something changed */\n if (html !== this.lastHTML) {\n this.el.innerHTML = html;\n this.lastHTML = html;\n }\n }\n\n show(): void {\n this.visible = true;\n this.el.style.display = \"block\";\n }\n\n hide(): void {\n this.visible = false;\n this.el.style.display = \"none\";\n }\n\n toggle(): void {\n if (this.visible) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n destroy(): void {\n window.removeEventListener(\"keydown\", this.handleKey);\n this.el.remove();\n }\n\n /* ---- helpers ---- */\n\n private positionStyles(\n pos: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\",\n ): Record<string, string> {\n switch (pos) {\n case \"top-left\":\n return { top: \"8px\", left: \"8px\" };\n case \"top-right\":\n return { top: \"8px\", right: \"8px\" };\n case \"bottom-left\":\n return { bottom: \"8px\", left: \"8px\" };\n case \"bottom-right\":\n return { bottom: \"8px\", right: \"8px\" };\n }\n }\n\n private formatLatency(latency: Map<string, number> | number): string {\n if (typeof latency === \"number\") {\n return latency.toFixed(1);\n }\n if (latency.size === 0) return \"—\";\n let sum = 0;\n latency.forEach((v) => (sum += v));\n return (sum / latency.size).toFixed(1);\n }\n}\n","import type { EntityState } from \"../types\";\n\n// ── Options ──\n\nexport interface InterestManagerOptions {\n /** Spatial hash cell size in world units. Default: 50 */\n cellSize?: number;\n /** Default relevance radius around a client's position. Default: 200 */\n defaultRadius?: number;\n /** Entity ids/names that are always sent to every client. */\n alwaysRelevant?: string[];\n}\n\n// ── InterestManager ──\n\n/**\n * Spatial-hash-grid area-of-interest filter.\n *\n * Runs on the host side. Each tick the host feeds the full entity map via\n * `updateEntities`, then queries per-client relevance with\n * `getRelevantEntities` (or creates a single filter callback via\n * `createFilter` for `HostAuthority.setInterestFilter`).\n */\nexport class InterestManager {\n /** cell-key -> set of entity ids occupying that cell */\n private _cells: Map<string, Set<string>>;\n /** entity id -> last-known 3D position */\n private _entityPositions: Map<string, { x: number; y: number; z: number }>;\n private _cellSize: number;\n private _defaultRadius: number;\n private _alwaysRelevant: Set<string>;\n\n constructor(options?: InterestManagerOptions) {\n this._cellSize = options?.cellSize ?? 50;\n this._defaultRadius = options?.defaultRadius ?? 200;\n this._alwaysRelevant = new Set(options?.alwaysRelevant ?? []);\n this._cells = new Map();\n this._entityPositions = new Map();\n }\n\n // ── Public API ──\n\n /**\n * Rebuild the spatial hash from the authoritative entity map.\n * Called once per host tick before any relevance queries.\n */\n updateEntities(entities: Map<string, EntityState>): void {\n // Clear previous grid state\n this._cells.clear();\n this._entityPositions.clear();\n\n for (const [id, entity] of entities) {\n const z = \"z\" in entity ? (entity as { z: number }).z : 0;\n const pos = { x: entity.x, y: entity.y, z };\n this._entityPositions.set(id, pos);\n\n const key = this._cellKey(pos.x, pos.y, pos.z);\n let bucket = this._cells.get(key);\n if (!bucket) {\n bucket = new Set();\n this._cells.set(key, bucket);\n }\n bucket.add(id);\n }\n }\n\n /**\n * Return the set of entity ids relevant to a single client.\n *\n * Relevance is the *union* of:\n * 1. Entities whose cell overlaps the client's bounding sphere\n * 2. Entities in the `alwaysRelevant` set\n * 3. Entities owned by this client\n */\n getRelevantEntities(\n clientPosition: { x: number; y: number; z?: number },\n clientId: string,\n owners: Map<string, string>,\n overrideRadius?: number,\n ): Set<string> {\n const radius = overrideRadius ?? this._defaultRadius;\n const cx = clientPosition.x;\n const cy = clientPosition.y;\n const cz = clientPosition.z ?? 0;\n\n const result = new Set<string>();\n\n // 1. Spatial query — iterate every cell that the bounding box of the\n // sphere overlaps.\n const minCellX = Math.floor((cx - radius) / this._cellSize);\n const maxCellX = Math.floor((cx + radius) / this._cellSize);\n const minCellY = Math.floor((cy - radius) / this._cellSize);\n const maxCellY = Math.floor((cy + radius) / this._cellSize);\n const minCellZ = Math.floor((cz - radius) / this._cellSize);\n const maxCellZ = Math.floor((cz + radius) / this._cellSize);\n\n for (let ix = minCellX; ix <= maxCellX; ix++) {\n for (let iy = minCellY; iy <= maxCellY; iy++) {\n for (let iz = minCellZ; iz <= maxCellZ; iz++) {\n const key = `${ix},${iy},${iz}`;\n const bucket = this._cells.get(key);\n if (bucket) {\n for (const entityId of bucket) {\n result.add(entityId);\n }\n }\n }\n }\n }\n\n // 2. Always-relevant entities (must still exist in the current frame)\n for (const id of this._alwaysRelevant) {\n if (this._entityPositions.has(id)) {\n result.add(id);\n }\n }\n\n // 3. Self-owned entities\n for (const [entityId, ownerId] of owners) {\n if (ownerId === clientId && this._entityPositions.has(entityId)) {\n result.add(entityId);\n }\n }\n\n return result;\n }\n\n /**\n * Build a filter callback compatible with\n * `HostAuthority.setInterestFilter`.\n *\n * The returned function closes over a single relevance pass for every\n * known client so that per-entity filtering during broadcast is a cheap\n * `Set.has` lookup.\n *\n * @param clientPositions peerId -> position of that client's camera/player\n * @param owners entityId -> ownerPeerId\n */\n createFilter(\n clientPositions: Map<string, { x: number; y: number; z?: number }>,\n owners: Map<string, string>,\n ): (entityId: string, peerId: string) => boolean {\n // Pre-compute the relevant set for every known client once.\n const relevanceSets = new Map<string, Set<string>>();\n for (const [peerId, pos] of clientPositions) {\n relevanceSets.set(\n peerId,\n this.getRelevantEntities(pos, peerId, owners),\n );\n }\n\n return (entityId: string, peerId: string): boolean => {\n const set = relevanceSets.get(peerId);\n // If we have no position info for this client, include everything\n // (fail-open so new joiners still receive data).\n if (!set) return true;\n return set.has(entityId);\n };\n }\n\n /** Remove all data from the grid. */\n clear(): void {\n this._cells.clear();\n this._entityPositions.clear();\n }\n\n // ── Private helpers ──\n\n private _cellKey(x: number, y: number, z: number): string {\n const cx = Math.floor(x / this._cellSize);\n const cy = Math.floor(y / this._cellSize);\n const cz = Math.floor(z / this._cellSize);\n return `${cx},${cy},${cz}`;\n }\n}\n"],"mappings":"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","names":["createElement","useContext","useContext","createElement","useEffect","useRef","useRef","useEffect","useState","useEffect","useCallback","useRef","useState","useRef","useCallback","useEffect","useState","useEffect","useCallback","useState","useEffect","useCallback","useCallback","useCallback","useEffect","useRef","useState","useCallback","useRef","useState","useCallback","useEffect","useRef","useEffect","useCallback","useRef","useEffect","useCallback","useState","useEffect","useCallback","useRef","useState","useRef","useCallback","useEffect"]}
1
+ {"version":3,"sources":["../src/components/MultiplayerProvider.ts","../src/core/TickKeeper.ts","../src/core/codec.ts","../src/core/NetworkManager.ts","../src/core/MultiplayerContext.ts","../src/components/MultiplayerBridge.ts","../src/hooks/useRoom.ts","../src/hooks/useLobby.ts","../src/hooks/usePlayers.ts","../src/hooks/useHost.ts","../src/hooks/useMultiplayer.ts","../src/core/NetworkSimulator.ts","../src/hooks/useNetworkEvents.ts","../src/hooks/useNetworkState.ts","../src/core/DebugOverlay.ts","../src/core/InterestManager.ts"],"sourcesContent":["import { createElement, useRef, useEffect } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { StrategyConfig } from \"../transport/strategy/types\";\nimport { MqttStrategy } from \"../transport/strategy/mqtt\";\nimport { FirebaseStrategy } from \"../transport/strategy/firebase\";\nimport { NetworkManager } from \"../core/NetworkManager\";\nimport { MultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { MultiplayerContextValue } from \"../core/MultiplayerContext\";\nimport type { SignalingStrategy } from \"../transport/strategy/types\";\n\nexport interface MultiplayerProviderProps {\n /**\n * Unique application identifier. Used to namespace rooms across the\n * signaling network so different games don't interfere.\n */\n appId: string;\n /**\n * Signaling strategy configuration. Defaults to MQTT (free public brokers).\n *\n * ```tsx\n * // Free (MQTT, zero config)\n * <MultiplayerProvider appId=\"my-game\">\n *\n * // Firebase (your own project)\n * <MultiplayerProvider\n * appId=\"my-game\"\n * strategy={{ type: 'firebase', databaseURL: 'https://my-project.firebaseio.com' }}\n * >\n * ```\n */\n strategy?: StrategyConfig;\n /**\n * ICE servers (STUN + TURN). Defaults to public Google/Cloudflare STUN.\n *\n * To add your own TURN server (e.g. Cloudflare TURN):\n * ```tsx\n * <MultiplayerProvider\n * appId=\"my-game\"\n * iceServers={[\n * { urls: 'stun:stun.cloudflare.com:3478' },\n * { urls: 'turn:turn.cloudflare.com:3478', username: '...', credential: '...' },\n * ]}\n * >\n * ```\n */\n iceServers?: RTCIceServer[];\n children: ReactNode;\n}\n\nfunction createStrategy(appId: string, config?: StrategyConfig): SignalingStrategy {\n if (!config || config.type === 'mqtt') {\n return new MqttStrategy(appId, config ?? { type: 'mqtt' });\n }\n if (config.type === 'firebase') {\n return new FirebaseStrategy(appId, config);\n }\n throw new Error(`Unknown strategy type: ${(config as any).type}`);\n}\n\nexport function MultiplayerProvider({\n appId,\n strategy: strategyConfig,\n iceServers,\n children,\n}: MultiplayerProviderProps) {\n const managerRef = useRef<NetworkManager | null>(null);\n const strategyRef = useRef<SignalingStrategy | null>(null);\n const destroyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n if (!managerRef.current) {\n managerRef.current = new NetworkManager();\n }\n if (!strategyRef.current) {\n strategyRef.current = createStrategy(appId, strategyConfig);\n }\n\n useEffect(() => {\n // React StrictMode simulates unmount/remount. Destroying synchronously in\n // cleanup left the remounted tree holding already-destroyed instances\n // captured at render time (dead lobby, dead transport). Defer destruction\n // one tick and cancel it when the effect re-runs.\n if (destroyTimerRef.current) {\n clearTimeout(destroyTimerRef.current);\n destroyTimerRef.current = null;\n }\n return () => {\n destroyTimerRef.current = setTimeout(() => {\n destroyTimerRef.current = null;\n strategyRef.current?.destroy();\n strategyRef.current = null;\n managerRef.current?.destroy();\n managerRef.current = null;\n }, 0);\n };\n }, []);\n\n const value: MultiplayerContextValue = {\n appId,\n strategy: strategyRef.current,\n iceServers,\n networkManager: managerRef.current,\n };\n\n return createElement(MultiplayerContext.Provider, { value }, children);\n}\n","/**\n * Accumulator-based fixed timestep with drift-aware time dilation.\n * Adapted from lumbernet's LumberTickKeeper.\n */\nexport class TickKeeper {\n private _tickRate: number;\n private _tickDelta: number;\n private _accumulator = 0;\n private _tick = 0;\n private _serverTick = 0;\n private _alpha = 0;\n private _timeScale = 1;\n\n // Drift correction zones\n private static readonly DRIFT_BEHIND_THRESHOLD = -5;\n private static readonly DRIFT_AHEAD_THRESHOLD = 5;\n private static readonly SPEED_UP_SCALE = 1.5;\n private static readonly SLOW_DOWN_SCALE = 0.1;\n private static readonly NORMAL_SCALE = 1.0;\n\n constructor(tickRate = 60) {\n this._tickRate = tickRate;\n this._tickDelta = 1 / tickRate;\n }\n\n get tick(): number {\n return this._tick;\n }\n\n get serverTick(): number {\n return this._serverTick;\n }\n\n get tickDelta(): number {\n return this._tickDelta;\n }\n\n get tickRate(): number {\n return this._tickRate;\n }\n\n /** Interpolation alpha for rendering between ticks (0-1) */\n get alpha(): number {\n return this._alpha;\n }\n\n /** Current time scale (affected by drift correction) */\n get timeScale(): number {\n return this._timeScale;\n }\n\n /** Ticks ahead of server (positive = ahead, negative = behind) */\n get drift(): number {\n return this._tick - this._serverTick;\n }\n\n /** Update server tick from received snapshot */\n setServerTick(serverTick: number): void {\n this._serverTick = serverTick;\n this._updateDriftCorrection();\n }\n\n /** Hard-set the local tick (prediction rollback snap). Does not touch the accumulator. */\n snapTick(tick: number): void {\n this._tick = tick;\n this._updateDriftCorrection();\n }\n\n /**\n * Accumulate time and return the number of fixed ticks to process.\n * Call this once per render frame with the raw frame delta.\n */\n update(rawDelta: number): number {\n // Cap delta to prevent spiral-of-death (e.g., after tab switch)\n const maxDelta = this._tickDelta * 8;\n const delta = Math.min(rawDelta, maxDelta) * this._timeScale;\n\n this._accumulator += delta;\n\n let ticksThisFrame = 0;\n while (this._accumulator >= this._tickDelta) {\n this._accumulator -= this._tickDelta;\n this._tick++;\n ticksThisFrame++;\n }\n\n // Compute interpolation alpha\n this._alpha = this._accumulator / this._tickDelta;\n\n return ticksThisFrame;\n }\n\n /** Reset to initial state */\n reset(): void {\n this._accumulator = 0;\n this._tick = 0;\n this._serverTick = 0;\n this._alpha = 0;\n this._timeScale = 1;\n }\n\n /** Set tick rate (updates tickDelta accordingly) */\n setTickRate(rate: number): void {\n this._tickRate = rate;\n this._tickDelta = 1 / rate;\n }\n\n private _updateDriftCorrection(): void {\n const drift = this.drift;\n if (drift < TickKeeper.DRIFT_BEHIND_THRESHOLD) {\n // Too far behind server -- speed up\n this._timeScale = TickKeeper.SPEED_UP_SCALE;\n } else if (drift > TickKeeper.DRIFT_AHEAD_THRESHOLD) {\n // Too far ahead of server -- slow down\n this._timeScale = TickKeeper.SLOW_DOWN_SCALE;\n } else {\n // Healthy zone\n this._timeScale = TickKeeper.NORMAL_SCALE;\n }\n }\n}\n","import { pack, unpack } from \"msgpackr\";\nimport type { EntityState, EntityState2D, EntityState3D, PlayerInput, SnapshotPacket } from \"../types\";\n\n/** Configuration for delta thresholds */\nexport interface DeltaThresholds {\n position: number;\n rotation: number;\n velocity: number;\n custom: 'strict' | number;\n}\n\n/** Quantization config: number of decimal places to keep */\nexport interface QuantizeConfig {\n position?: number;\n rotation?: number;\n velocity?: number;\n}\n\nconst DEFAULT_THRESHOLDS: DeltaThresholds = {\n position: 0.01,\n rotation: 0.001,\n velocity: 0.05,\n custom: 'strict',\n};\n\n/**\n * Snapshot ring buffer: stores recent snapshots for delta computation.\n */\nexport class SnapshotBuffer {\n private _buffer: Map<number, Map<string, EntityState>>; // tick -> (entityId -> state)\n private _capacity: number;\n\n constructor(capacity = 120) {\n this._capacity = capacity;\n this._buffer = new Map();\n }\n\n /** Store a snapshot at the given tick */\n store(tick: number, entities: Map<string, EntityState>): void {\n this._buffer.set(tick, entities);\n // Evict old entries by iterating actual keys (handles non-contiguous ticks)\n if (this._buffer.size > this._capacity) {\n const sortedTicks = Array.from(this._buffer.keys()).sort((a, b) => a - b);\n const toRemove = sortedTicks.length - this._capacity;\n for (let i = 0; i < toRemove; i++) {\n this._buffer.delete(sortedTicks[i]);\n }\n }\n }\n\n /** Get a snapshot at the given tick */\n get(tick: number): Map<string, EntityState> | undefined {\n return this._buffer.get(tick);\n }\n\n /** Clear all stored snapshots */\n clear(): void {\n this._buffer.clear();\n }\n}\n\n/**\n * Codec handles serialization and delta compression for network state.\n */\nexport class Codec {\n private _thresholds: DeltaThresholds;\n private _quantize: QuantizeConfig | undefined;\n private _is2D: boolean;\n\n constructor(options?: {\n thresholds?: Partial<DeltaThresholds>;\n quantize?: QuantizeConfig;\n is2D?: boolean;\n }) {\n this._thresholds = { ...DEFAULT_THRESHOLDS, ...options?.thresholds };\n this._quantize = options?.quantize;\n this._is2D = options?.is2D ?? false;\n }\n\n /** Serialize entity states to binary (msgpackr) */\n serialize(entities: EntityState[]): Uint8Array {\n const quantized = this._quantize ? entities.map(e => this._quantizeEntity(e)) : entities;\n return pack(quantized);\n }\n\n /** Deserialize binary to entity states */\n deserialize(data: Uint8Array): EntityState[] {\n return unpack(data) as EntityState[];\n }\n\n /**\n * Compute delta: only include entities that changed beyond thresholds\n * since the baseline snapshot.\n * Returns null if nothing changed.\n */\n computeDelta(\n current: Map<string, EntityState>,\n baseline: Map<string, EntityState> | undefined,\n ): EntityState[] | null {\n // No baseline = keyframe (send everything)\n if (!baseline) {\n return Array.from(current.values());\n }\n\n const changed: EntityState[] = [];\n for (const [id, entity] of current) {\n const prev = baseline.get(id);\n if (!prev || this._hasChanged(entity, prev)) {\n changed.push(entity);\n }\n }\n\n // Include removed entities as tombstones (entities in baseline but not in current)\n // Tombstones are indicated by entities with only an id field\n for (const id of baseline.keys()) {\n if (!current.has(id)) {\n // Tombstone: minimal entity state signaling removal\n if (this._is2D) {\n changed.push({ id, x: 0, y: 0, a: 0, vx: 0, vy: 0, va: 0, c: { __removed: true } } as EntityState2D);\n } else {\n changed.push({ id, x: 0, y: 0, z: 0, qx: 0, qy: 0, qz: 0, qw: 1, vx: 0, vy: 0, vz: 0, wx: 0, wy: 0, wz: 0, c: { __removed: true } } as EntityState3D);\n }\n }\n }\n\n return changed.length > 0 ? changed : null;\n }\n\n /** Serialize a delta snapshot packet (optionally embedding the host's own input as `hi`) */\n serializeDelta(\n tick: number,\n baseTick: number,\n current: Map<string, EntityState>,\n baseline: Map<string, EntityState> | undefined,\n hostInput?: PlayerInput,\n ): Uint8Array | null {\n const delta = this.computeDelta(current, baseline);\n if (!delta) return null;\n\n const packet: SnapshotPacket = {\n t: tick,\n b: baseline ? baseTick : -1, // -1 = keyframe\n s: this.serialize(delta),\n ...(hostInput !== undefined ? { hi: hostInput } : {}),\n };\n\n return pack(packet);\n }\n\n /** Deserialize a snapshot packet */\n deserializePacket(data: Uint8Array): {\n tick: number;\n baseTick: number;\n entities: EntityState[];\n hostInput: PlayerInput | undefined;\n } {\n const packet = unpack(data) as { t: number; b: number; s: Uint8Array; hi?: PlayerInput };\n return {\n tick: packet.t,\n baseTick: packet.b,\n entities: this.deserialize(packet.s),\n hostInput: packet.hi,\n };\n }\n\n private _hasChanged(current: EntityState, prev: EntityState): boolean {\n const t = this._thresholds;\n\n // Position\n if (Math.abs(current.x - prev.x) > t.position) return true;\n if (Math.abs(current.y - prev.y) > t.position) return true;\n\n if ('z' in current && 'z' in prev) {\n // 3D\n const c = current as EntityState3D;\n const p = prev as EntityState3D;\n if (Math.abs(c.z - p.z) > t.position) return true;\n\n // Rotation (quaternion)\n if (Math.abs(c.qx - p.qx) > t.rotation) return true;\n if (Math.abs(c.qy - p.qy) > t.rotation) return true;\n if (Math.abs(c.qz - p.qz) > t.rotation) return true;\n if (Math.abs(c.qw - p.qw) > t.rotation) return true;\n\n // Velocity\n if (Math.abs(c.vx - p.vx) > t.velocity) return true;\n if (Math.abs(c.vy - p.vy) > t.velocity) return true;\n if (Math.abs(c.vz - p.vz) > t.velocity) return true;\n\n // Angular velocity\n if (Math.abs(c.wx - p.wx) > t.velocity) return true;\n if (Math.abs(c.wy - p.wy) > t.velocity) return true;\n if (Math.abs(c.wz - p.wz) > t.velocity) return true;\n } else {\n // 2D\n const c = current as EntityState2D;\n const p = prev as EntityState2D;\n\n // Rotation\n if (Math.abs(c.a - p.a) > t.rotation) return true;\n\n // Velocity\n if (Math.abs(c.vx - p.vx) > t.velocity) return true;\n if (Math.abs(c.vy - p.vy) > t.velocity) return true;\n\n // Angular velocity\n if (Math.abs(c.va - p.va) > t.velocity) return true;\n }\n\n // Custom properties\n if (current.c || prev.c) {\n const cc = current.c ?? {};\n const pc = prev.c ?? {};\n const allKeys = new Set([...Object.keys(cc), ...Object.keys(pc)]);\n for (const key of allKeys) {\n if (t.custom === 'strict') {\n if (cc[key] !== pc[key]) return true;\n } else {\n const diff = typeof cc[key] === 'number' && typeof pc[key] === 'number'\n ? Math.abs((cc[key] as number) - (pc[key] as number))\n : cc[key] === pc[key] ? 0 : 1;\n if (diff > t.custom) return true;\n }\n }\n }\n\n return false;\n }\n\n private _quantizeEntity(entity: EntityState): EntityState {\n const q = this._quantize!;\n const result = { ...entity };\n\n if (q.position !== undefined) {\n const m = Math.pow(10, q.position);\n result.x = Math.round(result.x * m) / m;\n result.y = Math.round(result.y * m) / m;\n if ('z' in result) {\n (result as EntityState3D).z = Math.round((result as EntityState3D).z * m) / m;\n }\n }\n\n if (q.rotation !== undefined) {\n const m = Math.pow(10, q.rotation);\n if ('a' in result) {\n (result as EntityState2D).a = Math.round((result as EntityState2D).a * m) / m;\n } else if ('qx' in result) {\n const r = result as EntityState3D;\n r.qx = Math.round(r.qx * m) / m;\n r.qy = Math.round(r.qy * m) / m;\n r.qz = Math.round(r.qz * m) / m;\n r.qw = Math.round(r.qw * m) / m;\n }\n }\n\n if (q.velocity !== undefined) {\n const m = Math.pow(10, q.velocity);\n result.vx = Math.round(result.vx * m) / m;\n result.vy = Math.round(result.vy * m) / m;\n if ('vz' in result) {\n const r = result as EntityState3D;\n r.vz = Math.round(r.vz * m) / m;\n r.wx = Math.round(r.wx * m) / m;\n r.wy = Math.round(r.wy * m) / m;\n r.wz = Math.round(r.wz * m) / m;\n }\n if ('va' in result) {\n (result as EntityState2D).va = Math.round((result as EntityState2D).va * m) / m;\n }\n }\n\n return result;\n }\n}\n","import type {\n CarverTransport,\n ConnectionState,\n CarverMultiplayerError,\n UseMultiplayerOptions,\n Player,\n Room,\n SyncMode,\n NetworkQuality,\n} from \"../types\";\nimport { TickKeeper } from \"./TickKeeper\";\nimport { Codec, SnapshotBuffer } from \"./codec\";\n\n/**\n * Central orchestrator for the multiplayer system.\n * Holds references to the active transport, sync engine, room state, and codec.\n * One instance per MultiplayerProvider.\n */\nexport class NetworkManager {\n // Transport\n private _transport: CarverTransport | null = null;\n private _connectionState: ConnectionState = 'disconnected';\n\n // Room state\n private _room: Room | null = null;\n private _players = new Map<string, Player>();\n\n // Sync state\n private _syncMode: SyncMode = 'snapshot';\n private _tickKeeper: TickKeeper;\n private _codec: Codec;\n private _snapshotBuffer: SnapshotBuffer;\n private _networkQuality: NetworkQuality = 'good';\n\n // Options\n private _options: UseMultiplayerOptions;\n\n // Change listeners\n private _connectionListeners: ((state: ConnectionState) => void)[] = [];\n private _playerListeners: (() => void)[] = [];\n private _roomListeners: (() => void)[] = [];\n private _errorListeners: ((error: CarverMultiplayerError) => void)[] = [];\n\n constructor(options: UseMultiplayerOptions = {}) {\n this._options = options;\n this._syncMode = options.mode ?? 'snapshot';\n this._tickKeeper = new TickKeeper(options.tickRate ?? 60);\n this._codec = new Codec({\n thresholds: options.deltaThresholds,\n quantize: options.quantize,\n });\n this._snapshotBuffer = new SnapshotBuffer();\n }\n\n // -- Getters --\n\n get transport(): CarverTransport | null {\n return this._transport;\n }\n\n get connectionState(): ConnectionState {\n return this._connectionState;\n }\n\n get room(): Room | null {\n return this._room;\n }\n\n get players(): Map<string, Player> {\n return this._players;\n }\n\n get selfId(): string | null {\n return this._transport?.peerId || null;\n }\n\n get isHost(): boolean {\n return this._transport?.isHost ?? false;\n }\n\n get hostId(): string | null {\n return this._transport?.hostId ?? null;\n }\n\n get syncMode(): SyncMode {\n return this._syncMode;\n }\n\n get tickKeeper(): TickKeeper {\n return this._tickKeeper;\n }\n\n get codec(): Codec {\n return this._codec;\n }\n\n get snapshotBuffer(): SnapshotBuffer {\n return this._snapshotBuffer;\n }\n\n get networkQuality(): NetworkQuality {\n return this._networkQuality;\n }\n\n get options(): UseMultiplayerOptions {\n return this._options;\n }\n\n // -- Transport management --\n\n setTransport(transport: CarverTransport): void {\n this._transport = transport;\n\n transport.onPeerJoin((peerId) => {\n // Add a player entry if not already present\n if (!this._players.has(peerId)) {\n this._players.set(peerId, {\n peerId,\n displayName: `Player-${peerId.slice(0, 4)}`,\n isHost: peerId === transport.hostId,\n isSelf: false,\n isReady: false,\n isConnected: true,\n metadata: {},\n latencyMs: 0,\n joinedAt: Date.now(),\n });\n }\n this._notifyPlayerListeners();\n });\n\n transport.onPeerUpdated((player) => {\n this._players.set(player.peerId, {\n ...player,\n isSelf: player.peerId === this.selfId,\n });\n this._notifyPlayerListeners();\n });\n\n transport.onPeerLeave((peerId) => {\n this._players.delete(peerId);\n this._notifyPlayerListeners();\n });\n\n transport.onHostChanged((_newHostId) => {\n this._notifyRoomListeners();\n });\n }\n\n // -- Connection state --\n\n setConnectionState(state: ConnectionState): void {\n this._connectionState = state;\n for (const listener of this._connectionListeners) listener(state);\n }\n\n onConnectionStateChange(cb: (state: ConnectionState) => void): () => void {\n this._connectionListeners.push(cb);\n return () => {\n const idx = this._connectionListeners.indexOf(cb);\n if (idx >= 0) this._connectionListeners.splice(idx, 1);\n };\n }\n\n // -- Room state --\n\n setRoom(room: Room): void {\n this._room = room;\n this._notifyRoomListeners();\n }\n\n onRoomChange(cb: () => void): () => void {\n this._roomListeners.push(cb);\n return () => {\n const idx = this._roomListeners.indexOf(cb);\n if (idx >= 0) this._roomListeners.splice(idx, 1);\n };\n }\n\n // -- Players --\n\n setPlayers(players: Player[]): void {\n this._players.clear();\n for (const p of players) {\n this._players.set(p.peerId, p);\n }\n this._notifyPlayerListeners();\n }\n\n updatePlayer(player: Player): void {\n this._players.set(player.peerId, player);\n this._notifyPlayerListeners();\n }\n\n removePlayer(peerId: string): void {\n this._players.delete(peerId);\n this._notifyPlayerListeners();\n }\n\n onPlayersChange(cb: () => void): () => void {\n this._playerListeners.push(cb);\n return () => {\n const idx = this._playerListeners.indexOf(cb);\n if (idx >= 0) this._playerListeners.splice(idx, 1);\n };\n }\n\n // -- Errors --\n\n emitError(error: CarverMultiplayerError): void {\n for (const listener of this._errorListeners) listener(error);\n }\n\n onError(cb: (error: CarverMultiplayerError) => void): () => void {\n this._errorListeners.push(cb);\n return () => {\n const idx = this._errorListeners.indexOf(cb);\n if (idx >= 0) this._errorListeners.splice(idx, 1);\n };\n }\n\n // -- Network quality --\n\n setNetworkQuality(quality: NetworkQuality): void {\n this._networkQuality = quality;\n }\n\n // -- Sync options --\n\n updateOptions(options: UseMultiplayerOptions): void {\n this._options = options;\n if (options.mode) this._syncMode = options.mode;\n if (options.tickRate) this._tickKeeper.setTickRate(options.tickRate);\n if (options.deltaThresholds || options.quantize) {\n this._codec = new Codec({\n thresholds: options.deltaThresholds,\n quantize: options.quantize,\n });\n }\n }\n\n // -- Cleanup --\n\n destroy(): void {\n this._transport?.disconnect();\n this._transport = null;\n this._connectionState = 'disconnected';\n this._room = null;\n this._players.clear();\n this._tickKeeper.reset();\n this._snapshotBuffer.clear();\n this._connectionListeners = [];\n this._playerListeners = [];\n this._roomListeners = [];\n this._errorListeners = [];\n }\n\n // -- Private --\n\n private _notifyPlayerListeners(): void {\n for (const listener of this._playerListeners) listener();\n }\n\n private _notifyRoomListeners(): void {\n for (const listener of this._roomListeners) listener();\n }\n}\n","import { createContext, useContext } from \"react\";\nimport type { SignalingStrategy } from \"../transport/strategy/types\";\nimport type { NetworkManager } from \"./NetworkManager\";\n\nexport interface MultiplayerContextValue {\n appId: string;\n strategy: SignalingStrategy;\n iceServers?: RTCIceServer[];\n networkManager: NetworkManager;\n}\n\nexport const MultiplayerContext = createContext<MultiplayerContextValue | null>(null);\n\nexport function useMultiplayerContext(): MultiplayerContextValue {\n const ctx = useContext(MultiplayerContext);\n if (!ctx) {\n throw new Error(\"useMultiplayerContext must be used inside a <MultiplayerProvider>.\");\n }\n return ctx;\n}\n","import { createElement, useContext } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { MultiplayerContext } from \"../core/MultiplayerContext\";\n\nexport interface MultiplayerBridgeProps {\n children: ReactNode;\n}\n\n/**\n * Bridges the MultiplayerContext from the parent React tree into an R3F Canvas.\n *\n * R3F's `<Canvas>` uses a separate React reconciler, so React contexts from the\n * parent tree are not automatically available inside the Canvas. This component\n * reads the MultiplayerContext value from the parent tree and re-provides it\n * inside the Canvas, making all CarverJS multiplayer hooks work seamlessly.\n *\n * Place `<MultiplayerBridge>` as a direct child of `<Game>`, wrapping `<World>`\n * and all scene content that uses multiplayer hooks.\n *\n * @example\n * ```tsx\n * <MultiplayerProvider appId=\"my-game\">\n * <Game mode=\"2d\">\n * <MultiplayerBridge>\n * <World>\n * <MyScene />\n * </World>\n * </MultiplayerBridge>\n * </Game>\n * </MultiplayerProvider>\n * ```\n */\nexport function MultiplayerBridge({ children }: MultiplayerBridgeProps) {\n const ctx = useContext(MultiplayerContext);\n if (!ctx) return createElement(\"group\", null, children);\n return createElement(MultiplayerContext.Provider, { value: ctx }, children);\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport { WebRTCTransport } from \"../transport/webrtc/WebRTCTransport\";\nimport type {\n ConnectionState,\n CarverMultiplayerError,\n CarverTransport,\n UseRoomOptions,\n Room,\n} from \"../types\";\n\nexport interface UseRoomReturn {\n roomId: string | null;\n connectionState: ConnectionState;\n isHost: boolean;\n hostId: string | null;\n selfId: string | null;\n room: Room | null;\n error: CarverMultiplayerError | null;\n join: (roomId: string, options?: { password?: string }) => Promise<void>;\n leave: () => void;\n setReady: (ready: boolean) => void;\n setMetadata: (meta: Record<string, unknown>) => void;\n setRoomMetadata: (meta: Record<string, unknown>) => void;\n transport: CarverTransport | null;\n}\n\nexport function useRoom(roomId?: string, options?: UseRoomOptions): UseRoomReturn {\n const { strategy, iceServers, networkManager } = useMultiplayerContext();\n const [connectionState, setConnectionState] = useState<ConnectionState>('disconnected');\n const [isHost, setIsHost] = useState(false);\n const [hostId, setHostId] = useState<string | null>(null);\n const [selfId, setSelfId] = useState<string | null>(null);\n const [currentRoomId, setCurrentRoomId] = useState<string | null>(null);\n const [error, setError] = useState<CarverMultiplayerError | null>(null);\n const [transport, setTransport] = useState<CarverTransport | null>(null);\n const [room, setRoom] = useState<Room | null>(null);\n const reconnectAttemptsRef = useRef(0);\n const maxReconnectAttempts = options?.reconnectAttempts ?? 3;\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // Create transport based on options\n const createTransport = useCallback((): CarverTransport => {\n const opt = optionsRef.current;\n // Allow fully custom transport instances\n if (opt?.transport && typeof opt.transport === 'object' && 'connect' in opt.transport) {\n return opt.transport as CarverTransport;\n }\n // Default: WebRTC with shared strategy and configurable ICE servers\n const servers = opt?.iceServers ?? iceServers;\n const policy = opt?.privacy === 'relay' ? 'relay' as const : 'all' as const;\n return new WebRTCTransport(strategy, servers, policy);\n }, [strategy, iceServers]);\n\n // Track transport ref for cleanup\n const transportRef = useRef<CarverTransport | null>(null);\n\n const doJoin = useCallback(async (targetRoomId: string, joinOptions?: { password?: string }) => {\n // Disconnect any existing transport (handles StrictMode re-mount)\n if (transportRef.current) {\n transportRef.current.disconnect();\n transportRef.current = null;\n }\n\n const t = createTransport();\n transportRef.current = t;\n\n try {\n setError(null);\n setConnectionState('connecting');\n networkManager.setConnectionState('connecting');\n setTransport(t);\n networkManager.setTransport(t);\n\n // Setup transport event listeners\n t.onPeerJoin(() => {\n // Player list updates handled by NetworkManager\n });\n\n t.onPeerLeave(() => {\n // Player list updates handled by NetworkManager\n });\n\n t.onHostChanged((newHostId) => {\n setHostId(newHostId);\n setIsHost(t.peerId === newHostId);\n optionsRef.current?.onHostMigration?.(newHostId);\n });\n\n // Listen for room updates\n if ('onRoomUpdated' in t && typeof (t as any).onRoomUpdated === 'function') {\n (t as any).onRoomUpdated((updatedRoom: Room) => {\n networkManager.setRoom(updatedRoom);\n });\n }\n\n await t.connect(targetRoomId, {\n displayName: optionsRef.current?.displayName,\n playerMetadata: optionsRef.current?.playerMetadata,\n password: joinOptions?.password ?? optionsRef.current?.password,\n iceServers: optionsRef.current?.iceServers,\n iceTransportPolicy: optionsRef.current?.privacy === 'relay' ? 'relay' : 'all',\n });\n\n // If this transport was replaced by a StrictMode re-mount, bail out\n if (transportRef.current !== t) return;\n\n setCurrentRoomId(targetRoomId);\n setSelfId(t.peerId);\n setHostId(t.hostId);\n setIsHost(t.isHost);\n setConnectionState('connected');\n networkManager.setConnectionState('connected');\n\n // Populate NetworkManager with initial room state and players\n if (t.room) {\n networkManager.setRoom(t.room);\n }\n if (t.initialPlayers) {\n const players = t.initialPlayers.map((p) => ({\n ...p,\n isSelf: p.peerId === t.peerId,\n }));\n networkManager.setPlayers(players);\n }\n\n reconnectAttemptsRef.current = 0;\n optionsRef.current?.onConnected?.();\n } catch (err) {\n // If this transport was replaced, ignore\n if (transportRef.current !== t) return;\n\n const carverError: CarverMultiplayerError = {\n code: 'CONNECTION_FAILED',\n message: err instanceof Error ? err.message : 'Connection failed',\n recoverable: reconnectAttemptsRef.current < maxReconnectAttempts,\n };\n setError(carverError);\n networkManager.emitError(carverError);\n setConnectionState('disconnected');\n networkManager.setConnectionState('disconnected');\n optionsRef.current?.onError?.(carverError);\n }\n }, [createTransport, networkManager, maxReconnectAttempts]);\n\n const leave = useCallback(() => {\n if (transportRef.current) {\n transportRef.current.disconnect();\n transportRef.current = null;\n }\n setTransport(null);\n setConnectionState('disconnected');\n setCurrentRoomId(null);\n setSelfId(null);\n setHostId(null);\n setIsHost(false);\n setError(null);\n networkManager.setConnectionState('disconnected');\n optionsRef.current?.onDisconnected?.('user_left');\n }, [networkManager]);\n\n const setReady = useCallback((ready: boolean) => {\n transport?.setReady?.(ready);\n // Optimistic self-update so local UI responds immediately\n const selfPlayer = networkManager.players.get(transport?.peerId ?? '');\n if (selfPlayer) {\n networkManager.updatePlayer({ ...selfPlayer, isReady: ready });\n }\n }, [transport, networkManager]);\n\n const setMetadata = useCallback((meta: Record<string, unknown>) => {\n transport?.setMetadata?.(meta);\n }, [transport]);\n\n const setRoomMetadata = useCallback((meta: Record<string, unknown>) => {\n transport?.setRoomMetadata?.(meta);\n }, [transport]);\n\n // Auto-join if roomId is provided\n useEffect(() => {\n if (roomId) {\n doJoin(roomId);\n }\n return () => {\n if (transportRef.current) {\n transportRef.current.disconnect();\n transportRef.current = null;\n }\n };\n }, [roomId, doJoin]);\n\n // Listen for room updates\n useEffect(() => {\n const unsub = networkManager.onRoomChange(() => {\n setRoom(networkManager.room);\n });\n setRoom(networkManager.room);\n return unsub;\n }, [networkManager]);\n\n return {\n roomId: currentRoomId,\n connectionState,\n isHost,\n hostId,\n selfId,\n room,\n error,\n join: doJoin,\n leave,\n setReady,\n setMetadata,\n setRoomMetadata,\n transport,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { Room, RoomConfig, UseLobbyOptions, CarverMultiplayerError } from \"../types\";\nimport type { RoomAnnouncement } from \"../transport/strategy/types\";\n\nexport interface UseLobbyReturn {\n rooms: Room[];\n isLoading: boolean;\n error: CarverMultiplayerError | null;\n refresh: () => void;\n createRoom: (config: RoomConfig) => Promise<string>;\n}\n\n/** Convert a RoomAnnouncement (from strategy) to a Room (public API type) */\nfunction announcementToRoom(ann: RoomAnnouncement): Room {\n return {\n id: ann.roomId,\n name: ann.name,\n hostId: ann.hostId,\n playerCount: ann.playerCount,\n maxPlayers: ann.maxPlayers,\n gameMode: ann.gameMode,\n isPrivate: ann.isPrivate,\n metadata: ann.metadata,\n createdAt: ann.createdAt,\n state: ann.state ?? 'lobby',\n };\n}\n\nexport function useLobby(options?: UseLobbyOptions): UseLobbyReturn {\n const { strategy } = useMultiplayerContext();\n const [rooms, setRooms] = useState<Room[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<CarverMultiplayerError | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // Filter rooms based on options\n const filterRooms = useCallback((roomList: Room[]): Room[] => {\n const filter = optionsRef.current?.filter;\n if (!filter) return roomList;\n return roomList.filter((room) => {\n if (filter.maxPlayers !== undefined && room.maxPlayers > filter.maxPlayers) return false;\n if (filter.gameMode !== undefined && room.gameMode !== filter.gameMode) return false;\n if (filter.hasPassword !== undefined && room.isPrivate !== filter.hasPassword) return false;\n return true;\n });\n }, []);\n\n // Subscribe to lobby via strategy\n useEffect(() => {\n setIsLoading(true);\n setError(null);\n\n const unsub = strategy.subscribeToLobby((announcements: RoomAnnouncement[]) => {\n const converted = announcements.map(announcementToRoom);\n setRooms(filterRooms(converted));\n setIsLoading(false);\n });\n\n // After a short timeout, if we haven't received any data, stop loading\n const timeout = setTimeout(() => setIsLoading(false), 3000);\n\n return () => {\n unsub();\n clearTimeout(timeout);\n };\n }, [strategy, filterRooms]);\n\n const refresh = useCallback(() => {\n // With MQTT/Firebase, the lobby is live-updating.\n // Refresh is a no-op since we're subscribed to real-time updates.\n // But we reset loading to give visual feedback.\n setIsLoading(true);\n setTimeout(() => setIsLoading(false), 1000);\n }, []);\n\n const createRoom = useCallback(async (config: RoomConfig): Promise<string> => {\n // In serverless mode, \"creating a room\" just means announcing it.\n // The room ID is generated locally. The actual room is established\n // when the first peer joins via useRoom.\n const roomId = `${config.name.toLowerCase().replace(/\\s+/g, '-')}-${Date.now().toString(36)}`;\n\n const announcement: RoomAnnouncement = {\n roomId,\n name: config.name,\n hostId: strategy.selfId,\n playerCount: 0,\n maxPlayers: config.maxPlayers ?? 8,\n gameMode: config.gameMode ?? (config.metadata?.gameMode as string | undefined),\n isPrivate: config.isPrivate ?? false,\n metadata: config.metadata ?? {},\n createdAt: Date.now(),\n lastSeen: Date.now(),\n };\n\n strategy.announceRoom(announcement);\n return roomId;\n }, [strategy]);\n\n return {\n rooms,\n isLoading,\n error,\n refresh,\n createRoom,\n };\n}\n","import { useState, useEffect, useCallback } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { Player } from \"../types\";\n\nexport interface UsePlayersReturn {\n players: Player[];\n self: Player | null;\n host: Player | null;\n count: number;\n allReady: boolean;\n getPlayer: (peerId: string) => Player | undefined;\n}\n\nexport function usePlayers(): UsePlayersReturn {\n const { networkManager } = useMultiplayerContext();\n const [players, setPlayers] = useState<Player[]>([]);\n const [, setVersion] = useState(0);\n\n useEffect(() => {\n const unsubscribe = networkManager.onPlayersChange(() => {\n setPlayers(Array.from(networkManager.players.values()));\n setVersion((v) => v + 1);\n });\n\n // Initialize with current players\n setPlayers(Array.from(networkManager.players.values()));\n\n return unsubscribe;\n }, [networkManager]);\n\n const self = players.find((p) => p.isSelf) ?? null;\n const host = players.find((p) => p.isHost) ?? null;\n const allReady = players.length > 0 && players.every((p) => p.isReady);\n\n const getPlayer = useCallback(\n (peerId: string) => players.find((p) => p.peerId === peerId),\n [players]\n );\n\n return {\n players,\n self,\n host,\n count: players.length,\n allReady,\n getPlayer,\n };\n}\n","import { useCallback } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { RoomState } from \"../types\";\n\nexport interface UseHostReturn {\n kick: (peerId: string, reason?: string) => void;\n transferHost: (peerId: string) => void;\n setRoomState: (state: RoomState) => void;\n setMaxPlayers: (n: number) => void;\n lockRoom: () => void;\n unlockRoom: () => void;\n}\n\nexport function useHost(): UseHostReturn {\n const { networkManager } = useMultiplayerContext();\n\n const getTransport = useCallback(() => {\n const transport = networkManager.transport;\n if (!transport || !networkManager.isHost) return null;\n return transport;\n }, [networkManager]);\n\n const kick = useCallback((peerId: string, reason?: string) => {\n getTransport()?.kick?.(peerId, reason);\n }, [getTransport]);\n\n const transferHost = useCallback((peerId: string) => {\n getTransport()?.transferHost?.(peerId);\n }, [getTransport]);\n\n const setRoomState = useCallback((state: RoomState) => {\n getTransport()?.setRoomState?.(state);\n }, [getTransport]);\n\n const setMaxPlayers = useCallback((n: number) => {\n getTransport()?.setMaxPlayers?.(n);\n }, [getTransport]);\n\n const lockRoom = useCallback(() => {\n getTransport()?.lockRoom?.();\n }, [getTransport]);\n\n const unlockRoom = useCallback(() => {\n getTransport()?.unlockRoom?.();\n }, [getTransport]);\n\n return {\n kick,\n transferHost,\n setRoomState,\n setMaxPlayers,\n lockRoom,\n unlockRoom,\n };\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport { useFrame } from \"@react-three/fiber\";\nimport { getActorRegistry } from \"@carverjs/core/systems\";\nimport type { ActorRef, NetworkedConfig } from \"@carverjs/core/types\";\nimport type {\n UseMultiplayerOptions,\n NetworkQuality,\n SyncMode,\n EntityState,\n EntityState2D,\n EntityState3D,\n PlayerInput,\n PredictionWorldDriver,\n} from \"../types\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport { EventSync } from \"../sync/EventSync\";\nimport { SnapshotSync } from \"../sync/SnapshotSync\";\nimport type { SnapshotSyncOptions } from \"../sync/SnapshotSync\";\nimport { PredictionSync } from \"../sync/PredictionSync\";\nimport { quatMultiply, quatInvert } from \"../sync/Rollback\";\nimport type { Quat } from \"../sync/Rollback\";\nimport { NetworkSimulator } from \"../core/NetworkSimulator\";\n\n// ── Return type ──\n\nexport interface UseMultiplayerReturn {\n isActive: boolean;\n networkQuality: NetworkQuality;\n tick: number;\n serverTick: number;\n drift: number;\n syncEngine: SyncMode;\n /** Set the local player's input (prediction mode). Stable callback; no-op in events/snapshot modes. */\n setInput: (input: PlayerInput) => void;\n}\n\n// ── Helpers: read / write actor state ──\n\nconst Z_THRESHOLD = 0.01;\n\nfunction detect2D(actors: Map<string, ActorRef>): boolean {\n for (const [, ref] of actors) {\n if (Math.abs(ref.object3D.position.z) > Z_THRESHOLD) return false;\n }\n return true;\n}\n\nfunction readEntityState2D(ref: ActorRef): EntityState2D {\n const pos = ref.object3D.position;\n const rot = ref.object3D.rotation;\n const rb = ref.rigidBody;\n\n let vx = 0;\n let vy = 0;\n let va = 0;\n\n if (rb) {\n try {\n const lv = rb.linvel();\n vx = lv.x;\n vy = lv.y;\n } catch { /* rigid body may not support linvel */ }\n try {\n const av = rb.angvel();\n // 2D angular velocity is a scalar in Rapier 2D, but in 3D mode it's a vec3\n va = typeof av === \"number\" ? av : (av?.z ?? 0);\n } catch { /* rigid body may not support angvel */ }\n }\n\n const nc = ref.userData.networked as NetworkedConfig | undefined;\n const custom = nc?.custom;\n\n return {\n id: ref.id,\n x: pos.x,\n y: pos.y,\n a: rot.z,\n vx,\n vy,\n va,\n ...(custom ? { c: custom } : {}),\n };\n}\n\nfunction readEntityState3D(ref: ActorRef): EntityState3D {\n const pos = ref.object3D.position;\n const quat = ref.object3D.quaternion;\n const rb = ref.rigidBody;\n\n let vx = 0;\n let vy = 0;\n let vz = 0;\n let wx = 0;\n let wy = 0;\n let wz = 0;\n\n if (rb) {\n try {\n const lv = rb.linvel();\n vx = lv.x;\n vy = lv.y;\n vz = lv.z ?? 0;\n } catch { /* no linvel */ }\n try {\n const av = rb.angvel();\n wx = av.x ?? 0;\n wy = av.y ?? 0;\n wz = av.z ?? 0;\n } catch { /* no angvel */ }\n }\n\n const nc = ref.userData.networked as NetworkedConfig | undefined;\n const custom = nc?.custom;\n\n return {\n id: ref.id,\n x: pos.x,\n y: pos.y,\n z: pos.z,\n qx: quat.x,\n qy: quat.y,\n qz: quat.z,\n qw: quat.w,\n vx,\n vy,\n vz,\n wx,\n wy,\n wz,\n ...(custom ? { c: custom } : {}),\n };\n}\n\nfunction buildEntityMap(\n actors: Map<string, ActorRef>,\n is2D: boolean,\n): Map<string, EntityState> {\n const entities = new Map<string, EntityState>();\n for (const [id, ref] of actors) {\n const nc = ref.userData.networked as NetworkedConfig | undefined;\n if (nc && nc.sync === false) continue;\n entities.set(id, is2D ? readEntityState2D(ref) : readEntityState3D(ref));\n }\n return entities;\n}\n\nfunction applyState2D(ref: ActorRef, state: EntityState2D): void {\n ref.object3D.position.set(state.x, state.y, 0);\n ref.object3D.rotation.z = state.a;\n\n if (ref.rigidBody) {\n try {\n if (typeof ref.rigidBody.setTranslation === \"function\") {\n ref.rigidBody.setTranslation({ x: state.x, y: state.y }, true);\n }\n if (typeof ref.rigidBody.setRotation === \"function\") {\n ref.rigidBody.setRotation(state.a, true);\n }\n } catch { /* kinematic API may not be available */ }\n }\n}\n\nfunction applyState3D(ref: ActorRef, state: EntityState3D): void {\n ref.object3D.position.set(state.x, state.y, state.z);\n ref.object3D.quaternion.set(state.qx, state.qy, state.qz, state.qw);\n\n if (ref.rigidBody) {\n try {\n if (typeof ref.rigidBody.setTranslation === \"function\") {\n ref.rigidBody.setTranslation({ x: state.x, y: state.y, z: state.z }, true);\n }\n if (typeof ref.rigidBody.setRotation === \"function\") {\n ref.rigidBody.setRotation(\n { x: state.qx, y: state.qy, z: state.qz, w: state.qw },\n true,\n );\n }\n } catch { /* kinematic API may not be available */ }\n }\n}\n\n/** Hard state apply for prediction/rollback: transform plus linear and angular velocity. */\nfunction applyStateHard2D(ref: ActorRef, state: EntityState2D): void {\n applyState2D(ref, state);\n\n if (ref.rigidBody) {\n try {\n if (typeof ref.rigidBody.setLinvel === \"function\") {\n ref.rigidBody.setLinvel({ x: state.vx, y: state.vy }, true);\n }\n if (typeof ref.rigidBody.setAngvel === \"function\") {\n ref.rigidBody.setAngvel(state.va, true);\n }\n } catch { /* velocity API may not be available */ }\n }\n}\n\n/** Hard state apply for prediction/rollback: transform plus linear and angular velocity. */\nfunction applyStateHard3D(ref: ActorRef, state: EntityState3D): void {\n applyState3D(ref, state);\n\n if (ref.rigidBody) {\n try {\n if (typeof ref.rigidBody.setLinvel === \"function\") {\n ref.rigidBody.setLinvel({ x: state.vx, y: state.vy, z: state.vz }, true);\n }\n if (typeof ref.rigidBody.setAngvel === \"function\") {\n ref.rigidBody.setAngvel({ x: state.wx, y: state.wy, z: state.wz }, true);\n }\n } catch { /* velocity API may not be available */ }\n }\n}\n\nfunction applyEntityState(\n ref: ActorRef,\n state: EntityState,\n is2D: boolean,\n): void {\n if (is2D) {\n applyState2D(ref, state as EntityState2D);\n } else {\n applyState3D(ref, state as EntityState3D);\n }\n}\n\nfunction applyStatesToActors(\n states: Map<string, EntityState>,\n registry: ReturnType<typeof getActorRegistry>,\n is2D: boolean,\n): void {\n for (const [id, state] of states) {\n // Skip tombstones\n if (state.c && (state.c as Record<string, unknown>).__removed) continue;\n\n const ref = registry.get(id);\n if (!ref) continue;\n\n applyEntityState(ref, state, is2D);\n }\n}\n\n// ── Applied error-offset bookkeeping (prediction mode, render-only) ──\n\ninterface AppliedErrorRecord {\n x: number;\n y: number;\n z: number;\n a: number;\n q: Quat;\n px: number;\n py: number;\n pz: number;\n}\n\nconst IDENTITY_QUAT: Quat = { x: 0, y: 0, z: 0, w: 1 };\n\nfunction isIdentityQuat(q: Quat): boolean {\n return q.x === 0 && q.y === 0 && q.z === 0 && q.w === 1;\n}\n\n// ── Hook ──\n\nexport function useMultiplayer(\n options: UseMultiplayerOptions = {},\n): UseMultiplayerReturn {\n const { networkManager } = useMultiplayerContext();\n const mode: SyncMode = options.mode ?? networkManager.syncMode;\n\n // Refs for sync engines (mutable across renders, don't trigger re-render)\n const eventSyncRef = useRef<EventSync | null>(null);\n const snapshotSyncRef = useRef<SnapshotSync | null>(null);\n const predictionSyncRef = useRef<PredictionSync | null>(null);\n const networkSimulatorRef = useRef<NetworkSimulator | null>(null);\n const is2DRef = useRef<boolean | null>(null);\n\n // Observable state exposed to consumers\n const [isActive, setIsActive] = useState(false);\n const [networkQuality, setNetworkQuality] = useState<NetworkQuality>(\"good\");\n const [tick, setTick] = useState(0);\n const [serverTick, setServerTick] = useState(0);\n const [drift, setDrift] = useState(0);\n\n const actorRegistry = useRef(getActorRegistry());\n\n // Track whether we were the host last frame to detect migration\n const wasHostRef = useRef<boolean | null>(null);\n\n // Error offsets applied to rendered transforms last frame (prediction mode).\n // px/py/pz fingerprint the post-application position so we only undo when\n // nothing else rewrote the transform in between.\n const appliedErrorsRef = useRef(new Map<string, AppliedErrorRecord>());\n\n // Build SnapshotSyncOptions from user options\n const buildSnapshotOpts = useCallback((): SnapshotSyncOptions => {\n return {\n broadcastRate: options.broadcastRate,\n keyframeInterval: options.keyframeInterval,\n bufferSize: options.interpolation?.bufferSize,\n interpolationMethod: options.interpolation?.method,\n extrapolateMs: options.interpolation?.extrapolateMs,\n is2D: is2DRef.current ?? true,\n };\n }, [\n options.broadcastRate,\n options.keyframeInterval,\n options.interpolation?.bufferSize,\n options.interpolation?.method,\n options.interpolation?.extrapolateMs,\n ]);\n\n // Undo last frame's render-only error offsets so physics/rollback sees raw transforms.\n const undoAppliedErrorOffsets = useCallback(() => {\n const registry = actorRegistry.current;\n for (const [id, e] of appliedErrorsRef.current) {\n const ref = registry.get(id);\n if (!ref) {\n appliedErrorsRef.current.delete(id);\n continue;\n }\n const pos = ref.object3D.position;\n const untouched =\n Math.abs(pos.x - e.px) < 1e-9 &&\n Math.abs(pos.y - e.py) < 1e-9 &&\n Math.abs(pos.z - e.pz) < 1e-9;\n if (untouched) {\n pos.x -= e.x;\n pos.y -= e.y;\n pos.z -= e.z;\n if (e.a !== 0) {\n ref.object3D.rotation.z -= e.a;\n }\n if (!isIdentityQuat(e.q)) {\n const inv = quatInvert(e.q);\n const cur = ref.object3D.quaternion;\n const r = quatMultiply(inv, { x: cur.x, y: cur.y, z: cur.z, w: cur.w });\n cur.set(r.x, r.y, r.z, r.w);\n }\n }\n // Fingerprint mismatch: something rewrote the transform — drop the record.\n }\n appliedErrorsRef.current.clear();\n }, []);\n\n // Stable input setter — delegates to PredictionSync; no-op in events/snapshot modes.\n const setInput = useCallback((input: PlayerInput) => {\n predictionSyncRef.current?.setInput(input);\n }, []);\n\n // ── Setup & teardown sync engines ──\n useEffect(() => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n // Setup network simulator if debug options are configured\n const debugOpts = options.debug;\n let simulator: NetworkSimulator | null = null;\n if (debugOpts?.simulatedLatencyMs || debugOpts?.simulatedPacketLoss) {\n simulator = new NetworkSimulator({\n latencyMs: debugOpts.simulatedLatencyMs,\n packetLoss: debugOpts.simulatedPacketLoss,\n });\n networkSimulatorRef.current = simulator;\n\n // Wrap transport.createChannel so all new channels go through the simulator\n const origCreateChannel = transport.createChannel.bind(transport);\n transport.createChannel = <T>(name: string, channelOpts?: import(\"../types\").ChannelOptions) => {\n const ch = origCreateChannel<T>(name, channelOpts);\n const wrappedSend = simulator!.wrapSend(ch.send.bind(ch));\n return { ...ch, send: wrappedSend };\n };\n }\n\n // Always create EventSync (Layer 1) - it's lightweight and useful for all modes\n eventSyncRef.current = new EventSync(transport);\n\n // Create Layer 2 / Layer 3 based on mode\n if (mode === \"snapshot\" || mode === \"prediction\") {\n snapshotSyncRef.current = new SnapshotSync(\n transport,\n networkManager.codec,\n networkManager.snapshotBuffer,\n buildSnapshotOpts(),\n );\n }\n\n if (mode === \"prediction\") {\n // World driver: full-world capture/apply for forward sim and rollback.\n // Closures read live refs so the driver tracks registry and 2D detection.\n const driver: PredictionWorldDriver = {\n captureState: () =>\n buildEntityMap(actorRegistry.current.getNetworked(), is2DRef.current ?? true),\n applyState: (entities) => {\n const is2D = is2DRef.current ?? true;\n for (const state of entities) {\n if (state.c && (state.c as Record<string, unknown>).__removed) continue;\n const ref = actorRegistry.current.get(state.id);\n if (!ref) continue;\n if (is2D) applyStateHard2D(ref, state as EntityState2D);\n else applyStateHard3D(ref, state as EntityState3D);\n }\n },\n ...(options.stepWorld ? { stepWorld: options.stepWorld } : {}),\n };\n\n predictionSyncRef.current = new PredictionSync(\n transport,\n networkManager.tickKeeper,\n snapshotSyncRef.current!,\n options.prediction,\n );\n if (options.onPhysicsStep) {\n predictionSyncRef.current.setPhysicsStep(options.onPhysicsStep);\n }\n predictionSyncRef.current.setWorldDriver(driver);\n }\n\n wasHostRef.current = networkManager.isHost;\n setIsActive(true);\n\n // Listen for host migration\n const unsubHostChanged = (() => {\n const onHostChanged = (newHostId: string) => {\n const amNewHost = newHostId === transport.peerId;\n const wasPreviouslyHost = wasHostRef.current;\n wasHostRef.current = amNewHost;\n\n if (amNewHost && !wasPreviouslyHost) {\n // Promoted to host\n snapshotSyncRef.current?.promoteToHost(buildSnapshotOpts());\n } else if (!amNewHost && wasPreviouslyHost) {\n // Demoted to client\n snapshotSyncRef.current?.demoteToClient(buildSnapshotOpts());\n }\n };\n\n transport.onHostChanged(onHostChanged);\n // transport.onHostChanged doesn't return an unsub - we rely on destroy\n return () => {}; // no-op cleanup for this listener\n })();\n\n // Cleanup on unmount or when deps change\n return () => {\n unsubHostChanged();\n eventSyncRef.current?.destroy();\n snapshotSyncRef.current?.destroy();\n predictionSyncRef.current?.destroy();\n networkSimulatorRef.current?.destroy();\n eventSyncRef.current = null;\n snapshotSyncRef.current = null;\n predictionSyncRef.current = null;\n networkSimulatorRef.current = null;\n appliedErrorsRef.current.clear();\n setIsActive(false);\n };\n }, [networkManager, mode, buildSnapshotOpts, options.prediction, options.onPhysicsStep, options.stepWorld, options.debug]);\n\n // ── Sync network quality from manager ──\n useEffect(() => {\n const unsub = networkManager.onConnectionStateChange(() => {\n setNetworkQuality(networkManager.networkQuality);\n });\n return unsub;\n }, [networkManager]);\n\n // ── R3F render loop at priority -55 ──\n useFrame((_state: unknown, delta: number) => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n const tickKeeper = networkManager.tickKeeper;\n const isHost = networkManager.isHost;\n\n // Detect 2D/3D on first frame with actors\n if (is2DRef.current === null) {\n const networked = actorRegistry.current.getNetworked();\n if (networked.size > 0) {\n is2DRef.current = detect2D(networked);\n }\n }\n\n const is2D = is2DRef.current ?? true;\n\n // Events-only mode: no per-frame state sync needed\n if (mode === \"events\") return;\n\n // Prediction: undo render-only error offsets, then apply any pending server\n // snapshot (full-world rollback). MUST run before tickKeeper.update because\n // beginFrame may snap the local tick.\n if (mode === \"prediction\" && predictionSyncRef.current) {\n undoAppliedErrorOffsets();\n predictionSyncRef.current.beginFrame();\n }\n\n // Advance tick accumulator\n const ticksThisFrame = tickKeeper.update(delta);\n\n // ── Fixed-step processing ──\n for (let i = 0; i < ticksThisFrame; i++) {\n const currentTick = tickKeeper.tick - (ticksThisFrame - 1 - i);\n\n if (mode === \"prediction\" && predictionSyncRef.current) {\n // Host AND client: full forward simulation of every networked entity\n predictionSyncRef.current.tick(currentTick);\n\n if (isHost) {\n const entities = buildEntityMap(actorRegistry.current.getNetworked(), is2D);\n snapshotSyncRef.current?.hostTick(\n currentTick,\n entities,\n tickKeeper.tickDelta,\n predictionSyncRef.current.getLocalInput(currentTick),\n );\n }\n } else if (mode === \"snapshot\" && isHost) {\n // Host: read actor state and broadcast\n const networked = actorRegistry.current.getNetworked();\n const entities = buildEntityMap(networked, is2D);\n snapshotSyncRef.current?.hostTick(currentTick, entities, tickKeeper.tickDelta);\n }\n }\n\n // ── Render-phase interpolation / smoothing (runs every frame) ──\n if (!isHost && mode === \"snapshot\" && snapshotSyncRef.current) {\n // Client interpolation: use performance.now() as render time\n const renderTime = performance.now();\n const interpolated = snapshotSyncRef.current.clientInterpolate(renderTime);\n applyStatesToActors(interpolated, actorRegistry.current, is2D);\n }\n\n // Prediction: apply decayed error offsets to rendered transforms only.\n // Rigid bodies are never touched here — physics owns transforms via the\n // tick loop; offsets are an Object3D-only render adjustment. The host's\n // offset map is simply empty.\n if (mode === \"prediction\" && predictionSyncRef.current) {\n const offsets = predictionSyncRef.current.getRenderErrorOffsets();\n for (const [id, off] of offsets) {\n const ref = actorRegistry.current.get(id);\n if (!ref) continue;\n\n const pos = ref.object3D.position;\n pos.x += off.x;\n pos.y += off.y;\n if (!is2D) pos.z += off.z;\n\n let appliedA = 0;\n let appliedQ: Quat = IDENTITY_QUAT;\n if (is2D) {\n ref.object3D.rotation.z += off.a;\n appliedA = off.a;\n } else {\n appliedQ = { x: off.qx, y: off.qy, z: off.qz, w: off.qw };\n if (!isIdentityQuat(appliedQ)) {\n const cur = ref.object3D.quaternion;\n const r = quatMultiply(appliedQ, { x: cur.x, y: cur.y, z: cur.z, w: cur.w });\n cur.set(r.x, r.y, r.z, r.w);\n }\n }\n\n appliedErrorsRef.current.set(id, {\n x: off.x,\n y: off.y,\n z: is2D ? 0 : off.z,\n a: appliedA,\n q: appliedQ,\n px: pos.x,\n py: pos.y,\n pz: pos.z,\n });\n }\n }\n\n // ── Update observable state (throttled — only when values actually change) ──\n if (ticksThisFrame > 0) {\n const newTick = tickKeeper.tick;\n const newServerTick = tickKeeper.serverTick;\n const newDrift = tickKeeper.drift;\n const newQuality = networkManager.networkQuality;\n setTick((prev) => prev !== newTick ? newTick : prev);\n setServerTick((prev) => prev !== newServerTick ? newServerTick : prev);\n setDrift((prev) => prev !== newDrift ? newDrift : prev);\n setNetworkQuality((prev) => prev !== newQuality ? newQuality : prev);\n }\n }, -55);\n\n return {\n isActive,\n networkQuality,\n tick,\n serverTick,\n drift,\n syncEngine: mode,\n setInput,\n };\n}\n","/* ------------------------------------------------------------------- */\n/* NetworkSimulator – latency / packet-loss / jitter injection layer */\n/* ------------------------------------------------------------------- */\n\nexport interface NetworkSimulatorOptions {\n /** Additional one-way latency in milliseconds (default 0) */\n latencyMs?: number;\n /** Packet drop rate, 0-1 (default 0) */\n packetLoss?: number;\n /** Random jitter +/- milliseconds (default 0) */\n jitterMs?: number;\n}\n\ninterface SimulatorStats {\n sentCount: number;\n droppedCount: number;\n avgLatencyMs: number;\n}\n\nexport class NetworkSimulator {\n private latencyMs: number;\n private packetLoss: number;\n private jitterMs: number;\n\n private sentCount = 0;\n private droppedCount = 0;\n private latencySum = 0; // running sum of applied latencies\n\n /** Active timeout handles so we can cancel them on destroy() */\n private pending: Set<ReturnType<typeof setTimeout>> = new Set();\n\n constructor(options?: NetworkSimulatorOptions) {\n const opts = options ?? {};\n this.latencyMs = opts.latencyMs ?? 0;\n this.packetLoss = opts.packetLoss ?? 0;\n this.jitterMs = opts.jitterMs ?? 0;\n }\n\n /* ---- public API ---- */\n\n /** Update simulation parameters at runtime. */\n setOptions(options: Partial<NetworkSimulatorOptions>): void {\n if (options.latencyMs !== undefined) this.latencyMs = options.latencyMs;\n if (options.packetLoss !== undefined) this.packetLoss = options.packetLoss;\n if (options.jitterMs !== undefined) this.jitterMs = options.jitterMs;\n }\n\n /**\n * Wrap an existing send function so that every call goes through the\n * simulated network conditions (latency, jitter, packet loss).\n */\n wrapSend<T>(\n originalSend: (data: T, target?: string | string[]) => void,\n ): (data: T, target?: string | string[]) => void {\n return (data: T, target?: string | string[]) => {\n /* 1. Packet-loss check */\n if (Math.random() < this.packetLoss) {\n this.droppedCount++;\n return;\n }\n\n this.sentCount++;\n\n /* 2. Compute effective delay */\n const jitter =\n this.jitterMs > 0\n ? Math.random() * 2 * this.jitterMs - this.jitterMs\n : 0;\n const delay = Math.max(0, this.latencyMs + jitter);\n\n /* Track latency for stats */\n this.latencySum += delay;\n\n /* 3. Dispatch */\n if (delay === 0) {\n originalSend(data, target);\n } else {\n const handle = setTimeout(() => {\n this.pending.delete(handle);\n originalSend(data, target);\n }, delay);\n this.pending.add(handle);\n }\n };\n }\n\n /** Current statistics snapshot. */\n get stats(): SimulatorStats {\n return {\n sentCount: this.sentCount,\n droppedCount: this.droppedCount,\n avgLatencyMs:\n this.sentCount > 0 ? this.latencySum / this.sentCount : 0,\n };\n }\n\n /** Cancel all pending delayed sends and clean up. */\n destroy(): void {\n for (const handle of this.pending) {\n clearTimeout(handle);\n }\n this.pending.clear();\n }\n}\n","import { useRef, useEffect, useCallback } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport { EventSync } from \"../sync/EventSync\";\n\nexport interface UseNetworkEventsReturn<T extends { [K in keyof T]: unknown } = Record<string, unknown>> {\n sendEvent: <K extends keyof T & string>(type: K, payload: T[K], target?: string) => void;\n broadcast: <K extends keyof T & string>(type: K, payload: T[K]) => void;\n onEvent: <K extends keyof T & string>(type: K, callback: (data: T[K], peerId: string) => void) => () => void;\n}\n\n/**\n * Layer 1: Typed event-based messaging between peers.\n * Uses a single reliable+ordered channel.\n *\n * @example\n * ```tsx\n * interface MyEvents {\n * 'chat': { message: string };\n * 'turn-end': { playerId: string; action: string };\n * }\n *\n * const { sendEvent, broadcast, onEvent } = useNetworkEvents<MyEvents>();\n *\n * broadcast('chat', { message: 'hello' });\n * onEvent('chat', (data, peerId) => console.log(data.message));\n * ```\n */\ninterface PendingListener {\n type: string;\n callback: (payload: unknown, peerId: string) => void;\n unsub: (() => void) | null;\n}\n\nexport function useNetworkEvents<\n T extends { [K in keyof T]: unknown } = Record<string, unknown>\n>(options?: { hostValidation?: boolean }): UseNetworkEventsReturn<T> {\n const { networkManager } = useMultiplayerContext();\n const eventSyncRef = useRef<EventSync | null>(null);\n const pendingRef = useRef<PendingListener[]>([]);\n const drainedUnsubsRef = useRef<(() => void)[]>([]);\n\n // Initialize EventSync when transport is available\n useEffect(() => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n const eventSync = new EventSync(transport, {\n hostValidation: options?.hostValidation,\n });\n eventSyncRef.current = eventSync;\n\n // Drain pending listener queue\n const unsubs: (() => void)[] = [];\n for (const entry of pendingRef.current) {\n const unsub = eventSync.onEvent(entry.type, entry.callback);\n entry.unsub = unsub;\n unsubs.push(unsub);\n }\n pendingRef.current = [];\n drainedUnsubsRef.current = unsubs;\n\n return () => {\n // Clean up any drained listeners that are still active\n for (const unsub of drainedUnsubsRef.current) {\n unsub();\n }\n drainedUnsubsRef.current = [];\n eventSync.destroy();\n eventSyncRef.current = null;\n };\n }, [networkManager.transport, options?.hostValidation]);\n\n const sendEvent = useCallback(<K extends keyof T & string>(\n type: K,\n payload: T[K],\n target?: string,\n ) => {\n eventSyncRef.current?.sendEvent(type, payload, target);\n }, []);\n\n const broadcast = useCallback(<K extends keyof T & string>(\n type: K,\n payload: T[K],\n ) => {\n eventSyncRef.current?.broadcast(type, payload);\n }, []);\n\n const onEvent = useCallback(<K extends keyof T & string>(\n type: K,\n callback: (data: T[K], peerId: string) => void,\n ): (() => void) => {\n const castCallback = callback as (payload: unknown, peerId: string) => void;\n\n if (eventSyncRef.current) {\n return eventSyncRef.current.onEvent(type, castCallback);\n }\n\n // Buffer the listener until EventSync initializes\n const entry: PendingListener = { type, callback: castCallback, unsub: null };\n pendingRef.current.push(entry);\n\n return () => {\n if (entry.unsub) {\n // Already drained and registered with EventSync -- unsubscribe normally\n entry.unsub();\n drainedUnsubsRef.current = drainedUnsubsRef.current.filter((u) => u !== entry.unsub);\n } else {\n // Still pending -- remove from queue\n pendingRef.current = pendingRef.current.filter((e) => e !== entry);\n }\n };\n }, []);\n\n return { sendEvent, broadcast, onEvent };\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useMultiplayerContext } from \"../core/MultiplayerContext\";\nimport type { CarverChannel, EntityState } from \"../types\";\n\n// ── Message protocol ──\n\ninterface NetworkStateMessage {\n action: \"spawn\" | \"despawn\" | \"request-spawn\";\n id: string;\n state?: EntityState | Record<string, unknown>;\n}\n\n// ── Return type ──\n\nexport interface UseNetworkStateReturn {\n /** Host only. Create a networked entity and broadcast its existence to all peers. */\n spawn: (id: string, initialState: EntityState) => void;\n /** Host only. Remove a networked entity and broadcast removal to all peers. */\n despawn: (id: string) => void;\n /** Client sends a spawn request to the host, who validates and spawns if the id is not taken. */\n requestSpawn: (id: string, config: Record<string, unknown>) => void;\n /** Read the current state of a networked entity by id. */\n getState: (id: string) => EntityState | undefined;\n /** Write a partial update to a networked entity. Host-authoritative: only the host may call this. */\n setState: (id: string, partialState: Partial<EntityState>) => void;\n /** Reactive map of all current networked entity states. */\n entities: Map<string, EntityState>;\n}\n\nconst CHANNEL_NAME = \"carver:network-state\";\n\n/**\n * Phase 4.4 – Advanced escape-hatch hook for direct networked entity management.\n *\n * Provides host-authoritative spawn / despawn, client requestSpawn,\n * and direct state read / write over a reliable+ordered data channel.\n */\nexport function useNetworkState(): UseNetworkStateReturn {\n const { networkManager } = useMultiplayerContext();\n\n // Entity state map – drives reactive re-renders.\n const [entities, setEntities] = useState<Map<string, EntityState>>(\n () => new Map(),\n );\n\n // Keep a mutable ref mirror so callbacks always see the latest map\n // without needing to re-create the channel listener on every state change.\n const entitiesRef = useRef<Map<string, EntityState>>(entities);\n entitiesRef.current = entities;\n\n // Channel ref – created once and cleaned up on unmount.\n const channelRef = useRef<CarverChannel<NetworkStateMessage> | null>(null);\n\n // ── Helpers (internal, not exposed) ──\n\n /** Immutably replace the entities map so React picks up the change. */\n const replaceEntities = useCallback(\n (updater: (prev: Map<string, EntityState>) => Map<string, EntityState>) => {\n setEntities((prev) => {\n const next = updater(prev);\n entitiesRef.current = next;\n return next;\n });\n },\n [],\n );\n\n /** Apply a spawn locally and update React state. */\n const applySpawn = useCallback(\n (id: string, state: EntityState) => {\n replaceEntities((prev) => {\n const next = new Map(prev);\n next.set(id, state);\n return next;\n });\n },\n [replaceEntities],\n );\n\n /** Apply a despawn locally and update React state. */\n const applyDespawn = useCallback(\n (id: string) => {\n replaceEntities((prev) => {\n if (!prev.has(id)) return prev; // no-op\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n },\n [replaceEntities],\n );\n\n // ── Channel setup ──\n\n useEffect(() => {\n const transport = networkManager.transport;\n if (!transport) return;\n\n const channel = transport.createChannel<NetworkStateMessage>(CHANNEL_NAME, {\n reliable: true,\n ordered: true,\n });\n channelRef.current = channel;\n\n channel.onReceive((msg: NetworkStateMessage, _peerId: string) => {\n switch (msg.action) {\n // --- Spawn broadcast (sent by host to everyone) ---\n case \"spawn\": {\n if (msg.state) {\n applySpawn(msg.id, msg.state as EntityState);\n }\n break;\n }\n\n // --- Despawn broadcast (sent by host to everyone) ---\n case \"despawn\": {\n applyDespawn(msg.id);\n break;\n }\n\n // --- Request-spawn (client -> host only) ---\n case \"request-spawn\": {\n // Only the host processes spawn requests.\n if (!transport.isHost) break;\n\n // Validate: reject if id already exists.\n if (entitiesRef.current.has(msg.id)) break;\n\n // Build an EntityState from the config the client sent.\n // The config should at minimum contain an id. We merge defaults\n // for a 2D entity so the state is always well-formed.\n const config = (msg.state ?? {}) as Record<string, unknown>;\n const newState: EntityState = {\n id: msg.id,\n x: 0,\n y: 0,\n a: 0,\n vx: 0,\n vy: 0,\n va: 0,\n ...config,\n // Ensure id is authoritative.\n ...(config.id !== undefined ? {} : {}),\n } as EntityState;\n // Force the id to match the message id (authoritative).\n (newState as { id: string }).id = msg.id;\n\n // Apply locally on the host.\n applySpawn(msg.id, newState);\n\n // Broadcast spawn to all peers (including the requester).\n channel.send({ action: \"spawn\", id: msg.id, state: newState });\n break;\n }\n }\n });\n\n return () => {\n channel.close();\n channelRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [networkManager.transport, applySpawn, applyDespawn]);\n\n // ── Public API ──\n\n /**\n * Host only. Creates a networked entity and broadcasts a spawn event to all peers.\n */\n const spawn = useCallback(\n (id: string, initialState: EntityState) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\"[useNetworkState] spawn called before transport is ready.\");\n return;\n }\n if (!transport.isHost) {\n console.warn(\n \"[useNetworkState] spawn is host-only. Use requestSpawn() from a client.\",\n );\n return;\n }\n if (entitiesRef.current.has(id)) {\n console.warn(\n `[useNetworkState] entity \"${id}\" already exists. Ignoring spawn.`,\n );\n return;\n }\n\n // Ensure the id field matches.\n const state: EntityState = { ...initialState, id } as EntityState;\n\n // Apply locally.\n applySpawn(id, state);\n\n // Broadcast to all peers.\n channelRef.current?.send({ action: \"spawn\", id, state });\n },\n [networkManager, applySpawn],\n );\n\n /**\n * Host only. Removes a networked entity and broadcasts a despawn event to all peers.\n */\n const despawn = useCallback(\n (id: string) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\"[useNetworkState] despawn called before transport is ready.\");\n return;\n }\n if (!transport.isHost) {\n console.warn(\"[useNetworkState] despawn is host-only.\");\n return;\n }\n if (!entitiesRef.current.has(id)) {\n console.warn(\n `[useNetworkState] entity \"${id}\" does not exist. Ignoring despawn.`,\n );\n return;\n }\n\n // Apply locally.\n applyDespawn(id);\n\n // Broadcast to all peers.\n channelRef.current?.send({ action: \"despawn\", id });\n },\n [networkManager, applyDespawn],\n );\n\n /**\n * Client sends a spawn request to the host. The host validates the request\n * (no duplicate id) and, if valid, spawns the entity and broadcasts to everyone.\n */\n const requestSpawn = useCallback(\n (id: string, config: Record<string, unknown>) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\n \"[useNetworkState] requestSpawn called before transport is ready.\",\n );\n return;\n }\n\n // If we ARE the host, just handle it inline for convenience.\n if (transport.isHost) {\n if (entitiesRef.current.has(id)) {\n console.warn(\n `[useNetworkState] entity \"${id}\" already exists. Ignoring requestSpawn.`,\n );\n return;\n }\n const newState: EntityState = {\n id,\n x: 0,\n y: 0,\n a: 0,\n vx: 0,\n vy: 0,\n va: 0,\n ...config,\n } as EntityState;\n (newState as { id: string }).id = id;\n applySpawn(id, newState);\n channelRef.current?.send({ action: \"spawn\", id, state: newState });\n return;\n }\n\n // Send request to host.\n channelRef.current?.send(\n { action: \"request-spawn\", id, state: config },\n transport.hostId,\n );\n },\n [networkManager, applySpawn],\n );\n\n /**\n * Read the current state of a networked entity by id.\n */\n const getState = useCallback(\n (id: string): EntityState | undefined => {\n return entitiesRef.current.get(id);\n },\n [],\n );\n\n /**\n * Write a partial update to a networked entity's state.\n * Host-authoritative: only the host may call this.\n */\n const setState = useCallback(\n (id: string, partialState: Partial<EntityState>) => {\n const transport = networkManager.transport;\n if (!transport) {\n console.warn(\"[useNetworkState] setState called before transport is ready.\");\n return;\n }\n if (!transport.isHost) {\n console.warn(\"[useNetworkState] setState is host-only.\");\n return;\n }\n\n const existing = entitiesRef.current.get(id);\n if (!existing) {\n console.warn(\n `[useNetworkState] entity \"${id}\" does not exist. Cannot setState.`,\n );\n return;\n }\n\n const updated: EntityState = {\n ...existing,\n ...partialState,\n id, // id is immutable\n } as EntityState;\n\n replaceEntities((prev) => {\n const next = new Map(prev);\n next.set(id, updated);\n return next;\n });\n\n // Broadcast the full updated state so clients stay in sync.\n channelRef.current?.send({ action: \"spawn\", id, state: updated });\n },\n [networkManager, replaceEntities],\n );\n\n return {\n spawn,\n despawn,\n requestSpawn,\n getState,\n setState,\n entities,\n };\n}\n","/* ------------------------------------------------------------------ */\n/* DebugOverlay – DOM-based stats panel for multiplayer diagnostics */\n/* ------------------------------------------------------------------ */\n\nexport interface DebugOverlayOptions {\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n /** Keyboard key used to toggle visibility (default: \"F3\") */\n keyboardToggle?: string;\n}\n\nexport interface DebugStats {\n tick: number;\n serverTick: number;\n drift: number;\n /** Per-peer latency map or a single average value */\n latencyMs: Map<string, number> | number;\n /** Packet-loss rate in the range 0-1 */\n packetLossRate: number;\n /** Inbound bandwidth in bytes / second */\n bandwidthIn: number;\n /** Outbound bandwidth in bytes / second */\n bandwidthOut: number;\n networkQuality: \"good\" | \"degraded\" | \"poor\";\n peerCount: number;\n isHost: boolean;\n syncMode: string;\n}\n\nconst QUALITY_COLORS: Record<string, string> = {\n good: \"#00ff00\",\n degraded: \"#ffff00\",\n poor: \"#ff4444\",\n};\n\nexport class DebugOverlay {\n private el: HTMLDivElement;\n private visible = true;\n private lastHTML = \"\";\n private readonly keyboardToggle: string;\n private readonly handleKey: (e: KeyboardEvent) => void;\n\n constructor(options?: DebugOverlayOptions) {\n const opts = options ?? {};\n this.keyboardToggle = opts.keyboardToggle ?? \"F3\";\n\n /* ---- create container ---- */\n this.el = document.createElement(\"div\");\n\n const pos = opts.position ?? \"top-right\";\n const posStyles = this.positionStyles(pos);\n\n Object.assign(this.el.style, {\n position: \"fixed\",\n ...posStyles,\n background: \"rgba(0,0,0,0.75)\",\n color: \"#00ff00\",\n fontFamily: \"'Courier New', monospace\",\n fontSize: \"11px\",\n padding: \"8px\",\n borderRadius: \"4px\",\n zIndex: \"99999\",\n pointerEvents: \"none\",\n whiteSpace: \"pre\",\n lineHeight: \"1.4\",\n minWidth: \"200px\",\n boxSizing: \"border-box\",\n } as CSSStyleDeclaration);\n\n document.body.appendChild(this.el);\n\n /* ---- keyboard listener ---- */\n this.handleKey = (e: KeyboardEvent) => {\n if (e.key === this.keyboardToggle) {\n e.preventDefault();\n this.toggle();\n }\n };\n window.addEventListener(\"keydown\", this.handleKey);\n }\n\n /* ---- public API ---- */\n\n update(stats: DebugStats): void {\n if (!this.visible) return;\n\n const latencyDisplay = this.formatLatency(stats.latencyMs);\n const qualityColor = QUALITY_COLORS[stats.networkQuality] ?? \"#00ff00\";\n const bwIn = (stats.bandwidthIn / 1024).toFixed(1);\n const bwOut = (stats.bandwidthOut / 1024).toFixed(1);\n const loss = (stats.packetLossRate * 100).toFixed(1);\n\n const html =\n `<b style=\"color:#00ccff\">== NET DEBUG ==</b>\\n` +\n `tick ${stats.tick}\\n` +\n `srv tick ${stats.serverTick}\\n` +\n `drift ${stats.drift}\\n` +\n `latency ${latencyDisplay} ms\\n` +\n `loss ${loss}%\\n` +\n `bw in ${bwIn} KB/s\\n` +\n `bw out ${bwOut} KB/s\\n` +\n `quality <span style=\"color:${qualityColor}\">${stats.networkQuality}</span>\\n` +\n `peers ${stats.peerCount}\\n` +\n `host ${stats.isHost ? \"YES\" : \"NO\"}\\n` +\n `sync ${stats.syncMode}`;\n\n /* Only touch the DOM when something changed */\n if (html !== this.lastHTML) {\n this.el.innerHTML = html;\n this.lastHTML = html;\n }\n }\n\n show(): void {\n this.visible = true;\n this.el.style.display = \"block\";\n }\n\n hide(): void {\n this.visible = false;\n this.el.style.display = \"none\";\n }\n\n toggle(): void {\n if (this.visible) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n destroy(): void {\n window.removeEventListener(\"keydown\", this.handleKey);\n this.el.remove();\n }\n\n /* ---- helpers ---- */\n\n private positionStyles(\n pos: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\",\n ): Record<string, string> {\n switch (pos) {\n case \"top-left\":\n return { top: \"8px\", left: \"8px\" };\n case \"top-right\":\n return { top: \"8px\", right: \"8px\" };\n case \"bottom-left\":\n return { bottom: \"8px\", left: \"8px\" };\n case \"bottom-right\":\n return { bottom: \"8px\", right: \"8px\" };\n }\n }\n\n private formatLatency(latency: Map<string, number> | number): string {\n if (typeof latency === \"number\") {\n return latency.toFixed(1);\n }\n if (latency.size === 0) return \"—\";\n let sum = 0;\n latency.forEach((v) => (sum += v));\n return (sum / latency.size).toFixed(1);\n }\n}\n","import type { EntityState } from \"../types\";\n\n// ── Options ──\n\nexport interface InterestManagerOptions {\n /** Spatial hash cell size in world units. Default: 50 */\n cellSize?: number;\n /** Default relevance radius around a client's position. Default: 200 */\n defaultRadius?: number;\n /** Entity ids/names that are always sent to every client. */\n alwaysRelevant?: string[];\n}\n\n// ── InterestManager ──\n\n/**\n * Spatial-hash-grid area-of-interest filter.\n *\n * Runs on the host side. Each tick the host feeds the full entity map via\n * `updateEntities`, then queries per-client relevance with\n * `getRelevantEntities` (or creates a single filter callback via\n * `createFilter` for `HostAuthority.setInterestFilter`).\n */\nexport class InterestManager {\n /** cell-key -> set of entity ids occupying that cell */\n private _cells: Map<string, Set<string>>;\n /** entity id -> last-known 3D position */\n private _entityPositions: Map<string, { x: number; y: number; z: number }>;\n private _cellSize: number;\n private _defaultRadius: number;\n private _alwaysRelevant: Set<string>;\n\n constructor(options?: InterestManagerOptions) {\n this._cellSize = options?.cellSize ?? 50;\n this._defaultRadius = options?.defaultRadius ?? 200;\n this._alwaysRelevant = new Set(options?.alwaysRelevant ?? []);\n this._cells = new Map();\n this._entityPositions = new Map();\n }\n\n // ── Public API ──\n\n /**\n * Rebuild the spatial hash from the authoritative entity map.\n * Called once per host tick before any relevance queries.\n */\n updateEntities(entities: Map<string, EntityState>): void {\n // Clear previous grid state\n this._cells.clear();\n this._entityPositions.clear();\n\n for (const [id, entity] of entities) {\n const z = \"z\" in entity ? (entity as { z: number }).z : 0;\n const pos = { x: entity.x, y: entity.y, z };\n this._entityPositions.set(id, pos);\n\n const key = this._cellKey(pos.x, pos.y, pos.z);\n let bucket = this._cells.get(key);\n if (!bucket) {\n bucket = new Set();\n this._cells.set(key, bucket);\n }\n bucket.add(id);\n }\n }\n\n /**\n * Return the set of entity ids relevant to a single client.\n *\n * Relevance is the *union* of:\n * 1. Entities whose cell overlaps the client's bounding sphere\n * 2. Entities in the `alwaysRelevant` set\n * 3. Entities owned by this client\n */\n getRelevantEntities(\n clientPosition: { x: number; y: number; z?: number },\n clientId: string,\n owners: Map<string, string>,\n overrideRadius?: number,\n ): Set<string> {\n const radius = overrideRadius ?? this._defaultRadius;\n const cx = clientPosition.x;\n const cy = clientPosition.y;\n const cz = clientPosition.z ?? 0;\n\n const result = new Set<string>();\n\n // 1. Spatial query — iterate every cell that the bounding box of the\n // sphere overlaps.\n const minCellX = Math.floor((cx - radius) / this._cellSize);\n const maxCellX = Math.floor((cx + radius) / this._cellSize);\n const minCellY = Math.floor((cy - radius) / this._cellSize);\n const maxCellY = Math.floor((cy + radius) / this._cellSize);\n const minCellZ = Math.floor((cz - radius) / this._cellSize);\n const maxCellZ = Math.floor((cz + radius) / this._cellSize);\n\n for (let ix = minCellX; ix <= maxCellX; ix++) {\n for (let iy = minCellY; iy <= maxCellY; iy++) {\n for (let iz = minCellZ; iz <= maxCellZ; iz++) {\n const key = `${ix},${iy},${iz}`;\n const bucket = this._cells.get(key);\n if (bucket) {\n for (const entityId of bucket) {\n result.add(entityId);\n }\n }\n }\n }\n }\n\n // 2. Always-relevant entities (must still exist in the current frame)\n for (const id of this._alwaysRelevant) {\n if (this._entityPositions.has(id)) {\n result.add(id);\n }\n }\n\n // 3. Self-owned entities\n for (const [entityId, ownerId] of owners) {\n if (ownerId === clientId && this._entityPositions.has(entityId)) {\n result.add(entityId);\n }\n }\n\n return result;\n }\n\n /**\n * Build a filter callback compatible with\n * `HostAuthority.setInterestFilter`.\n *\n * The returned function closes over a single relevance pass for every\n * known client so that per-entity filtering during broadcast is a cheap\n * `Set.has` lookup.\n *\n * @param clientPositions peerId -> position of that client's camera/player\n * @param owners entityId -> ownerPeerId\n */\n createFilter(\n clientPositions: Map<string, { x: number; y: number; z?: number }>,\n owners: Map<string, string>,\n ): (entityId: string, peerId: string) => boolean {\n // Pre-compute the relevant set for every known client once.\n const relevanceSets = new Map<string, Set<string>>();\n for (const [peerId, pos] of clientPositions) {\n relevanceSets.set(\n peerId,\n this.getRelevantEntities(pos, peerId, owners),\n );\n }\n\n return (entityId: string, peerId: string): boolean => {\n const set = relevanceSets.get(peerId);\n // If we have no position info for this client, include everything\n // (fail-open so new joiners still receive data).\n if (!set) return true;\n return set.has(entityId);\n };\n }\n\n /** Remove all data from the grid. */\n clear(): void {\n this._cells.clear();\n this._entityPositions.clear();\n }\n\n // ── Private helpers ──\n\n private _cellKey(x: number, y: number, z: number): string {\n const cx = Math.floor(x / this._cellSize);\n const cy = Math.floor(y / this._cellSize);\n const cz = Math.floor(z / this._cellSize);\n return `${cx},${cy},${cz}`;\n }\n}\n"],"mappings":"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","names":["createElement","useContext","useContext","createElement","useEffect","useRef","useRef","useEffect","useState","useEffect","useCallback","useRef","useState","useRef","useCallback","useEffect","useState","useEffect","useCallback","useState","useEffect","useCallback","useCallback","useCallback","useEffect","useRef","useState","useCallback","useRef","useState","useCallback","useEffect","useRef","useEffect","useCallback","useRef","useEffect","useCallback","useState","useEffect","useCallback","useRef","useState","useRef","useCallback","useEffect"]}