@carverjs/multiplayer 0.0.1 → 0.0.2

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 (42) hide show
  1. package/dist/InputBuffer-J6XT_Tt0.d.mts +61 -0
  2. package/dist/InputBuffer-V7XfHbc6.d.ts +61 -0
  3. package/dist/{NetworkManager-nvVAOr1O.d.ts → NetworkManager-D-DxFgdM.d.mts} +66 -14
  4. package/dist/{NetworkManager-DrKM2tEx.d.mts → NetworkManager-DH9uGVMg.d.ts} +66 -14
  5. package/dist/{chunk-UD6FDZMX.mjs → chunk-CBTAOVXP.mjs} +34 -3
  6. package/dist/chunk-CBTAOVXP.mjs.map +1 -0
  7. package/dist/{chunk-EO3YNPRQ.mjs → chunk-Q25TJEY4.mjs} +494 -204
  8. package/dist/chunk-Q25TJEY4.mjs.map +1 -0
  9. package/dist/{chunk-3KT73N2S.mjs → chunk-UKEFWQ76.mjs} +0 -0
  10. package/dist/chunk-UKEFWQ76.mjs.map +1 -0
  11. package/dist/{firebase-CPu87KA0.d.ts → firebase-B5MgLlHk.d.ts} +6 -1
  12. package/dist/{firebase-PE6MxGdJ.d.mts → firebase-GrbVrNgs.d.mts} +6 -1
  13. package/dist/index.d.mts +27 -6
  14. package/dist/index.d.ts +27 -6
  15. package/dist/index.js +744 -245
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +172 -37
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/strategy.d.mts +2 -2
  20. package/dist/strategy.d.ts +2 -2
  21. package/dist/strategy.js +33 -2
  22. package/dist/strategy.js.map +1 -1
  23. package/dist/strategy.mjs +1 -1
  24. package/dist/sync.d.mts +134 -50
  25. package/dist/sync.d.ts +134 -50
  26. package/dist/sync.js +499 -205
  27. package/dist/sync.js.map +1 -1
  28. package/dist/sync.mjs +15 -3
  29. package/dist/transport.d.mts +0 -0
  30. package/dist/transport.d.ts +0 -0
  31. package/dist/transport.js +0 -0
  32. package/dist/transport.js.map +1 -1
  33. package/dist/transport.mjs +2 -2
  34. package/dist/{types-5LHBOW08.d.mts → types-hNfCIBzj.d.mts} +7 -0
  35. package/dist/{types-5LHBOW08.d.ts → types-hNfCIBzj.d.ts} +7 -0
  36. package/dist/types.d.mts +2 -2
  37. package/dist/types.d.ts +2 -2
  38. package/dist/types.js.map +1 -1
  39. package/package.json +26 -5
  40. package/dist/chunk-3KT73N2S.mjs.map +0 -1
  41. package/dist/chunk-EO3YNPRQ.mjs.map +0 -1
  42. package/dist/chunk-UD6FDZMX.mjs.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/MultiplayerProvider.ts","../src/transport/strategy/utils.ts","../src/transport/strategy/mqtt.ts","../src/transport/strategy/firebase.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/transport/webrtc/ice.ts","../src/transport/webrtc/peer.ts","../src/transport/webrtc/WebRTCTransport.ts","../src/hooks/useLobby.ts","../src/hooks/usePlayers.ts","../src/hooks/useHost.ts","../src/hooks/useMultiplayer.ts","../src/sync/EventSync.ts","../src/core/HostAuthority.ts","../src/core/ClientReceiver.ts","../src/sync/SnapshotSync.ts","../src/sync/PredictionSync.ts","../src/core/NetworkSimulator.ts","../src/hooks/useNetworkEvents.ts","../src/hooks/useNetworkState.ts","../src/core/DebugOverlay.ts","../src/core/InterestManager.ts"],"sourcesContent":["// Components\nexport { MultiplayerProvider } from \"./components/MultiplayerProvider\";\nexport type { MultiplayerProviderProps } from \"./components/MultiplayerProvider\";\nexport { MultiplayerBridge } from \"./components/MultiplayerBridge\";\n\n// Hooks\nexport { useRoom } from \"./hooks/useRoom\";\nexport { useLobby } from \"./hooks/useLobby\";\nexport { usePlayers } from \"./hooks/usePlayers\";\nexport { useHost } from \"./hooks/useHost\";\nexport { useMultiplayer } from \"./hooks/useMultiplayer\";\nexport { useNetworkEvents } from \"./hooks/useNetworkEvents\";\nexport { useNetworkState } from \"./hooks/useNetworkState\";\n\n// Strategy (for advanced users who want direct access)\nexport { MqttStrategy, FirebaseStrategy } from \"./transport/strategy\";\n\n// Core utilities (advanced)\nexport { DebugOverlay } from \"./core/DebugOverlay\";\nexport type { DebugStats, DebugOverlayOptions } from \"./core/DebugOverlay\";\nexport { NetworkSimulator } from \"./core/NetworkSimulator\";\nexport type { NetworkSimulatorOptions } from \"./core/NetworkSimulator\";\nexport { InterestManager } from \"./core/InterestManager\";\nexport type { InterestManagerOptions } from \"./core/InterestManager\";\n\n// Re-export types\nexport type * from \"./types\";\n","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","/** Generate a random peer ID (20 chars, URL-safe) */\nexport function generatePeerId(): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n const bytes = new Uint8Array(20);\n crypto.getRandomValues(bytes);\n let id = '';\n for (let i = 0; i < 20; i++) {\n id += chars[bytes[i] % chars.length];\n }\n return id;\n}\n\n/** Build MQTT topic paths for a given appId + roomId */\nexport function mqttTopics(appId: string, roomId: string, peerId?: string) {\n const base = `carver/${appId}`;\n return {\n /** Lobby wildcard: subscribe to discover all room announcements */\n lobbyWildcard: `${base}/lobby/+`,\n /** Single room lobby entry */\n roomLobbyEntry: `${base}/lobby/${roomId}`,\n /** Wildcard for all peer presence in a room */\n roomPresenceWildcard: `${base}/room/${roomId}/presence/+`,\n /** This peer's presence topic */\n peerPresence: peerId ? `${base}/room/${roomId}/presence/${peerId}` : '',\n /** This peer's signal inbox */\n peerSignalInbox: peerId ? `${base}/room/${roomId}/signal/${peerId}` : '',\n };\n}\n\n/** Build Firebase RTDB paths for a given appId + roomId */\nexport function firebasePaths(appId: string, roomId: string, peerId?: string) {\n const base = `${appId}/__carver__`;\n return {\n lobby: `${base}/lobby`,\n roomLobbyEntry: `${base}/lobby/${roomId}`,\n peers: `${base}/rooms/${roomId}/peers`,\n peerPresence: peerId ? `${base}/rooms/${roomId}/peers/${peerId}` : '',\n peerSignalInbox: peerId ? `${base}/rooms/${roomId}/signals/${peerId}` : '',\n };\n}\n\n/** Default MQTT brokers (WebSocket endpoints, free/public) */\nexport const DEFAULT_MQTT_BROKERS = [\n 'wss://broker.emqx.io:8084/mqtt',\n 'wss://test.mosquitto.org:8081/mqtt',\n];\n\n/** Room announcement expiry time (30s without heartbeat = stale) */\nexport const ROOM_ANNOUNCE_EXPIRY_MS = 30_000;\n\n/** Room announcement heartbeat interval */\nexport const ROOM_ANNOUNCE_INTERVAL_MS = 10_000;\n\n/** Peer presence heartbeat interval */\nexport const PRESENCE_HEARTBEAT_MS = 5_000;\n\n/** Peer expiry: 3 missed heartbeats */\nexport const PEER_EXPIRY_MS = PRESENCE_HEARTBEAT_MS * 3;\n\n/** Rapid warmup announces for faster initial peer discovery */\nexport const PRESENCE_WARMUP_DELAYS_MS = [200, 500, 1500];\n\n/** Remove an item from an array by reference. Returns true if found. */\nexport function removeFromArray<T>(arr: T[], item: T): boolean {\n const idx = arr.indexOf(item);\n if (idx >= 0) {\n arr.splice(idx, 1);\n return true;\n }\n return false;\n}\n","import type {\n SignalingStrategy,\n PeerMetadata,\n RoomAnnouncement,\n MqttStrategyConfig,\n} from \"./types\";\nimport {\n generatePeerId,\n mqttTopics,\n removeFromArray,\n DEFAULT_MQTT_BROKERS,\n ROOM_ANNOUNCE_EXPIRY_MS,\n ROOM_ANNOUNCE_INTERVAL_MS,\n PRESENCE_HEARTBEAT_MS,\n PEER_EXPIRY_MS,\n PRESENCE_WARMUP_DELAYS_MS,\n} from \"./utils\";\n\n// mqtt.MqttClient type (avoid hard import at module level)\ntype MqttClient = {\n on(event: string, cb: (...args: any[]) => void): void;\n subscribe(topic: string | string[], opts: Record<string, unknown>, cb?: (err: Error | null) => void): void;\n unsubscribe(topic: string | string[]): void;\n publish(topic: string, payload: string | Buffer, opts?: Record<string, unknown>): void;\n end(force?: boolean): void;\n};\n\n/**\n * MQTT-based signaling strategy.\n *\n * Connects to public MQTT brokers over WebSocket. Peer discovery uses\n * retained presence messages with periodic heartbeats. SDP/ICE relay\n * uses per-peer signal topics. Room discovery uses retained lobby topics.\n *\n * Zero infrastructure cost -- uses free public brokers by default.\n */\nexport class MqttStrategy implements SignalingStrategy {\n readonly selfId: string;\n\n private _appId: string;\n private _config: MqttStrategyConfig;\n private _client: MqttClient | null = null;\n private _roomId: string | null = null;\n private _peerMeta: PeerMetadata = {};\n /** Monotonic counter to detect stale leaveRoom completions */\n private _joinGeneration = 0;\n\n // Lazy init\n private _initPromise: Promise<void> | null = null;\n\n // Callbacks\n private _onPeerDiscovered: ((peerId: string, meta: PeerMetadata) => void)[] = [];\n private _onPeerLeft: ((peerId: string) => void)[] = [];\n private _onSignal: ((fromPeerId: string, data: unknown) => void)[] = [];\n private _onLobby: ((rooms: RoomAnnouncement[]) => void)[] = [];\n\n // State\n private _knownPeers = new Map<string, { meta: PeerMetadata; lastSeen: number }>();\n private _lobbyRooms = new Map<string, RoomAnnouncement>();\n private _presenceTimer: ReturnType<typeof setInterval> | null = null;\n private _warmupTimers: ReturnType<typeof setTimeout>[] = [];\n private _lobbyAnnounceTimer: ReturnType<typeof setInterval> | null = null;\n private _peerExpiryTimer: ReturnType<typeof setInterval> | null = null;\n private _lobbySubscribed = false;\n private _destroyed = false;\n\n constructor(appId: string, config: MqttStrategyConfig = { type: 'mqtt' }) {\n this.selfId = generatePeerId();\n this._appId = appId;\n this._config = config;\n }\n\n // ── Public API ──\n\n async init(): Promise<void> {\n return this._ensureInit();\n }\n\n async joinRoom(roomId: string, peerMeta: PeerMetadata): Promise<void> {\n await this._ensureInit();\n if (!this._client) throw new Error('MQTT client not available');\n\n this._joinGeneration++;\n this._roomId = roomId;\n this._peerMeta = peerMeta;\n\n const topics = mqttTopics(this._appId, roomId, this.selfId);\n\n // Subscribe to room presence (discover peers) and own signal inbox\n await new Promise<void>((resolve, reject) => {\n this._client!.subscribe(\n [topics.roomPresenceWildcard, topics.peerSignalInbox],\n { qos: 1 },\n (err: Error | null) => (err ? reject(err) : resolve()),\n );\n });\n\n // Publish retained presence\n this._publishPresence();\n\n // Rapid warmup announces for fast peer discovery\n for (const delay of PRESENCE_WARMUP_DELAYS_MS) {\n this._warmupTimers.push(setTimeout(() => this._publishPresence(), delay));\n }\n\n // Periodic heartbeat\n this._presenceTimer = setInterval(() => this._publishPresence(), PRESENCE_HEARTBEAT_MS);\n\n // Periodic peer expiry check\n this._peerExpiryTimer = setInterval(() => this._checkPeerExpiry(), PRESENCE_HEARTBEAT_MS);\n }\n\n async leaveRoom(): Promise<void> {\n if (!this._client || !this._roomId) return;\n\n const generation = this._joinGeneration;\n const topics = mqttTopics(this._appId, this._roomId, this.selfId);\n this._clearRoomTimers();\n\n // Clear retained presence\n this._client.publish(topics.peerPresence, '', { retain: true, qos: 1 });\n\n // Unsubscribe from room topics\n this._client.unsubscribe([topics.roomPresenceWildcard, topics.peerSignalInbox]);\n\n this._knownPeers.clear();\n\n // Only null out _roomId if no new joinRoom() has run since we started.\n if (this._joinGeneration === generation) {\n this._roomId = null;\n }\n }\n\n signal(targetPeerId: string, data: unknown): void {\n if (!this._client || !this._roomId) return;\n const targetTopic = `carver/${this._appId}/room/${this._roomId}/signal/${targetPeerId}`;\n this._client.publish(\n targetTopic,\n JSON.stringify({ from: this.selfId, data, ts: Date.now() }),\n { qos: 1 },\n );\n }\n\n subscribeToLobby(cb: (rooms: RoomAnnouncement[]) => void): () => void {\n this._onLobby.push(cb);\n\n // Subscribe to lobby topic (lazy -- waits for init)\n if (!this._lobbySubscribed) {\n this._lobbySubscribed = true;\n this._ensureInit().then(() => {\n if (this._client && !this._destroyed) {\n const lobbyTopic = mqttTopics(this._appId, '', '').lobbyWildcard;\n this._client.subscribe(lobbyTopic, { qos: 0 });\n }\n });\n }\n\n return () => {\n removeFromArray(this._onLobby, cb);\n };\n }\n\n announceRoom(announcement: RoomAnnouncement): void {\n if (!this._client) return;\n const topic = mqttTopics(this._appId, announcement.roomId, '').roomLobbyEntry;\n\n announcement.lastSeen = Date.now();\n this._client.publish(topic, JSON.stringify(announcement), { retain: true, qos: 1 });\n\n // Periodic heartbeat\n if (this._lobbyAnnounceTimer) clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = setInterval(() => {\n announcement.lastSeen = Date.now();\n this._client?.publish(topic, JSON.stringify(announcement), { retain: true, qos: 1 });\n }, ROOM_ANNOUNCE_INTERVAL_MS);\n }\n\n removeRoomAnnouncement(roomId: string): void {\n if (!this._client) return;\n const topic = mqttTopics(this._appId, roomId, '').roomLobbyEntry;\n this._client.publish(topic, '', { retain: true, qos: 1 });\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n }\n\n onPeerDiscovered(cb: (peerId: string, meta: PeerMetadata) => void): () => void {\n this._onPeerDiscovered.push(cb);\n return () => { removeFromArray(this._onPeerDiscovered, cb); };\n }\n\n onPeerLeft(cb: (peerId: string) => void): () => void {\n this._onPeerLeft.push(cb);\n return () => { removeFromArray(this._onPeerLeft, cb); };\n }\n\n onSignal(cb: (fromPeerId: string, data: unknown) => void): () => void {\n this._onSignal.push(cb);\n return () => { removeFromArray(this._onSignal, cb); };\n }\n\n destroy(): void {\n this._destroyed = true;\n this._clearRoomTimers();\n\n // Clean up retained presence\n if (this._client && this._roomId) {\n const topics = mqttTopics(this._appId, this._roomId, this.selfId);\n this._client.publish(topics.peerPresence, '', { retain: true, qos: 1 });\n }\n\n this._client?.end(true);\n this._client = null;\n this._knownPeers.clear();\n this._lobbyRooms.clear();\n this._onPeerDiscovered = [];\n this._onPeerLeft = [];\n this._onSignal = [];\n this._onLobby = [];\n }\n\n // ── Private ──\n\n private _ensureInit(): Promise<void> {\n if (!this._initPromise) {\n this._initPromise = this._doInit();\n }\n return this._initPromise;\n }\n\n private async _doInit(): Promise<void> {\n const mqtt = await import('mqtt');\n const brokers = this._config.brokerUrls ?? DEFAULT_MQTT_BROKERS;\n // Pick a random broker from the available pool\n const brokerUrl = brokers[Math.floor(Math.random() * brokers.length)];\n\n return new Promise<void>((resolve, reject) => {\n const connectFn = mqtt.default?.connect ?? mqtt.connect;\n this._client = connectFn(brokerUrl, {\n clientId: `carver_${this.selfId}`,\n clean: true,\n connectTimeout: 10_000,\n keepalive: 30,\n }) as MqttClient;\n\n this._client.on('connect', () => {\n if (!this._destroyed) resolve();\n });\n\n this._client.on('error', (err: Error) => {\n if (!this._initPromise) return; // already resolved\n reject(err);\n });\n\n this._client.on('message', (topic: string, payload: Buffer) => {\n this._handleMessage(topic, payload);\n });\n });\n }\n\n private _publishPresence(): void {\n if (!this._client || !this._roomId) return;\n const topics = mqttTopics(this._appId, this._roomId, this.selfId);\n this._client.publish(\n topics.peerPresence,\n JSON.stringify({ peerId: this.selfId, meta: this._peerMeta, ts: Date.now() }),\n { retain: true, qos: 1 },\n );\n }\n\n private _handleMessage(topic: string, payload: Buffer): void {\n const raw = payload.toString();\n\n // ── Presence message ──\n const presenceMatch = topic.match(/\\/room\\/[^/]+\\/presence\\/([^/]+)$/);\n if (presenceMatch) {\n const peerId = presenceMatch[1];\n if (peerId === this.selfId) return;\n\n if (!raw) {\n // Empty retained = peer left\n if (this._knownPeers.has(peerId)) {\n this._knownPeers.delete(peerId);\n for (const cb of this._onPeerLeft) cb(peerId);\n }\n return;\n }\n try {\n const msg = JSON.parse(raw);\n const isNew = !this._knownPeers.has(peerId);\n this._knownPeers.set(peerId, { meta: msg.meta ?? {}, lastSeen: msg.ts ?? Date.now() });\n if (isNew) {\n for (const cb of this._onPeerDiscovered) cb(peerId, msg.meta ?? {});\n }\n } catch { /* ignore malformed */ }\n return;\n }\n\n // ── Signal message (SDP / ICE) ──\n const signalMatch = topic.match(/\\/room\\/[^/]+\\/signal\\/([^/]+)$/);\n if (signalMatch) {\n try {\n const msg = JSON.parse(raw);\n if (msg.from && msg.from !== this.selfId) {\n for (const cb of this._onSignal) cb(msg.from, msg.data);\n }\n } catch { /* ignore malformed */ }\n return;\n }\n\n // ── Lobby announcement ──\n const lobbyMatch = topic.match(/\\/lobby\\/([^/]+)$/);\n if (lobbyMatch) {\n const roomId = lobbyMatch[1];\n if (!raw) {\n this._lobbyRooms.delete(roomId);\n } else {\n try {\n const ann = JSON.parse(raw) as RoomAnnouncement;\n if (Date.now() - ann.lastSeen < ROOM_ANNOUNCE_EXPIRY_MS) {\n this._lobbyRooms.set(roomId, ann);\n } else {\n this._lobbyRooms.delete(roomId);\n }\n } catch { /* ignore */ }\n }\n const rooms = Array.from(this._lobbyRooms.values());\n for (const cb of this._onLobby) cb(rooms);\n }\n }\n\n private _checkPeerExpiry(): void {\n const now = Date.now();\n for (const [peerId, data] of this._knownPeers) {\n if (now - data.lastSeen > PEER_EXPIRY_MS) {\n this._knownPeers.delete(peerId);\n for (const cb of this._onPeerLeft) cb(peerId);\n }\n }\n }\n\n private _clearRoomTimers(): void {\n if (this._presenceTimer) { clearInterval(this._presenceTimer); this._presenceTimer = null; }\n for (const t of this._warmupTimers) clearTimeout(t);\n this._warmupTimers = [];\n if (this._lobbyAnnounceTimer) { clearInterval(this._lobbyAnnounceTimer); this._lobbyAnnounceTimer = null; }\n if (this._peerExpiryTimer) { clearInterval(this._peerExpiryTimer); this._peerExpiryTimer = null; }\n }\n}\n","import type {\n SignalingStrategy,\n PeerMetadata,\n RoomAnnouncement,\n FirebaseStrategyConfig,\n} from \"./types\";\nimport {\n generatePeerId,\n firebasePaths,\n removeFromArray,\n ROOM_ANNOUNCE_EXPIRY_MS,\n ROOM_ANNOUNCE_INTERVAL_MS,\n} from \"./utils\";\n\n/**\n * Firebase Realtime Database signaling strategy.\n *\n * Requires the `firebase` package as a peer dependency.\n * Pass either a `databaseURL` (auto-creates a namespaced Firebase app)\n * or an existing `firebaseApp` instance.\n *\n * Presence cleanup is automatic via Firebase onDisconnect().\n */\nexport class FirebaseStrategy implements SignalingStrategy {\n readonly selfId: string;\n\n private _appId: string;\n private _config: FirebaseStrategyConfig;\n private _db: any = null;\n private _firebaseApp: any = null;\n private _ownApp = false;\n private _roomId: string | null = null;\n private _peerMeta: PeerMetadata = {};\n /** Monotonic counter to detect stale leaveRoom completions */\n private _joinGeneration = 0;\n\n // Lazy init\n private _initPromise: Promise<void> | null = null;\n\n // Firebase module references (filled after dynamic import)\n private _fb: {\n ref: any;\n set: any;\n push: any;\n remove: any;\n onValue: any;\n onChildAdded: any;\n onChildRemoved: any;\n onDisconnect: any;\n } | null = null;\n\n // Unsubscribe handles for Firebase listeners\n private _listeners: (() => void)[] = [];\n\n // Callbacks\n private _onPeerDiscovered: ((peerId: string, meta: PeerMetadata) => void)[] = [];\n private _onPeerLeft: ((peerId: string) => void)[] = [];\n private _onSignal: ((fromPeerId: string, data: unknown) => void)[] = [];\n private _onLobby: ((rooms: RoomAnnouncement[]) => void)[] = [];\n\n // State\n private _knownPeers = new Set<string>();\n private _lobbyAnnounceTimer: ReturnType<typeof setInterval> | null = null;\n private _destroyed = false;\n\n constructor(appId: string, config: FirebaseStrategyConfig) {\n this.selfId = generatePeerId();\n this._appId = appId;\n this._config = config;\n }\n\n // ── Public API ──\n\n async init(): Promise<void> {\n return this._ensureInit();\n }\n\n async joinRoom(roomId: string, peerMeta: PeerMetadata): Promise<void> {\n await this._ensureInit();\n if (!this._db || !this._fb) throw new Error('Firebase not initialized');\n\n // Bump generation so any in-flight leaveRoom from a prior call won't\n // null out _roomId after we set it here (React StrictMode race fix).\n this._joinGeneration++;\n\n this._roomId = roomId;\n this._peerMeta = peerMeta;\n const { ref, set, onChildAdded, onChildRemoved, onDisconnect, remove } = this._fb;\n const paths = firebasePaths(this._appId, roomId, this.selfId);\n\n // Clean stale signals from our inbox before listening (prevents\n // replaying SDP from a previous session that wasn't cleaned up).\n await remove(ref(this._db, paths.peerSignalInbox)).catch(() => {});\n\n // 1. Write presence with auto-cleanup on disconnect\n const presenceRef = ref(this._db, paths.peerPresence);\n await set(presenceRef, {\n peerId: this.selfId,\n meta: peerMeta,\n ts: Date.now(),\n });\n onDisconnect(presenceRef).remove();\n\n // 2. Listen for peers joining\n const peersRef = ref(this._db, paths.peers);\n const addedUnsub = onChildAdded(peersRef, (snapshot: any) => {\n const data = snapshot.val();\n if (!data || data.peerId === this.selfId) return;\n if (!this._knownPeers.has(data.peerId)) {\n this._knownPeers.add(data.peerId);\n for (const cb of this._onPeerDiscovered) cb(data.peerId, data.meta ?? {});\n }\n });\n this._listeners.push(() => addedUnsub());\n\n // 3. Listen for peers leaving\n const removedUnsub = onChildRemoved(peersRef, (snapshot: any) => {\n const data = snapshot.val();\n const peerId = data?.peerId ?? snapshot.key;\n if (peerId && this._knownPeers.has(peerId)) {\n this._knownPeers.delete(peerId);\n for (const cb of this._onPeerLeft) cb(peerId);\n }\n });\n this._listeners.push(() => removedUnsub());\n\n // 4. Listen for signals addressed to us\n const signalRef = ref(this._db, paths.peerSignalInbox);\n const signalUnsub = onChildAdded(signalRef, (snapshot: any) => {\n const msg = snapshot.val();\n if (!msg || msg.from === this.selfId) return;\n for (const cb of this._onSignal) cb(msg.from, msg.data);\n // Remove processed signal to keep the inbox clean\n remove(snapshot.ref);\n });\n this._listeners.push(() => signalUnsub());\n }\n\n async leaveRoom(): Promise<void> {\n if (!this._db || !this._fb || !this._roomId) return;\n\n // Capture current state so async cleanup targets the correct room\n // even if joinRoom() is called concurrently (React StrictMode).\n const leavingRoomId = this._roomId;\n const generation = this._joinGeneration;\n\n const { ref, remove } = this._fb;\n const paths = firebasePaths(this._appId, leavingRoomId, this.selfId);\n\n // Detach listeners\n for (const unsub of this._listeners) unsub();\n this._listeners = [];\n\n // Remove presence and signal inbox\n await Promise.all([\n remove(ref(this._db, paths.peerPresence)),\n remove(ref(this._db, paths.peerSignalInbox)),\n ]).catch(() => {});\n\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n\n this._knownPeers.clear();\n\n // Only null out _roomId if no new joinRoom() has run since we started.\n // This prevents the StrictMode race: old leaveRoom completing after\n // new joinRoom already set _roomId to the fresh value.\n if (this._joinGeneration === generation) {\n this._roomId = null;\n }\n }\n\n signal(targetPeerId: string, data: unknown): void {\n if (!this._db || !this._fb || !this._roomId) return;\n const { ref, push } = this._fb;\n\n // Atomic push: single operation writes the key + data together.\n // Avoids the push() + set() two-step that can cause onChildAdded to\n // fire with null if the listener catches the intermediate state.\n const inboxPath = firebasePaths(this._appId, this._roomId, targetPeerId).peerSignalInbox;\n push(ref(this._db, inboxPath), {\n from: this.selfId,\n data: sanitizeForFirebase(data),\n ts: Date.now(),\n });\n }\n\n subscribeToLobby(cb: (rooms: RoomAnnouncement[]) => void): () => void {\n this._onLobby.push(cb);\n\n this._ensureInit().then(() => {\n if (!this._db || !this._fb || this._destroyed) return;\n const { ref, onValue } = this._fb;\n const paths = firebasePaths(this._appId, '', '');\n const lobbyRef = ref(this._db, paths.lobby);\n\n const unsub = onValue(lobbyRef, (snapshot: any) => {\n const data = snapshot.val();\n if (!data) {\n for (const lcb of this._onLobby) lcb([]);\n return;\n }\n const now = Date.now();\n const rooms: RoomAnnouncement[] = Object.values(data).filter(\n (r: any) => r && now - (r.lastSeen ?? 0) < ROOM_ANNOUNCE_EXPIRY_MS,\n ) as RoomAnnouncement[];\n for (const lcb of this._onLobby) lcb(rooms);\n });\n this._listeners.push(() => unsub());\n });\n\n return () => {\n removeFromArray(this._onLobby, cb);\n };\n }\n\n announceRoom(announcement: RoomAnnouncement): void {\n if (!this._db || !this._fb) return;\n const { ref, set } = this._fb;\n const paths = firebasePaths(this._appId, announcement.roomId, '');\n\n announcement.lastSeen = Date.now();\n set(ref(this._db, paths.roomLobbyEntry), announcement);\n\n // Periodic heartbeat\n if (this._lobbyAnnounceTimer) clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = setInterval(() => {\n announcement.lastSeen = Date.now();\n set(ref(this._db, paths.roomLobbyEntry), announcement);\n }, ROOM_ANNOUNCE_INTERVAL_MS);\n }\n\n removeRoomAnnouncement(roomId: string): void {\n if (!this._db || !this._fb) return;\n const { ref, remove } = this._fb;\n remove(ref(this._db, firebasePaths(this._appId, roomId, '').roomLobbyEntry));\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n }\n\n onPeerDiscovered(cb: (peerId: string, meta: PeerMetadata) => void): () => void {\n this._onPeerDiscovered.push(cb);\n return () => { removeFromArray(this._onPeerDiscovered, cb); };\n }\n\n onPeerLeft(cb: (peerId: string) => void): () => void {\n this._onPeerLeft.push(cb);\n return () => { removeFromArray(this._onPeerLeft, cb); };\n }\n\n onSignal(cb: (fromPeerId: string, data: unknown) => void): () => void {\n this._onSignal.push(cb);\n return () => { removeFromArray(this._onSignal, cb); };\n }\n\n destroy(): void {\n this._destroyed = true;\n for (const unsub of this._listeners) unsub();\n this._listeners = [];\n\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n\n // Best-effort cleanup\n if (this._db && this._fb && this._roomId) {\n const { ref, remove } = this._fb;\n const paths = firebasePaths(this._appId, this._roomId, this.selfId);\n remove(ref(this._db, paths.peerPresence)).catch(() => {});\n remove(ref(this._db, paths.peerSignalInbox)).catch(() => {});\n }\n\n // Delete own Firebase app if we created it\n if (this._ownApp && this._firebaseApp) {\n import('firebase/app').then(({ deleteApp }) => {\n deleteApp(this._firebaseApp).catch(() => {});\n });\n }\n\n this._db = null;\n this._firebaseApp = null;\n this._fb = null;\n this._knownPeers.clear();\n this._onPeerDiscovered = [];\n this._onPeerLeft = [];\n this._onSignal = [];\n this._onLobby = [];\n }\n\n // ── Private ──\n\n private _ensureInit(): Promise<void> {\n if (!this._initPromise) {\n this._initPromise = this._doInit();\n }\n return this._initPromise;\n }\n\n private async _doInit(): Promise<void> {\n const { initializeApp, getApps } = await import('firebase/app');\n const {\n getDatabase,\n ref,\n set,\n push,\n remove,\n onValue,\n onChildAdded,\n onChildRemoved,\n onDisconnect,\n } = await import('firebase/database');\n\n this._fb = { ref, set, push, remove, onValue, onChildAdded, onChildRemoved, onDisconnect };\n\n if (this._config.firebaseApp) {\n this._firebaseApp = this._config.firebaseApp;\n this._ownApp = false;\n } else {\n const appName = `carver_${this._appId}`;\n const existing = getApps().find((a: any) => a.name === appName);\n if (existing) {\n this._firebaseApp = existing;\n this._ownApp = false;\n } else {\n this._firebaseApp = initializeApp({ databaseURL: this._config.databaseURL }, appName);\n this._ownApp = true;\n }\n }\n\n this._db = getDatabase(this._firebaseApp);\n }\n}\n\n/**\n * Firebase RTDB deletes any key whose value is `null` (treats null as \"remove\").\n * ICE candidates from `toJSON()` can contain `null` fields (e.g. usernameFragment).\n * We recursively replace `null` with a sentinel so Firebase preserves the key.\n * On the receiving end, `_handleSignal` doesn't need to reverse this because\n * `new RTCIceCandidate()` / `new RTCSessionDescription()` accept missing fields.\n */\nfunction sanitizeForFirebase(obj: unknown): unknown {\n if (obj === null) return '__null__';\n if (Array.isArray(obj)) return obj.map(sanitizeForFirebase);\n if (typeof obj === 'object' && obj !== null) {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[key] = value === null ? '__null__' : sanitizeForFirebase(value);\n }\n return result;\n }\n return obj;\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","/** Default STUN servers (free, public) */\nconst DEFAULT_STUN_SERVERS: RTCIceServer[] = [\n { urls: 'stun:stun.l.google.com:19302' },\n { urls: 'stun:stun1.l.google.com:19302' },\n { urls: 'stun:stun2.l.google.com:19302' },\n { urls: 'stun:stun.cloudflare.com:3478' },\n];\n\n/**\n * Build RTCConfiguration from user-provided ICE servers.\n *\n * If the user provides `iceServers`, those are used as-is (STUN + TURN).\n * Otherwise, default public STUN servers are used.\n *\n * TURN servers should be included in the `iceServers` array by the user:\n * ```ts\n * iceServers: [\n * { urls: 'stun:stun.cloudflare.com:3478' },\n * { urls: 'turn:turn.cloudflare.com:3478', username: '...', credential: '...' },\n * ]\n * ```\n */\nexport function buildICEConfig(options?: {\n iceServers?: RTCIceServer[];\n iceTransportPolicy?: RTCIceTransportPolicy;\n}): RTCConfiguration {\n const servers: RTCIceServer[] =\n options?.iceServers && options.iceServers.length > 0\n ? options.iceServers\n : DEFAULT_STUN_SERVERS;\n\n return {\n iceServers: servers,\n iceCandidatePoolSize: 10,\n iceTransportPolicy: options?.iceTransportPolicy ?? 'all',\n };\n}\n","import type { ChannelOptions } from \"../../types\";\nimport type { PeerState } from \"../types\";\n\nexport interface PeerConnectionEvents {\n onStateChange: (state: PeerState) => void;\n onDataChannel: (channel: RTCDataChannel) => void;\n onIceCandidate: (candidate: RTCIceCandidate) => void;\n}\n\n/**\n * Manages a single RTCPeerConnection to one remote peer.\n *\n * ICE candidates that arrive before the remote description is set are\n * buffered and flushed automatically once setRemoteDescription completes.\n * This is critical for Firebase/MQTT signaling where offer, answer, and\n * candidates can arrive nearly simultaneously.\n */\nexport class PeerConnection {\n readonly peerId: string;\n private _connection: RTCPeerConnection;\n private _channels = new Map<string, RTCDataChannel>();\n private _events: PeerConnectionEvents;\n private _state: PeerState = 'connecting';\n private _remoteDescriptionSet = false;\n private _pendingCandidates: RTCIceCandidateInit[] = [];\n\n constructor(\n peerId: string,\n config: RTCConfiguration,\n events: PeerConnectionEvents,\n ) {\n this.peerId = peerId;\n this._events = events;\n this._connection = new RTCPeerConnection(config);\n\n this._connection.onicecandidate = (e) => {\n if (e.candidate) {\n this._events.onIceCandidate(e.candidate);\n }\n };\n\n this._connection.oniceconnectionstatechange = () => {\n this._updateState();\n };\n\n this._connection.onconnectionstatechange = () => {\n this._updateState();\n };\n\n this._connection.ondatachannel = (e) => {\n const channel = e.channel;\n this._channels.set(channel.label, channel);\n this._events.onDataChannel(channel);\n };\n }\n\n get state(): PeerState {\n return this._state;\n }\n\n get connection(): RTCPeerConnection {\n return this._connection;\n }\n\n private _updateState(): void {\n const iceState = this._connection.iceConnectionState;\n const connState = this._connection.connectionState;\n\n let newState: PeerState;\n if (connState === 'connected' || iceState === 'connected') {\n newState = 'connected';\n } else if (connState === 'failed' || iceState === 'failed') {\n newState = 'failed';\n } else if (connState === 'closed' || iceState === 'closed' || iceState === 'disconnected') {\n newState = 'disconnected';\n } else {\n newState = 'connecting';\n }\n\n if (newState !== this._state) {\n this._state = newState;\n this._events.onStateChange(newState);\n }\n }\n\n async createOffer(): Promise<RTCSessionDescriptionInit> {\n const offer = await this._connection.createOffer();\n await this._connection.setLocalDescription(offer);\n return offer;\n }\n\n async handleOffer(offer: RTCSessionDescriptionInit): Promise<RTCSessionDescriptionInit> {\n await this._connection.setRemoteDescription(new RTCSessionDescription(offer));\n this._remoteDescriptionSet = true;\n await this._flushPendingCandidates();\n const answer = await this._connection.createAnswer();\n await this._connection.setLocalDescription(answer);\n return answer;\n }\n\n async handleAnswer(answer: RTCSessionDescriptionInit): Promise<void> {\n await this._connection.setRemoteDescription(new RTCSessionDescription(answer));\n this._remoteDescriptionSet = true;\n await this._flushPendingCandidates();\n }\n\n async addIceCandidate(candidate: RTCIceCandidateInit): Promise<void> {\n if (!this._remoteDescriptionSet) {\n // Buffer until remote description is set -- prevents silent drops\n this._pendingCandidates.push(candidate);\n return;\n }\n try {\n await this._connection.addIceCandidate(new RTCIceCandidate(candidate));\n } catch {\n // Ignore ICE candidate errors (can happen during race conditions)\n }\n }\n\n private async _flushPendingCandidates(): Promise<void> {\n const candidates = this._pendingCandidates;\n this._pendingCandidates = [];\n for (const c of candidates) {\n try {\n await this._connection.addIceCandidate(new RTCIceCandidate(c));\n } catch {\n // Ignore errors on individual candidates\n }\n }\n }\n\n createDataChannel(name: string, options?: ChannelOptions): RTCDataChannel {\n // If a channel with this label already exists (e.g. received via\n // ondatachannel from the remote peer), reuse it instead of creating\n // a duplicate that fragments send/receive across two channels.\n const existing = this._channels.get(name);\n if (existing && existing.readyState !== 'closed') {\n return existing;\n }\n\n const dcOptions: RTCDataChannelInit = {};\n if (options?.reliable === false) {\n dcOptions.ordered = options?.ordered ?? false;\n dcOptions.maxRetransmits = options?.maxRetransmits ?? 0;\n } else {\n dcOptions.ordered = options?.ordered ?? true;\n }\n const channel = this._connection.createDataChannel(name, dcOptions);\n this._channels.set(name, channel);\n return channel;\n }\n\n getDataChannel(name: string): RTCDataChannel | undefined {\n return this._channels.get(name);\n }\n\n close(): void {\n for (const channel of this._channels.values()) {\n try { channel.close(); } catch { /* ignore */ }\n }\n this._channels.clear();\n this._pendingCandidates = [];\n this._remoteDescriptionSet = false;\n try { this._connection.close(); } catch { /* ignore */ }\n this._state = 'disconnected';\n }\n}\n","import type {\n CarverTransport,\n CarverChannel,\n ChannelOptions,\n TransportConfig,\n Player,\n Room,\n RoomState,\n} from \"../../types\";\nimport type { TransportCallbacks, RateLimitConfig } from \"../types\";\nimport type { SignalingStrategy, PeerMetadata } from \"../strategy/types\";\nimport { buildICEConfig } from \"./ice\";\nimport { PeerConnection } from \"./peer\";\n\nconst ROOM_CONTROL_CHANNEL = 'carver:room-control';\n\ninterface ChannelState<T> {\n name: string;\n options: ChannelOptions;\n receivers: ((data: T, peerId: string) => void)[];\n}\n\n/** Room control messages exchanged over the room-control data channel */\ntype RoomControlMessage =\n | { type: 'player-updated'; player: Player }\n | { type: 'room-updated'; room: Partial<Room> }\n | { type: 'kick'; peerId: string; reason?: string }\n | { type: 'host-changed'; newHostId: string }\n | { type: 'request-ready'; ready: boolean }\n | { type: 'request-metadata'; metadata: Record<string, unknown> }\n | { type: 'request-room-metadata'; metadata: Record<string, unknown> }\n | { type: 'request-room-state'; state: RoomState }\n | { type: 'request-max-players'; maxPlayers: number }\n | { type: 'request-lock' }\n | { type: 'request-unlock' }\n | { type: 'request-transfer-host'; peerId: string }\n | { type: 'sync-state'; room: Room; players: Player[] };\n\n/** Deterministic host election: lowest peerId alphabetically */\nfunction electHost(peerIds: string[]): string {\n return [...peerIds].sort()[0];\n}\n\n/**\n * Implements CarverTransport using WebRTC data channels for game data\n * and a pluggable SignalingStrategy for peer discovery + SDP/ICE relay.\n *\n * No WebSocket server required. The strategy handles signaling through\n * MQTT brokers, Firebase RTDB, or any other network.\n */\nexport class WebRTCTransport implements CarverTransport {\n private _strategy: SignalingStrategy;\n private _peers = new Map<string, PeerConnection>();\n private _peerSet = new Set<string>();\n private _peerId: string;\n private _hostId = '';\n private _isHost = false;\n private _callbacks: TransportCallbacks = {\n onPeerJoin: [],\n onPeerLeave: [],\n onPeerUpdated: [],\n onHostChanged: [],\n };\n private _roomUpdatedCallbacks: ((room: Room) => void)[] = [];\n private _channels = new Map<string, ChannelState<any>>();\n private _iceConfig: RTCConfiguration;\n private _rateLimitConfig: RateLimitConfig = { maxMessagesPerSecond: 60, windowMs: 1000 };\n private _rateLimitCounters = new Map<string, { count: number; resetAt: number }>();\n private _connected = false;\n private _room: Room | null = null;\n private _playerMap = new Map<string, Player>();\n private _initialPeers: Player[] = [];\n private _strategyUnsubs: (() => void)[] = [];\n\n /**\n * @param strategy Shared SignalingStrategy instance (managed by MultiplayerProvider)\n * @param iceServers Optional ICE servers (STUN + TURN). Defaults to public STUN.\n * @param iceTransportPolicy 'all' (default) or 'relay' (force TURN only).\n */\n constructor(\n strategy: SignalingStrategy,\n iceServers?: RTCIceServer[],\n iceTransportPolicy?: RTCIceTransportPolicy,\n ) {\n this._strategy = strategy;\n this._peerId = strategy.selfId;\n this._iceConfig = buildICEConfig({ iceServers, iceTransportPolicy });\n }\n\n // ── CarverTransport getters ──\n\n get peerId(): string { return this._peerId; }\n get peers(): ReadonlySet<string> { return this._peerSet; }\n get hostId(): string { return this._hostId; }\n get isHost(): boolean { return this._isHost; }\n get room(): Room | undefined { return this._room ?? undefined; }\n get initialPlayers(): Player[] { return this._initialPeers; }\n\n // ── Event registration ──\n\n onPeerJoin(cb: (peerId: string) => void): void { this._callbacks.onPeerJoin.push(cb); }\n onPeerLeave(cb: (peerId: string) => void): void { this._callbacks.onPeerLeave.push(cb); }\n onPeerUpdated(cb: (player: Player) => void): void { this._callbacks.onPeerUpdated.push(cb); }\n onRoomUpdated(cb: (room: Room) => void): void { this._roomUpdatedCallbacks.push(cb); }\n onHostChanged(cb: (newHostId: string) => void): void { this._callbacks.onHostChanged.push(cb); }\n\n // ── Channel management ──\n\n createChannel<T>(name: string, options?: ChannelOptions): CarverChannel<T> {\n // Idempotent: return existing channel if already created\n const existing = this._channels.get(name);\n if (existing) {\n return {\n send: (data: T, target?: string | string[]) => this._sendOnChannel(name, data, target),\n onReceive: (cb: (data: T, peerId: string) => void) => { existing.receivers.push(cb); },\n close: () => { this._channels.delete(name); },\n };\n }\n\n const state: ChannelState<T> = {\n name,\n options: options ?? { reliable: true, ordered: true },\n receivers: [],\n };\n this._channels.set(name, state);\n\n // Create data channels on existing peers if already connected\n if (this._connected) {\n for (const peer of this._peers.values()) {\n this._createDataChannelOnPeer(peer, name, state.options);\n }\n }\n\n return {\n send: (data: T, target?: string | string[]) => this._sendOnChannel(name, data, target),\n onReceive: (cb: (data: T, peerId: string) => void) => { state.receivers.push(cb); },\n close: () => { this._channels.delete(name); },\n };\n }\n\n // ── Connect / Disconnect ──\n\n async connect(roomId: string, config?: TransportConfig): Promise<void> {\n // Override ICE config if user passed custom servers\n if (config?.iceServers) {\n this._iceConfig = buildICEConfig({\n iceServers: config.iceServers,\n iceTransportPolicy: config.iceTransportPolicy,\n });\n }\n\n // Pre-register ALL standard channels so the initiator includes them\n // in the initial WebRTC offer. Channels created after the peer connection\n // is established won't get a proper data channel on the remote side.\n this._setupRoomControlChannel();\n this._preRegisterChannel('carver:events', { reliable: true, ordered: true });\n this._preRegisterChannel('carver:snapshots', { reliable: false, ordered: false });\n this._preRegisterChannel('carver:acks', { reliable: true, ordered: true });\n this._preRegisterChannel('carver:inputs', { reliable: true, ordered: true });\n this._preRegisterChannel('carver:network-state', { reliable: true, ordered: true });\n\n // Bind strategy callbacks (store unsubs for cleanup)\n this._strategyUnsubs.push(\n this._strategy.onPeerDiscovered((peerId, meta) => {\n this._onStrategyPeerDiscovered(peerId, meta);\n }),\n );\n this._strategyUnsubs.push(\n this._strategy.onPeerLeft((peerId) => {\n this._removePeer(peerId);\n this._playerMap.delete(peerId);\n this._electAndSetHost();\n for (const cb of this._callbacks.onPeerLeave) cb(peerId);\n }),\n );\n this._strategyUnsubs.push(\n this._strategy.onSignal((fromPeerId, data) => {\n this._handleSignal(fromPeerId, data);\n }),\n );\n\n // Join room via strategy (publishes presence, subscribes to room)\n await this._strategy.joinRoom(roomId, {\n displayName: config?.displayName,\n ...(config?.playerMetadata ?? {}),\n });\n\n // Create self Player\n const selfPlayer: Player = {\n peerId: this._peerId,\n displayName: config?.displayName ?? `Player-${this._peerId.slice(0, 4)}`,\n isHost: false,\n isSelf: true,\n isReady: false,\n isConnected: true,\n metadata: config?.playerMetadata ?? {},\n latencyMs: 0,\n joinedAt: Date.now(),\n };\n this._playerMap.set(this._peerId, selfPlayer);\n\n // Elect host (may just be us if we're the first in the room)\n this._electAndSetHost();\n\n // Create initial Room object\n this._room = {\n id: roomId,\n name: roomId,\n hostId: this._hostId,\n playerCount: this._playerMap.size,\n maxPlayers: config?.maxPlayers ?? 8,\n isPrivate: false,\n metadata: {},\n createdAt: Date.now(),\n state: 'lobby',\n };\n\n this._initialPeers = Array.from(this._playerMap.values());\n this._connected = true;\n }\n\n disconnect(): void {\n this._connected = false;\n\n // Unsubscribe from strategy callbacks\n for (const unsub of this._strategyUnsubs) unsub();\n this._strategyUnsubs = [];\n\n // Close all peer connections\n for (const peer of this._peers.values()) peer.close();\n this._peers.clear();\n this._peerSet.clear();\n this._channels.clear();\n this._rateLimitCounters.clear();\n this._playerMap.clear();\n\n // Leave room via strategy (don't destroy -- provider manages lifecycle)\n this._strategy.leaveRoom().catch(() => {});\n\n this._hostId = '';\n this._isHost = false;\n this._room = null;\n }\n\n /** Expose strategy for lobby hooks */\n get strategy(): SignalingStrategy { return this._strategy; }\n\n // ── Channel pre-registration ──\n\n /**\n * Register a channel name and options without creating data channels yet.\n * When _connectToPeer runs, it iterates this._channels and creates data\n * channels for every registered name in the initial WebRTC offer.\n * Later, when EventSync/SnapshotSync call createChannel(), the idempotent\n * check returns the pre-registered entry and they just attach receivers.\n */\n private _preRegisterChannel(name: string, options: ChannelOptions): void {\n if (this._channels.has(name)) return;\n this._channels.set(name, { name, options, receivers: [] });\n }\n\n // ── Room management (over WebRTC data channels) ──\n\n setReady(ready: boolean): void {\n this._sendControlMessage({ type: 'request-ready', ready });\n }\n\n setMetadata(metadata: Record<string, unknown>): void {\n this._sendControlMessage({ type: 'request-metadata', metadata });\n }\n\n setRoomMetadata(metadata: Record<string, unknown>): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-room-metadata', metadata });\n }\n\n kick(peerId: string, reason?: string): void {\n if (!this._isHost) return;\n // Broadcast kick so the target peer and everyone else knows\n this._broadcastControlMessage({ type: 'kick', peerId, reason });\n }\n\n transferHost(peerId: string): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-transfer-host', peerId });\n }\n\n setRoomState(state: RoomState): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-room-state', state });\n }\n\n setMaxPlayers(n: number): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-max-players', maxPlayers: n });\n }\n\n lockRoom(): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-lock' });\n }\n\n unlockRoom(): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-unlock' });\n }\n\n /** No-op: lobby uses strategy.subscribeToLobby() directly */\n requestRoomList(): void {}\n\n // ── Private: Strategy callbacks ──\n\n private _onStrategyPeerDiscovered(peerId: string, meta: PeerMetadata): void {\n this._connectToPeer(peerId);\n this._peerSet.add(peerId);\n\n const player: Player = {\n peerId,\n displayName: (meta.displayName as string) ?? `Player-${peerId.slice(0, 4)}`,\n isHost: false,\n isSelf: false,\n isReady: false,\n isConnected: true,\n metadata: meta as Record<string, unknown>,\n latencyMs: 0,\n joinedAt: Date.now(),\n };\n this._playerMap.set(peerId, player);\n this._electAndSetHost();\n\n for (const cb of this._callbacks.onPeerJoin) cb(peerId);\n for (const cb of this._callbacks.onPeerUpdated) cb(player);\n }\n\n // ── Private: Room control channel ──\n\n private _setupRoomControlChannel(): void {\n const ch = this.createChannel<RoomControlMessage>(ROOM_CONTROL_CHANNEL, {\n reliable: true,\n ordered: true,\n });\n ch.onReceive((msg, peerId) => {\n this._handleControlMessage(msg, peerId);\n });\n }\n\n private _handleControlMessage(msg: RoomControlMessage, fromPeerId: string): void {\n switch (msg.type) {\n case 'player-updated': {\n this._playerMap.set(msg.player.peerId, msg.player);\n for (const cb of this._callbacks.onPeerUpdated) cb(msg.player);\n break;\n }\n case 'room-updated': {\n if (this._room) {\n Object.assign(this._room, msg.room);\n for (const cb of this._roomUpdatedCallbacks) cb(this._room);\n }\n break;\n }\n case 'kick': {\n if (msg.peerId === this._peerId) {\n // We were kicked\n this.disconnect();\n }\n break;\n }\n case 'host-changed': {\n this._hostId = msg.newHostId;\n this._isHost = msg.newHostId === this._peerId;\n for (const cb of this._callbacks.onHostChanged) cb(msg.newHostId);\n break;\n }\n case 'sync-state': {\n // Full state sync from host (sent to newly connected peers)\n this._room = msg.room;\n for (const p of msg.players) {\n this._playerMap.set(p.peerId, { ...p, isSelf: p.peerId === this._peerId });\n for (const cb of this._callbacks.onPeerUpdated) cb(p);\n }\n for (const cb of this._roomUpdatedCallbacks) cb(msg.room);\n break;\n }\n\n // Host processes requests from peers\n case 'request-ready': {\n if (!this._isHost) break;\n const p = this._playerMap.get(fromPeerId);\n if (p) {\n p.isReady = msg.ready;\n this._broadcastControlMessage({ type: 'player-updated', player: p });\n }\n break;\n }\n case 'request-metadata': {\n if (!this._isHost) break;\n const pm = this._playerMap.get(fromPeerId);\n if (pm) {\n pm.metadata = { ...pm.metadata, ...msg.metadata };\n this._broadcastControlMessage({ type: 'player-updated', player: pm });\n }\n break;\n }\n case 'request-room-metadata': {\n if (!this._isHost || !this._room) break;\n this._room.metadata = { ...this._room.metadata, ...msg.metadata };\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-room-state': {\n if (!this._isHost || !this._room) break;\n this._room.state = msg.state;\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-max-players': {\n if (!this._isHost || !this._room) break;\n this._room.maxPlayers = msg.maxPlayers;\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-lock': {\n if (!this._isHost || !this._room) break;\n (this._room as any).locked = true;\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-unlock': {\n if (!this._isHost || !this._room) break;\n (this._room as any).locked = false;\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-transfer-host': {\n if (!this._isHost) break;\n this._hostId = msg.peerId;\n this._isHost = false;\n this._broadcastControlMessage({ type: 'host-changed', newHostId: msg.peerId });\n break;\n }\n }\n }\n\n private _sendControlMessage(msg: RoomControlMessage): void {\n if (this._isHost && msg.type.startsWith('request-')) {\n // Host processes locally and broadcasts result\n this._handleControlMessage(msg, this._peerId);\n return;\n }\n // Non-host: send to host\n if (this._hostId && this._hostId !== this._peerId) {\n this._sendOnChannel(ROOM_CONTROL_CHANNEL, msg, this._hostId);\n }\n }\n\n private _broadcastControlMessage(msg: RoomControlMessage): void {\n this._sendOnChannel(ROOM_CONTROL_CHANNEL, msg);\n // Handle locally too so host updates its own state\n this._handleControlMessage(msg, this._peerId);\n }\n\n // ── Private: Host election ──\n\n private _electAndSetHost(): void {\n const allIds = [this._peerId, ...this._peerSet];\n const newHostId = electHost(allIds);\n const changed = newHostId !== this._hostId;\n this._hostId = newHostId;\n this._isHost = newHostId === this._peerId;\n\n for (const [id, p] of this._playerMap) {\n p.isHost = id === newHostId;\n }\n if (this._room) {\n this._room.hostId = newHostId;\n this._room.playerCount = this._playerMap.size;\n }\n\n if (changed) {\n for (const cb of this._callbacks.onHostChanged) cb(newHostId);\n }\n }\n\n // ── Private: WebRTC peer management ──\n\n private _connectToPeer(peerId: string): void {\n if (this._peers.has(peerId)) return;\n\n const peer = new PeerConnection(peerId, this._iceConfig, {\n onStateChange: (state) => {\n if (state === 'connected' && this._isHost && this._room) {\n // Send full state sync to the new peer\n const syncMsg: RoomControlMessage = {\n type: 'sync-state',\n room: this._room,\n players: Array.from(this._playerMap.values()),\n };\n setTimeout(() => {\n this._sendOnChannel(ROOM_CONTROL_CHANNEL, syncMsg, peerId);\n }, 100);\n }\n if (state === 'failed' || state === 'disconnected') {\n this._removePeer(peerId);\n this._playerMap.delete(peerId);\n this._electAndSetHost();\n for (const cb of this._callbacks.onPeerLeave) cb(peerId);\n }\n },\n onDataChannel: (channel) => {\n this._setupDataChannelReceiver(channel, peerId);\n },\n onIceCandidate: (candidate) => {\n this._strategy.signal(peerId, { type: 'ice-candidate', candidate: candidate.toJSON() });\n },\n });\n\n this._peers.set(peerId, peer);\n this._peerSet.add(peerId);\n\n // Deterministic initiator: lower peerId creates the offer\n if (this._peerId < peerId) {\n for (const [name, state] of this._channels) {\n this._createDataChannelOnPeer(peer, name, state.options);\n }\n peer.createOffer().then((offer) => {\n this._strategy.signal(peerId, { type: 'offer', sdp: offer });\n });\n }\n }\n\n private async _handleSignal(peerId: string, data: unknown): Promise<void> {\n try {\n const signal = data as {\n type: string;\n sdp?: RTCSessionDescriptionInit;\n candidate?: RTCIceCandidateInit;\n };\n\n let peer = this._peers.get(peerId);\n\n if (signal.type === 'offer') {\n if (!peer) {\n this._connectToPeer(peerId);\n peer = this._peers.get(peerId)!;\n }\n const answer = await peer.handleOffer(signal.sdp!);\n this._strategy.signal(peerId, { type: 'answer', sdp: answer });\n } else if (signal.type === 'answer' && peer) {\n await peer.handleAnswer(signal.sdp!);\n } else if (signal.type === 'ice-candidate' && peer) {\n await peer.addIceCandidate(signal.candidate!);\n }\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.error('[CarverJS] Signal handling failed:', err);\n }\n }\n }\n\n // ── Private: Data channel helpers ──\n\n private _createDataChannelOnPeer(peer: PeerConnection, name: string, options: ChannelOptions): void {\n const channel = peer.createDataChannel(name, options);\n this._setupDataChannelReceiver(channel, peer.peerId);\n }\n\n private _setupDataChannelReceiver(dataChannel: RTCDataChannel, peerId: string): void {\n const channelName = dataChannel.label;\n dataChannel.onmessage = (event) => {\n if (!this._checkRateLimit(peerId)) return;\n const channelState = this._channels.get(channelName);\n if (!channelState) return;\n try {\n const data =\n typeof event.data === 'string' ? JSON.parse(event.data) : event.data;\n for (const receiver of channelState.receivers) receiver(data, peerId);\n } catch {\n // Ignore malformed messages\n }\n };\n }\n\n private _sendOnChannel<T>(channelName: string, data: T, target?: string | string[]): void {\n const serialized =\n typeof data === 'object' &&\n data !== null &&\n !(data instanceof ArrayBuffer) &&\n !(data instanceof Uint8Array)\n ? JSON.stringify(data)\n : data;\n\n const targets = target\n ? Array.isArray(target) ? target : [target]\n : Array.from(this._peers.keys());\n\n for (const pid of targets) {\n const peer = this._peers.get(pid);\n const ch = peer?.getDataChannel(channelName);\n if (ch?.readyState === 'open') {\n try { ch.send(serialized as string); } catch { /* closed between check and send */ }\n }\n }\n }\n\n private _removePeer(peerId: string): void {\n const peer = this._peers.get(peerId);\n if (peer) { peer.close(); this._peers.delete(peerId); }\n this._peerSet.delete(peerId);\n this._rateLimitCounters.delete(peerId);\n }\n\n private _checkRateLimit(peerId: string): boolean {\n const now = Date.now();\n let c = this._rateLimitCounters.get(peerId);\n if (!c || now >= c.resetAt) {\n c = { count: 0, resetAt: now + this._rateLimitConfig.windowMs };\n this._rateLimitCounters.set(peerId, c);\n }\n c.count++;\n return c.count <= this._rateLimitConfig.maxMessagesPerSecond;\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","import type { CarverTransport, CarverChannel, EventPacket } from \"../types\";\n\n/**\n * Layer 1: Event-based messaging over a reliable+ordered channel.\n * Used for turn-based games, chat, and infrequent state changes.\n */\nexport class EventSync {\n private _transport: CarverTransport;\n private _channel: CarverChannel<string>;\n private _handlers = new Map<string, ((payload: unknown, peerId: string) => void)[]>();\n private _hostValidation: boolean;\n\n constructor(transport: CarverTransport, options?: { hostValidation?: boolean }) {\n this._transport = transport;\n this._hostValidation = options?.hostValidation ?? false;\n\n // Create a single reliable+ordered channel for events\n this._channel = transport.createChannel<string>('carver:events', {\n reliable: true,\n ordered: true,\n });\n\n // Listen for incoming events\n this._channel.onReceive((rawData: string, peerId: string) => {\n try {\n const packet: EventPacket = typeof rawData === 'string' ? JSON.parse(rawData) : rawData as unknown as EventPacket;\n\n // If host validation is enabled and we're the host, rebroadcast\n if (this._hostValidation && this._transport.isHost && packet.sender !== this._transport.peerId) {\n // Rebroadcast to all peers (except the original sender)\n const targets = Array.from(this._transport.peers).filter(p => p !== peerId);\n if (targets.length > 0) {\n this._channel.send(JSON.stringify(packet), targets);\n }\n }\n\n // If host validation is enabled and we're NOT the host,\n // only accept events from host (who rebroadcasts validated events)\n if (this._hostValidation && !this._transport.isHost && peerId !== this._transport.hostId) {\n return;\n }\n\n // Fire handlers for this event type\n const handlers = this._handlers.get(packet.type);\n if (handlers) {\n for (const handler of handlers) {\n handler(packet.payload, packet.sender);\n }\n }\n } catch {\n // Ignore malformed events\n }\n });\n }\n\n /**\n * Send a typed event to a specific peer or all peers.\n */\n sendEvent(type: string, payload: unknown, target?: string): void {\n const packet: EventPacket = {\n type,\n payload,\n sender: this._transport.peerId,\n target,\n };\n const serialized = JSON.stringify(packet);\n\n if (this._hostValidation && !this._transport.isHost) {\n // Route through host for validation\n this._channel.send(serialized, this._transport.hostId);\n } else if (target) {\n this._channel.send(serialized, target);\n } else {\n // Broadcast to all peers\n this._channel.send(serialized);\n }\n }\n\n /**\n * Broadcast a typed event to all connected peers.\n */\n broadcast(type: string, payload: unknown): void {\n this.sendEvent(type, payload);\n }\n\n /**\n * Register a handler for a specific event type.\n * Returns an unsubscribe function.\n */\n onEvent(type: string, callback: (payload: unknown, peerId: string) => void): () => void {\n let handlers = this._handlers.get(type);\n if (!handlers) {\n handlers = [];\n this._handlers.set(type, handlers);\n }\n handlers.push(callback);\n\n return () => {\n const arr = this._handlers.get(type);\n if (arr) {\n const idx = arr.indexOf(callback);\n if (idx >= 0) arr.splice(idx, 1);\n if (arr.length === 0) this._handlers.delete(type);\n }\n };\n }\n\n /**\n * Clean up the event channel.\n */\n destroy(): void {\n this._channel.close();\n this._handlers.clear();\n }\n}\n","import type { CarverTransport, CarverChannel, EntityState } from \"../types\";\nimport { Codec, SnapshotBuffer } from \"./codec\";\n\n/**\n * Host-side authority: reads networked actor states, serializes with delta compression,\n * and broadcasts to all clients at the configured broadcast rate.\n */\nexport class HostAuthority {\n private _transport: CarverTransport;\n private _codec: Codec;\n private _snapshotBuffer: SnapshotBuffer;\n private _snapshotChannel: CarverChannel<Uint8Array>;\n private _ackChannel: CarverChannel<string>;\n private _tick = 0;\n private _broadcastRate: number;\n private _broadcastAccumulator = 0;\n private _keyframeInterval: number;\n\n // Per-client last ACK'd tick for delta compression\n private _clientBaselines = new Map<string, number>();\n // Per-client last keyframe tick for scheduling\n private _clientLastKeyframeTick = new Map<string, number>();\n\n // Interest management callback (optional)\n private _interestFilter:\n | ((entityId: string, peerId: string) => boolean)\n | null = null;\n\n constructor(\n transport: CarverTransport,\n codec: Codec,\n snapshotBuffer: SnapshotBuffer,\n options?: {\n broadcastRate?: number;\n keyframeInterval?: number;\n },\n ) {\n this._transport = transport;\n this._codec = codec;\n this._snapshotBuffer = snapshotBuffer;\n this._broadcastRate = options?.broadcastRate ?? 20;\n this._keyframeInterval = options?.keyframeInterval ?? 300;\n\n // Unreliable channel for snapshots (fast, may drop)\n this._snapshotChannel = transport.createChannel<Uint8Array>(\n \"carver:snapshots\",\n {\n reliable: false,\n ordered: false,\n maxRetransmits: 0,\n },\n );\n\n // Reliable channel for ACKs\n this._ackChannel = transport.createChannel<string>(\"carver:acks\", {\n reliable: true,\n ordered: true,\n });\n\n // Listen for client ACKs\n this._ackChannel.onReceive((data: string, peerId: string) => {\n try {\n const ackTick =\n typeof data === \"string\"\n ? parseInt(data, 10)\n : (data as unknown as number);\n if (ackTick === -1) {\n // Client requesting keyframe\n this._clientBaselines.delete(peerId);\n } else {\n this._clientBaselines.set(peerId, ackTick);\n }\n } catch {\n /* ignore malformed ACKs */\n }\n });\n\n // Handle new peer joins — they need a keyframe\n transport.onPeerJoin((peerId) => {\n this._clientBaselines.delete(peerId); // Will force keyframe\n });\n\n transport.onPeerLeave((peerId) => {\n this._clientBaselines.delete(peerId);\n });\n }\n\n /** Set optional interest management filter */\n setInterestFilter(\n filter: ((entityId: string, peerId: string) => boolean) | null,\n ): void {\n this._interestFilter = filter;\n }\n\n /**\n * Called every fixed tick by the sync engine.\n * Collects entity states and decides whether to broadcast.\n */\n tick(\n currentTick: number,\n entities: Map<string, EntityState>,\n delta: number,\n ): void {\n this._tick = currentTick;\n\n // Store snapshot in ring buffer\n this._snapshotBuffer.store(currentTick, new Map(entities));\n\n // Check if we should broadcast this tick\n this._broadcastAccumulator += delta;\n const broadcastInterval = 1 / this._broadcastRate;\n if (this._broadcastAccumulator < broadcastInterval) return;\n this._broadcastAccumulator -= broadcastInterval;\n\n // Broadcast to each connected client\n for (const peerId of this._transport.peers) {\n this._broadcastToClient(peerId, currentTick, entities);\n }\n }\n\n /** Force a keyframe broadcast to all clients (e.g., after host migration) */\n forceKeyframe(\n currentTick: number,\n entities: Map<string, EntityState>,\n ): void {\n this._clientBaselines.clear();\n this._clientLastKeyframeTick.clear();\n this._snapshotBuffer.store(currentTick, new Map(entities));\n for (const peerId of this._transport.peers) {\n this._broadcastToClient(peerId, currentTick, entities);\n }\n }\n\n destroy(): void {\n this._snapshotChannel.close();\n this._ackChannel.close();\n this._clientBaselines.clear();\n this._clientLastKeyframeTick.clear();\n }\n\n private _broadcastToClient(\n peerId: string,\n currentTick: number,\n entities: Map<string, EntityState>,\n ): void {\n // Apply interest management filter\n let clientEntities = entities;\n if (this._interestFilter) {\n clientEntities = new Map<string, EntityState>();\n for (const [id, entity] of entities) {\n if (this._interestFilter(id, peerId)) {\n clientEntities.set(id, entity);\n }\n }\n }\n\n // Determine baseline for delta compression (per-client keyframe scheduling)\n const clientBaseTick = this._clientBaselines.get(peerId);\n const clientLastKeyframe = this._clientLastKeyframeTick.get(peerId) ?? 0;\n const needsKeyframe =\n clientBaseTick === undefined ||\n currentTick - clientLastKeyframe >= this._keyframeInterval;\n\n let baseline: Map<string, EntityState> | undefined;\n if (!needsKeyframe && clientBaseTick !== undefined) {\n baseline = this._snapshotBuffer.get(clientBaseTick);\n }\n\n if (needsKeyframe) {\n this._clientLastKeyframeTick.set(peerId, currentTick);\n }\n\n // Serialize (delta or keyframe)\n const packet = this._codec.serializeDelta(\n currentTick,\n needsKeyframe ? -1 : (clientBaseTick ?? -1),\n clientEntities,\n baseline,\n );\n\n if (packet) {\n this._snapshotChannel.send(packet, peerId);\n }\n }\n}\n","import type {\n CarverTransport,\n CarverChannel,\n EntityState,\n EntityState2D,\n EntityState3D,\n NetworkQuality,\n} from \"../types\";\nimport { Codec } from \"./codec\";\n\ninterface BufferedSnapshot {\n tick: number;\n entities: Map<string, EntityState>;\n receivedAt: number;\n}\n\n/**\n * Client-side state receiver: buffers incoming snapshots and interpolates\n * between them for smooth rendering.\n */\nexport class ClientReceiver {\n private _transport: CarverTransport;\n private _codec: Codec;\n private _snapshotChannel: CarverChannel<Uint8Array>;\n private _ackChannel: CarverChannel<string>;\n\n // Snapshot buffer (ring buffer of last N snapshots)\n private _buffer: BufferedSnapshot[] = [];\n private _bufferSize: number;\n\n // Interpolation settings\n private _method: \"hermite\" | \"linear\";\n private _extrapolateMs: number;\n\n // Current interpolated state\n private _interpolatedState = new Map<string, EntityState>();\n\n // Network quality tracking\n private _lastSnapshotTime = 0;\n private _networkQuality: NetworkQuality = \"good\";\n private _packetLossCount = 0;\n private _packetCount = 0;\n\n // Is2D mode\n private _is2D: boolean;\n\n // Entity state: full accumulated state from keyframes + deltas\n private _fullState = new Map<string, EntityState>();\n\n constructor(\n transport: CarverTransport,\n codec: Codec,\n options?: {\n bufferSize?: number;\n method?: \"hermite\" | \"linear\";\n extrapolateMs?: number;\n is2D?: boolean;\n },\n ) {\n this._transport = transport;\n this._codec = codec;\n this._bufferSize = options?.bufferSize ?? 3;\n this._method = options?.method ?? \"hermite\";\n this._extrapolateMs = options?.extrapolateMs ?? 250;\n this._is2D = options?.is2D ?? false;\n\n // Listen on the unreliable snapshot channel\n this._snapshotChannel = transport.createChannel<Uint8Array>(\n \"carver:snapshots\",\n {\n reliable: false,\n ordered: false,\n maxRetransmits: 0,\n },\n );\n\n this._ackChannel = transport.createChannel<string>(\"carver:acks\", {\n reliable: true,\n ordered: true,\n });\n\n this._snapshotChannel.onReceive((data: Uint8Array) => {\n this._handleSnapshot(data);\n });\n }\n\n /** Get the current interpolated entity states */\n get state(): Map<string, EntityState> {\n return this._interpolatedState;\n }\n\n get networkQuality(): NetworkQuality {\n return this._networkQuality;\n }\n\n /**\n * Called every render frame to interpolate between buffered snapshots.\n * @param renderTime - current render time in ms\n */\n interpolate(renderTime: number): Map<string, EntityState> {\n if (this._buffer.length < 2) {\n // Not enough snapshots to interpolate, return latest\n return this._buffer.length > 0\n ? this._buffer[this._buffer.length - 1].entities\n : this._interpolatedState;\n }\n\n // Find two snapshots to interpolate between\n // We render \"behind\" by one buffer interval\n const interpDelay = (this._bufferSize - 1) * (1000 / 20); // Assume ~20 pps\n const targetTime = renderTime - interpDelay;\n\n let from: BufferedSnapshot | null = null;\n let to: BufferedSnapshot | null = null;\n\n for (let i = 0; i < this._buffer.length - 1; i++) {\n if (\n this._buffer[i].receivedAt <= targetTime &&\n this._buffer[i + 1].receivedAt > targetTime\n ) {\n from = this._buffer[i];\n to = this._buffer[i + 1];\n break;\n }\n }\n\n if (!from || !to) {\n // Extrapolation case: we're past all buffered snapshots\n const latest = this._buffer[this._buffer.length - 1];\n const timeSinceLatest = renderTime - latest.receivedAt;\n\n if (timeSinceLatest > this._extrapolateMs) {\n // Too far behind, just use latest snapshot\n this._updateNetworkQuality(\"poor\");\n return latest.entities;\n }\n\n if (this._buffer.length >= 2) {\n from = this._buffer[this._buffer.length - 2];\n to = latest;\n this._updateNetworkQuality(\"degraded\");\n } else {\n return latest.entities;\n }\n } else {\n this._updateNetworkQuality(\"good\");\n }\n\n // Compute interpolation factor\n const range = to.receivedAt - from.receivedAt;\n const t =\n range > 0\n ? Math.min(1, Math.max(0, (targetTime - from.receivedAt) / range))\n : 1;\n\n // Interpolate all entities\n const result = new Map<string, EntityState>();\n const allIds = new Set([...from.entities.keys(), ...to.entities.keys()]);\n\n for (const id of allIds) {\n const fromEntity = from.entities.get(id);\n const toEntity = to.entities.get(id);\n\n if (toEntity && toEntity.c?.__removed) continue; // Removed entity\n\n if (fromEntity && toEntity) {\n result.set(id, this._interpolateEntity(fromEntity, toEntity, t));\n } else if (toEntity) {\n result.set(id, toEntity);\n }\n }\n\n this._interpolatedState = result;\n return result;\n }\n\n /** Request a keyframe from the host */\n requestKeyframe(): void {\n this._ackChannel.send(\"-1\");\n }\n\n destroy(): void {\n this._snapshotChannel.close();\n this._ackChannel.close();\n this._buffer = [];\n this._interpolatedState.clear();\n this._fullState.clear();\n }\n\n private _handleSnapshot(data: Uint8Array): void {\n try {\n const { tick, baseTick, entities } = this._codec.deserializePacket(data);\n const now = performance.now();\n\n if (baseTick === -1) {\n // Keyframe: replace full state\n this._fullState.clear();\n for (const entity of entities) {\n this._fullState.set(entity.id, entity);\n }\n } else {\n // Delta: apply changes to full state\n for (const entity of entities) {\n if (entity.c?.__removed) {\n this._fullState.delete(entity.id);\n } else {\n this._fullState.set(entity.id, entity);\n }\n }\n }\n\n // Buffer the full state snapshot\n this._buffer.push({\n tick,\n entities: new Map(this._fullState),\n receivedAt: now,\n });\n\n // Keep buffer bounded\n while (this._buffer.length > this._bufferSize * 2) {\n this._buffer.shift();\n }\n\n // Send ACK\n this._ackChannel.send(String(tick));\n\n // Track timing for network quality\n this._lastSnapshotTime = now;\n this._packetCount++;\n } catch {\n this._packetLossCount++;\n }\n }\n\n private _interpolateEntity(\n from: EntityState,\n to: EntityState,\n t: number,\n ): EntityState {\n if (this._is2D || !(\"z\" in from)) {\n return this._interpolateEntity2D(\n from as EntityState2D,\n to as EntityState2D,\n t,\n );\n }\n return this._interpolateEntity3D(\n from as EntityState3D,\n to as EntityState3D,\n t,\n );\n }\n\n private _interpolateEntity2D(\n from: EntityState2D,\n to: EntityState2D,\n t: number,\n ): EntityState2D {\n if (this._method === \"hermite\") {\n return {\n id: to.id,\n x: hermite(from.x, from.vx, to.x, to.vx, t),\n y: hermite(from.y, from.vy, to.y, to.vy, t),\n a: lerpAngle(from.a, to.a, t),\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n va: lerp(from.va, to.va, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n // Linear\n return {\n id: to.id,\n x: lerp(from.x, to.x, t),\n y: lerp(from.y, to.y, t),\n a: lerpAngle(from.a, to.a, t),\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n va: lerp(from.va, to.va, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n\n private _interpolateEntity3D(\n from: EntityState3D,\n to: EntityState3D,\n t: number,\n ): EntityState3D {\n // Quaternion SLERP for rotation\n const [qx, qy, qz, qw] = slerp(\n from.qx,\n from.qy,\n from.qz,\n from.qw,\n to.qx,\n to.qy,\n to.qz,\n to.qw,\n t,\n );\n\n if (this._method === \"hermite\") {\n return {\n id: to.id,\n x: hermite(from.x, from.vx, to.x, to.vx, t),\n y: hermite(from.y, from.vy, to.y, to.vy, t),\n z: hermite(from.z, from.vz, to.z, to.vz, t),\n qx,\n qy,\n qz,\n qw,\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n vz: lerp(from.vz, to.vz, t),\n wx: lerp(from.wx, to.wx, t),\n wy: lerp(from.wy, to.wy, t),\n wz: lerp(from.wz, to.wz, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n\n // Linear\n return {\n id: to.id,\n x: lerp(from.x, to.x, t),\n y: lerp(from.y, to.y, t),\n z: lerp(from.z, to.z, t),\n qx,\n qy,\n qz,\n qw,\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n vz: lerp(from.vz, to.vz, t),\n wx: lerp(from.wx, to.wx, t),\n wy: lerp(from.wy, to.wy, t),\n wz: lerp(from.wz, to.wz, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n\n private _updateNetworkQuality(quality: NetworkQuality): void {\n this._networkQuality = quality;\n }\n}\n\n// ── Math utilities ──\n\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nfunction lerpAngle(a: number, b: number, t: number): number {\n let diff = b - a;\n // Wrap to [-PI, PI]\n while (diff > Math.PI) diff -= Math.PI * 2;\n while (diff < -Math.PI) diff += Math.PI * 2;\n return a + diff * t;\n}\n\n/**\n * Hermite spline interpolation using velocity for smooth curves.\n * h(t) = (2t^3 - 3t^2 + 1)p0 + (t^3 - 2t^2 + t)v0 + (-2t^3 + 3t^2)p1 + (t^3 - t^2)v1\n */\nfunction hermite(\n p0: number,\n v0: number,\n p1: number,\n v1: number,\n t: number,\n): number {\n const t2 = t * t;\n const t3 = t2 * t;\n return (\n (2 * t3 - 3 * t2 + 1) * p0 +\n (t3 - 2 * t2 + t) * v0 +\n (-2 * t3 + 3 * t2) * p1 +\n (t3 - t2) * v1\n );\n}\n\n/**\n * Quaternion SLERP (Spherical Linear Interpolation).\n */\nfunction slerp(\n ax: number,\n ay: number,\n az: number,\n aw: number,\n bx: number,\n by: number,\n bz: number,\n bw: number,\n t: number,\n): [number, number, number, number] {\n // Compute dot product\n let dot = ax * bx + ay * by + az * bz + aw * bw;\n\n // Ensure shortest path\n if (dot < 0) {\n bx = -bx;\n by = -by;\n bz = -bz;\n bw = -bw;\n dot = -dot;\n }\n\n if (dot > 0.9995) {\n // Very close, use linear interpolation\n return [lerp(ax, bx, t), lerp(ay, by, t), lerp(az, bz, t), lerp(aw, bw, t)];\n }\n\n const theta = Math.acos(Math.min(1, Math.max(-1, dot)));\n const sinTheta = Math.sin(theta);\n const wa = Math.sin((1 - t) * theta) / sinTheta;\n const wb = Math.sin(t * theta) / sinTheta;\n\n return [\n ax * wa + bx * wb,\n ay * wa + by * wb,\n az * wa + bz * wb,\n aw * wa + bw * wb,\n ];\n}\n\n/**\n * Interpolate custom properties: lerp numbers, instant-swap others.\n */\nfunction interpolateCustom(\n from: Record<string, unknown> | undefined,\n to: Record<string, unknown> | undefined,\n t: number,\n): Record<string, unknown> | undefined {\n if (!from && !to) return undefined;\n if (!from) return to;\n if (!to) return from;\n\n const result: Record<string, unknown> = {};\n const allKeys = new Set([...Object.keys(from), ...Object.keys(to)]);\n\n for (const key of allKeys) {\n const fromVal = from[key];\n const toVal = to[key];\n if (typeof fromVal === \"number\" && typeof toVal === \"number\") {\n result[key] = lerp(fromVal, toVal, t);\n } else {\n // Instant swap: use target value after halfway\n result[key] = t >= 0.5 ? toVal : fromVal;\n }\n }\n\n return result;\n}\n","import type { CarverTransport, EntityState } from \"../types\";\nimport { Codec, SnapshotBuffer } from \"../core/codec\";\nimport { HostAuthority } from \"../core/HostAuthority\";\nimport { ClientReceiver } from \"../core/ClientReceiver\";\n\nexport interface SnapshotSyncOptions {\n broadcastRate?: number;\n keyframeInterval?: number;\n bufferSize?: number;\n interpolationMethod?: \"hermite\" | \"linear\";\n extrapolateMs?: number;\n is2D?: boolean;\n}\n\n/**\n * Layer 2: Snapshot interpolation sync engine.\n * Host broadcasts state at fixed intervals, clients interpolate.\n */\nexport class SnapshotSync {\n private _transport: CarverTransport;\n private _hostAuthority: HostAuthority | null = null;\n private _clientReceiver: ClientReceiver | null = null;\n private _codec: Codec;\n private _snapshotBuffer: SnapshotBuffer;\n\n constructor(\n transport: CarverTransport,\n codec: Codec,\n snapshotBuffer: SnapshotBuffer,\n options?: SnapshotSyncOptions,\n ) {\n this._transport = transport;\n this._codec = codec;\n this._snapshotBuffer = snapshotBuffer;\n\n if (transport.isHost) {\n this._hostAuthority = new HostAuthority(\n transport,\n codec,\n snapshotBuffer,\n {\n broadcastRate: options?.broadcastRate,\n keyframeInterval: options?.keyframeInterval,\n },\n );\n } else {\n this._clientReceiver = new ClientReceiver(transport, codec, {\n bufferSize: options?.bufferSize,\n method: options?.interpolationMethod,\n extrapolateMs: options?.extrapolateMs,\n is2D: options?.is2D,\n });\n }\n }\n\n get isHost(): boolean {\n return this._hostAuthority !== null;\n }\n\n get hostAuthority(): HostAuthority | null {\n return this._hostAuthority;\n }\n\n get clientReceiver(): ClientReceiver | null {\n return this._clientReceiver;\n }\n\n /** Host: called every fixed tick to potentially broadcast state */\n hostTick(\n tick: number,\n entities: Map<string, EntityState>,\n delta: number,\n ): void {\n this._hostAuthority?.tick(tick, entities, delta);\n }\n\n /** Client: called every render frame to interpolate */\n clientInterpolate(renderTime: number): Map<string, EntityState> {\n return this._clientReceiver?.interpolate(renderTime) ?? new Map();\n }\n\n /** Set interest filter on host authority */\n setInterestFilter(\n filter: ((entityId: string, peerId: string) => boolean) | null,\n ): void {\n this._hostAuthority?.setInterestFilter(filter);\n }\n\n /** Handle host migration: switch from client to host mode */\n promoteToHost(options?: SnapshotSyncOptions): void {\n this._clientReceiver?.destroy();\n this._clientReceiver = null;\n this._hostAuthority = new HostAuthority(\n this._transport,\n this._codec,\n this._snapshotBuffer,\n {\n broadcastRate: options?.broadcastRate,\n keyframeInterval: options?.keyframeInterval,\n },\n );\n }\n\n /** Handle host migration: switch from host to client mode */\n demoteToClient(options?: SnapshotSyncOptions): void {\n this._hostAuthority?.destroy();\n this._hostAuthority = null;\n this._clientReceiver = new ClientReceiver(\n this._transport,\n this._codec,\n {\n bufferSize: options?.bufferSize,\n method: options?.interpolationMethod,\n extrapolateMs: options?.extrapolateMs,\n is2D: options?.is2D,\n },\n );\n }\n\n destroy(): void {\n this._hostAuthority?.destroy();\n this._clientReceiver?.destroy();\n this._hostAuthority = null;\n this._clientReceiver = null;\n }\n}\n","import { pack, unpack } from \"msgpackr\";\nimport type {\n CarverTransport,\n CarverChannel,\n EntityState,\n EntityState3D,\n InputPacket,\n} from \"../types\";\nimport { Codec } from \"../core/codec\";\nimport { TickKeeper } from \"../core/TickKeeper\";\n\ninterface PredictionOptions {\n maxRewindTicks: number;\n errorSmoothingDecay: number;\n maxErrorPerFrame: number;\n snapThreshold: number;\n lagCompensation: boolean;\n}\n\ninterface InputBufferEntry {\n tick: number;\n input: unknown;\n}\n\ninterface ErrorCorrection {\n x: number;\n y: number;\n z: number;\n}\n\nconst DEFAULT_OPTIONS: PredictionOptions = {\n maxRewindTicks: 15,\n errorSmoothingDecay: 0.85,\n maxErrorPerFrame: 5,\n snapThreshold: 15,\n lagCompensation: false,\n};\n\n/**\n * Layer 3: Client-side prediction with server reconciliation.\n * Builds on top of Layer 2 (SnapshotSync).\n *\n * Flow:\n * Client: input -> apply locally (predict) -> store in buffer -> send to host\n * Host: receive input -> apply to simulation -> broadcast state + lastProcessedInputTick\n * Client: receive state -> compare with prediction ->\n * if mismatch: reset to server state + replay unacked inputs -> visual smoothing\n */\nexport class PredictionSync {\n private _transport: CarverTransport;\n private _codec: Codec;\n private _tickKeeper: TickKeeper;\n private _options: PredictionOptions;\n\n // Channels\n private _inputChannel: CarverChannel<string>;\n private _stateChannel: CarverChannel<Uint8Array>;\n private _ackChannel: CarverChannel<string>;\n\n // Input buffer: ring buffer of recent inputs keyed by tick\n private _inputBuffer: InputBufferEntry[] = [];\n // Per-client last processed input tick (host-side tracking)\n private _clientLastProcessedTick = new Map<string, number>();\n\n // Predicted state (client-side)\n private _predictedState = new Map<string, EntityState>();\n\n // Error correction vectors per entity\n private _errorCorrections = new Map<string, ErrorCorrection>();\n\n // Server state (last received authoritative snapshot)\n private _serverState = new Map<string, EntityState>();\n private _serverTick = 0;\n\n // Physics step callback (provided by developer)\n private _onPhysicsStep:\n | ((inputs: Map<string, unknown>, tick: number, isRollback: boolean) => void)\n | null = null;\n\n // Own input for current tick\n private _currentInput: unknown = null;\n\n // Is host\n private _isHost: boolean;\n\n constructor(\n transport: CarverTransport,\n codec: Codec,\n tickKeeper: TickKeeper,\n options?: Partial<PredictionOptions>,\n ) {\n this._transport = transport;\n this._codec = codec;\n this._tickKeeper = tickKeeper;\n this._options = { ...DEFAULT_OPTIONS, ...options };\n this._isHost = transport.isHost;\n\n // Reliable channel for inputs (client -> host)\n this._inputChannel = transport.createChannel<string>(\"carver:inputs\", {\n reliable: true,\n ordered: true,\n });\n\n // Unreliable channel for state (host -> clients)\n this._stateChannel = transport.createChannel<Uint8Array>(\"carver:pred-state\", {\n reliable: false,\n ordered: false,\n maxRetransmits: 0,\n });\n\n // Reliable ACK channel\n this._ackChannel = transport.createChannel<string>(\"carver:pred-acks\", {\n reliable: true,\n ordered: true,\n });\n\n if (this._isHost) {\n this._setupHostListeners();\n } else {\n this._setupClientListeners();\n }\n }\n\n /** Set the physics step callback (required for rollback re-simulation) */\n setPhysicsStep(\n cb: (inputs: Map<string, unknown>, tick: number, isRollback: boolean) => void,\n ): void {\n this._onPhysicsStep = cb;\n }\n\n /** Set the current input for this tick (client-side) */\n setInput(input: unknown): void {\n this._currentInput = input;\n }\n\n /**\n * Called every fixed tick on the client.\n * Applies input locally (prediction), buffers it, and sends to host.\n */\n clientTick(tick: number): void {\n if (this._isHost) return;\n\n // Buffer the input\n if (this._currentInput !== null) {\n this._inputBuffer.push({ tick, input: this._currentInput });\n\n // Send input to host\n const packet: InputPacket = {\n t: tick,\n i: this._currentInput,\n p: this._transport.peerId,\n };\n this._inputChannel.send(JSON.stringify(packet));\n\n // Apply input locally (prediction)\n if (this._onPhysicsStep) {\n const inputs = new Map<string, unknown>();\n inputs.set(this._transport.peerId, this._currentInput);\n this._onPhysicsStep(inputs, tick, false);\n }\n\n this._currentInput = null;\n }\n\n // Trim old inputs from buffer\n const minTick = tick - this._options.maxRewindTicks * 2;\n while (this._inputBuffer.length > 0 && this._inputBuffer[0].tick < minTick) {\n this._inputBuffer.shift();\n }\n }\n\n /**\n * Called every fixed tick on the host.\n * Processes received inputs and broadcasts authoritative state.\n */\n hostTick(tick: number, entities: Map<string, EntityState>, _delta: number): void {\n if (!this._isHost) return;\n\n // Broadcast authoritative state with per-client last processed input tick\n const stateArray = Array.from(entities.values());\n const data = this._codec.serialize(stateArray);\n\n // Send per-client packets with each client's own last processed input tick\n for (const peerId of this._transport.peers) {\n const lastTick = this._clientLastProcessedTick.get(peerId) ?? -1;\n const packet = {\n t: tick,\n s: data,\n li: lastTick,\n };\n this._stateChannel.send(pack(packet), peerId);\n }\n }\n\n /**\n * Called every render frame on the client to apply visual error smoothing.\n * Returns the corrected entity states.\n */\n applyErrorSmoothing(entities: Map<string, EntityState>): Map<string, EntityState> {\n const result = new Map<string, EntityState>();\n const decay = this._options.errorSmoothingDecay;\n\n for (const [id, entity] of entities) {\n const correction = this._errorCorrections.get(id);\n if (!correction) {\n result.set(id, entity);\n continue;\n }\n\n // Apply correction and decay\n const corrected = { ...entity };\n corrected.x += correction.x;\n corrected.y += correction.y;\n if (\"z\" in corrected) {\n (corrected as EntityState3D).z += correction.z;\n }\n\n // Decay the correction\n correction.x *= decay;\n correction.y *= decay;\n correction.z *= decay;\n\n // Remove if negligible\n const mag = Math.abs(correction.x) + Math.abs(correction.y) + Math.abs(correction.z);\n if (mag < 0.001) {\n this._errorCorrections.delete(id);\n }\n\n result.set(id, corrected);\n }\n\n return result;\n }\n\n get predictedState(): Map<string, EntityState> {\n return this._predictedState;\n }\n\n get serverTick(): number {\n return this._serverTick;\n }\n\n destroy(): void {\n this._inputChannel.close();\n this._stateChannel.close();\n this._ackChannel.close();\n this._inputBuffer = [];\n this._predictedState.clear();\n this._errorCorrections.clear();\n this._serverState.clear();\n }\n\n // ── Private: Host-side ──\n\n private _setupHostListeners(): void {\n // Receive inputs from clients\n this._inputChannel.onReceive((rawData: string, peerId: string) => {\n try {\n const packet: InputPacket = JSON.parse(rawData);\n // Apply input to simulation via callback\n if (this._onPhysicsStep) {\n const inputs = new Map<string, unknown>();\n inputs.set(peerId, packet.i);\n this._onPhysicsStep(inputs, packet.t, false);\n }\n const prevTick = this._clientLastProcessedTick.get(peerId) ?? -1;\n this._clientLastProcessedTick.set(peerId, Math.max(prevTick, packet.t));\n } catch (err) {\n if (typeof console !== 'undefined') console.debug('[CarverJS] Malformed input packet:', err);\n }\n });\n }\n\n // ── Private: Client-side ──\n\n private _setupClientListeners(): void {\n // Receive authoritative state from host\n this._stateChannel.onReceive((data: Uint8Array) => {\n try {\n const packet = unpack(data) as { t: number; s: Uint8Array; li: number };\n\n const entities = this._codec.deserialize(packet.s);\n const serverTick = packet.t;\n const lastInputTick = packet.li;\n\n this._serverTick = serverTick;\n this._tickKeeper.setServerTick(serverTick);\n\n // Build server state map\n this._serverState.clear();\n for (const entity of entities) {\n this._serverState.set(entity.id, entity);\n }\n\n // Reconciliation: compare predicted state with server state\n this._reconcile(lastInputTick);\n } catch (err) {\n if (typeof console !== 'undefined') console.debug('[CarverJS] Malformed state packet:', err);\n }\n });\n }\n\n private _reconcile(lastInputTick: number): void {\n // Remove acknowledged inputs from buffer\n this._inputBuffer = this._inputBuffer.filter((entry) => entry.tick > lastInputTick);\n\n // Compare predicted state with server state\n let needsRollback = false;\n let maxError = 0;\n\n for (const [id, serverEntity] of this._serverState) {\n const predicted = this._predictedState.get(id);\n if (!predicted) continue;\n\n const error = this._computeError(predicted, serverEntity);\n maxError = Math.max(maxError, error);\n\n if (error > this._options.maxErrorPerFrame) {\n needsRollback = true;\n }\n }\n\n if (maxError > this._options.snapThreshold) {\n // Error too large -- hard snap to server state\n this._predictedState = new Map(this._serverState);\n this._errorCorrections.clear();\n return;\n }\n\n if (needsRollback) {\n // Store current positions for visual smoothing\n const oldPositions = new Map<string, { x: number; y: number; z: number }>();\n for (const [id, entity] of this._predictedState) {\n oldPositions.set(id, {\n x: entity.x,\n y: entity.y,\n z: \"z\" in entity ? (entity as EntityState3D).z : 0,\n });\n }\n\n // Reset to server state\n this._predictedState = new Map(this._serverState);\n\n // Replay unacked inputs\n if (this._onPhysicsStep) {\n for (const entry of this._inputBuffer) {\n const inputs = new Map<string, unknown>();\n inputs.set(this._transport.peerId, entry.input);\n this._onPhysicsStep(inputs, entry.tick, true); // isRollback = true\n }\n }\n\n // Compute visual error correction vectors\n for (const [id, newEntity] of this._predictedState) {\n const oldPos = oldPositions.get(id);\n if (oldPos) {\n this._errorCorrections.set(id, {\n x: oldPos.x - newEntity.x,\n y: oldPos.y - newEntity.y,\n z: oldPos.z - (\"z\" in newEntity ? (newEntity as EntityState3D).z : 0),\n });\n }\n }\n }\n }\n\n private _computeError(predicted: EntityState, server: EntityState): number {\n const dx = predicted.x - server.x;\n const dy = predicted.y - server.y;\n let dz = 0;\n if (\"z\" in predicted && \"z\" in server) {\n dz = (predicted as EntityState3D).z - (server as EntityState3D).z;\n }\n return Math.sqrt(dx * dx + dy * dy + dz * dz);\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":["import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_msgpackr","import_react","import_react"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/MultiplayerProvider.ts","../src/transport/strategy/utils.ts","../src/transport/strategy/mqtt.ts","../src/transport/strategy/firebase.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/transport/webrtc/ice.ts","../src/transport/webrtc/peer.ts","../src/transport/webrtc/WebRTCTransport.ts","../src/hooks/useLobby.ts","../src/hooks/usePlayers.ts","../src/hooks/useHost.ts","../src/hooks/useMultiplayer.ts","../src/sync/EventSync.ts","../src/core/HostAuthority.ts","../src/core/ClientReceiver.ts","../src/sync/SnapshotSync.ts","../src/core/InputBuffer.ts","../src/core/InputUtils.ts","../src/sync/Rollback.ts","../src/sync/PredictionSync.ts","../src/core/NetworkSimulator.ts","../src/hooks/useNetworkEvents.ts","../src/hooks/useNetworkState.ts","../src/core/DebugOverlay.ts","../src/core/InterestManager.ts"],"sourcesContent":["// Components\nexport { MultiplayerProvider } from \"./components/MultiplayerProvider\";\nexport type { MultiplayerProviderProps } from \"./components/MultiplayerProvider\";\nexport { MultiplayerBridge } from \"./components/MultiplayerBridge\";\n\n// Hooks\nexport { useRoom } from \"./hooks/useRoom\";\nexport { useLobby } from \"./hooks/useLobby\";\nexport { usePlayers } from \"./hooks/usePlayers\";\nexport { useHost } from \"./hooks/useHost\";\nexport { useMultiplayer } from \"./hooks/useMultiplayer\";\nexport { useNetworkEvents } from \"./hooks/useNetworkEvents\";\nexport { useNetworkState } from \"./hooks/useNetworkState\";\n\n// Strategy (for advanced users who want direct access)\nexport { MqttStrategy, FirebaseStrategy } from \"./transport/strategy\";\n\n// Core utilities (advanced)\nexport { DebugOverlay } from \"./core/DebugOverlay\";\nexport type { DebugStats, DebugOverlayOptions } from \"./core/DebugOverlay\";\nexport { NetworkSimulator } from \"./core/NetworkSimulator\";\nexport type { NetworkSimulatorOptions } from \"./core/NetworkSimulator\";\nexport { InterestManager } from \"./core/InterestManager\";\nexport type { InterestManagerOptions } from \"./core/InterestManager\";\nexport { InputBuffer } from \"./core/InputBuffer\";\nexport { computeJustPressed } from \"./core/InputUtils\";\n\n// Re-export types\nexport type * from \"./types\";\n","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","/** Generate a random peer ID (20 chars, URL-safe) */\nexport function generatePeerId(): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n const bytes = new Uint8Array(20);\n crypto.getRandomValues(bytes);\n let id = '';\n for (let i = 0; i < 20; i++) {\n id += chars[bytes[i] % chars.length];\n }\n return id;\n}\n\n/** Build MQTT topic paths for a given appId + roomId */\nexport function mqttTopics(appId: string, roomId: string, peerId?: string) {\n const base = `carver/${appId}`;\n return {\n /** Lobby wildcard: subscribe to discover all room announcements */\n lobbyWildcard: `${base}/lobby/+`,\n /** Single room lobby entry */\n roomLobbyEntry: `${base}/lobby/${roomId}`,\n /** Wildcard for all peer presence in a room */\n roomPresenceWildcard: `${base}/room/${roomId}/presence/+`,\n /** This peer's presence topic */\n peerPresence: peerId ? `${base}/room/${roomId}/presence/${peerId}` : '',\n /** This peer's signal inbox */\n peerSignalInbox: peerId ? `${base}/room/${roomId}/signal/${peerId}` : '',\n };\n}\n\n/** Build Firebase RTDB paths for a given appId + roomId */\nexport function firebasePaths(appId: string, roomId: string, peerId?: string) {\n const base = `${appId}/__carver__`;\n return {\n lobby: `${base}/lobby`,\n roomLobbyEntry: `${base}/lobby/${roomId}`,\n peers: `${base}/rooms/${roomId}/peers`,\n peerPresence: peerId ? `${base}/rooms/${roomId}/peers/${peerId}` : '',\n peerSignalInbox: peerId ? `${base}/rooms/${roomId}/signals/${peerId}` : '',\n };\n}\n\n/** Default MQTT brokers (WebSocket endpoints, free/public) */\nexport const DEFAULT_MQTT_BROKERS = [\n 'wss://broker.emqx.io:8084/mqtt',\n 'wss://test.mosquitto.org:8081/mqtt',\n];\n\n/** Room announcement expiry time (30s without heartbeat = stale) */\nexport const ROOM_ANNOUNCE_EXPIRY_MS = 30_000;\n\n/** Room announcement heartbeat interval */\nexport const ROOM_ANNOUNCE_INTERVAL_MS = 10_000;\n\n/** Peer presence heartbeat interval */\nexport const PRESENCE_HEARTBEAT_MS = 5_000;\n\n/** Peer expiry: 3 missed heartbeats */\nexport const PEER_EXPIRY_MS = PRESENCE_HEARTBEAT_MS * 3;\n\n/** Rapid warmup announces for faster initial peer discovery */\nexport const PRESENCE_WARMUP_DELAYS_MS = [200, 500, 1500];\n\n/** Remove an item from an array by reference. Returns true if found. */\nexport function removeFromArray<T>(arr: T[], item: T): boolean {\n const idx = arr.indexOf(item);\n if (idx >= 0) {\n arr.splice(idx, 1);\n return true;\n }\n return false;\n}\n","import type {\n SignalingStrategy,\n PeerMetadata,\n RoomAnnouncement,\n MqttStrategyConfig,\n} from \"./types\";\nimport {\n generatePeerId,\n mqttTopics,\n removeFromArray,\n DEFAULT_MQTT_BROKERS,\n ROOM_ANNOUNCE_EXPIRY_MS,\n ROOM_ANNOUNCE_INTERVAL_MS,\n PRESENCE_HEARTBEAT_MS,\n PEER_EXPIRY_MS,\n PRESENCE_WARMUP_DELAYS_MS,\n} from \"./utils\";\n\n// mqtt.MqttClient type (avoid hard import at module level)\ntype MqttClient = {\n on(event: string, cb: (...args: any[]) => void): void;\n subscribe(topic: string | string[], opts: Record<string, unknown>, cb?: (err: Error | null) => void): void;\n unsubscribe(topic: string | string[]): void;\n publish(topic: string, payload: string | Buffer, opts?: Record<string, unknown>): void;\n end(force?: boolean): void;\n};\n\n/**\n * MQTT-based signaling strategy.\n *\n * Connects to public MQTT brokers over WebSocket. Peer discovery uses\n * retained presence messages with periodic heartbeats. SDP/ICE relay\n * uses per-peer signal topics. Room discovery uses retained lobby topics.\n *\n * Zero infrastructure cost -- uses free public brokers by default.\n */\nexport class MqttStrategy implements SignalingStrategy {\n readonly selfId: string;\n\n private _appId: string;\n private _config: MqttStrategyConfig;\n private _client: MqttClient | null = null;\n private _roomId: string | null = null;\n private _peerMeta: PeerMetadata = {};\n /** Monotonic counter to detect stale leaveRoom completions */\n private _joinGeneration = 0;\n\n // Lazy init\n private _initPromise: Promise<void> | null = null;\n\n // Callbacks\n private _onPeerDiscovered: ((peerId: string, meta: PeerMetadata) => void)[] = [];\n private _onPeerLeft: ((peerId: string) => void)[] = [];\n private _onSignal: ((fromPeerId: string, data: unknown) => void)[] = [];\n private _onLobby: ((rooms: RoomAnnouncement[]) => void)[] = [];\n\n // State\n private _knownPeers = new Map<string, { meta: PeerMetadata; lastSeen: number }>();\n private _lobbyRooms = new Map<string, RoomAnnouncement>();\n private _presenceTimer: ReturnType<typeof setInterval> | null = null;\n private _warmupTimers: ReturnType<typeof setTimeout>[] = [];\n private _lobbyAnnounceTimer: ReturnType<typeof setInterval> | null = null;\n private _peerExpiryTimer: ReturnType<typeof setInterval> | null = null;\n private _lobbySubscribed = false;\n private _destroyed = false;\n\n constructor(appId: string, config: MqttStrategyConfig = { type: 'mqtt' }) {\n this.selfId = generatePeerId();\n this._appId = appId;\n this._config = config;\n }\n\n // ── Public API ──\n\n async init(): Promise<void> {\n return this._ensureInit();\n }\n\n async joinRoom(roomId: string, peerMeta: PeerMetadata): Promise<void> {\n await this._ensureInit();\n if (!this._client) throw new Error('MQTT client not available');\n\n this._joinGeneration++;\n this._roomId = roomId;\n this._peerMeta = peerMeta;\n\n const topics = mqttTopics(this._appId, roomId, this.selfId);\n\n // Subscribe to room presence (discover peers) and own signal inbox\n await new Promise<void>((resolve, reject) => {\n this._client!.subscribe(\n [topics.roomPresenceWildcard, topics.peerSignalInbox],\n { qos: 1 },\n (err: Error | null) => (err ? reject(err) : resolve()),\n );\n });\n\n // Publish retained presence\n this._publishPresence();\n\n // Rapid warmup announces for fast peer discovery\n for (const delay of PRESENCE_WARMUP_DELAYS_MS) {\n this._warmupTimers.push(setTimeout(() => this._publishPresence(), delay));\n }\n\n // Periodic heartbeat\n this._presenceTimer = setInterval(() => this._publishPresence(), PRESENCE_HEARTBEAT_MS);\n\n // Periodic peer expiry check\n this._peerExpiryTimer = setInterval(() => this._checkPeerExpiry(), PRESENCE_HEARTBEAT_MS);\n }\n\n async leaveRoom(): Promise<void> {\n if (!this._client || !this._roomId) return;\n\n const generation = this._joinGeneration;\n const topics = mqttTopics(this._appId, this._roomId, this.selfId);\n this._clearRoomTimers();\n\n // Clear retained presence\n this._client.publish(topics.peerPresence, '', { retain: true, qos: 1 });\n\n // Unsubscribe from room topics\n this._client.unsubscribe([topics.roomPresenceWildcard, topics.peerSignalInbox]);\n\n this._knownPeers.clear();\n\n // Only null out _roomId if no new joinRoom() has run since we started.\n if (this._joinGeneration === generation) {\n this._roomId = null;\n }\n }\n\n signal(targetPeerId: string, data: unknown): void {\n if (!this._client || !this._roomId) return;\n const targetTopic = `carver/${this._appId}/room/${this._roomId}/signal/${targetPeerId}`;\n this._client.publish(\n targetTopic,\n JSON.stringify({ from: this.selfId, data, ts: Date.now() }),\n { qos: 1 },\n );\n }\n\n subscribeToLobby(cb: (rooms: RoomAnnouncement[]) => void): () => void {\n this._onLobby.push(cb);\n\n // Subscribe to lobby topic (lazy -- waits for init)\n if (!this._lobbySubscribed) {\n this._lobbySubscribed = true;\n this._ensureInit().then(() => {\n if (this._client && !this._destroyed) {\n const lobbyTopic = mqttTopics(this._appId, '', '').lobbyWildcard;\n this._client.subscribe(lobbyTopic, { qos: 0 });\n }\n });\n }\n\n return () => {\n removeFromArray(this._onLobby, cb);\n };\n }\n\n private _lastAnnouncement: RoomAnnouncement | null = null;\n\n updateRoomOccupancy(roomId: string, playerCount: number, state?: 'lobby' | 'playing' | 'ended'): void {\n const ann = this._lastAnnouncement;\n if (!ann || ann.roomId !== roomId || !this._client) return;\n ann.playerCount = playerCount;\n if (state) ann.state = state;\n ann.lastSeen = Date.now();\n const topic = mqttTopics(this._appId, roomId, '').roomLobbyEntry;\n this._client.publish(topic, JSON.stringify(ann), { retain: true, qos: 1 });\n }\n\n announceRoom(announcement: RoomAnnouncement): void {\n if (!this._client) return;\n const topic = mqttTopics(this._appId, announcement.roomId, '').roomLobbyEntry;\n\n this._lastAnnouncement = announcement;\n announcement.lastSeen = Date.now();\n this._client.publish(topic, JSON.stringify(announcement), { retain: true, qos: 1 });\n\n // Periodic heartbeat\n if (this._lobbyAnnounceTimer) clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = setInterval(() => {\n announcement.lastSeen = Date.now();\n this._client?.publish(topic, JSON.stringify(announcement), { retain: true, qos: 1 });\n }, ROOM_ANNOUNCE_INTERVAL_MS);\n }\n\n removeRoomAnnouncement(roomId: string): void {\n if (!this._client) return;\n const topic = mqttTopics(this._appId, roomId, '').roomLobbyEntry;\n this._client.publish(topic, '', { retain: true, qos: 1 });\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n }\n\n onPeerDiscovered(cb: (peerId: string, meta: PeerMetadata) => void): () => void {\n this._onPeerDiscovered.push(cb);\n return () => { removeFromArray(this._onPeerDiscovered, cb); };\n }\n\n onPeerLeft(cb: (peerId: string) => void): () => void {\n this._onPeerLeft.push(cb);\n return () => { removeFromArray(this._onPeerLeft, cb); };\n }\n\n onSignal(cb: (fromPeerId: string, data: unknown) => void): () => void {\n this._onSignal.push(cb);\n return () => { removeFromArray(this._onSignal, cb); };\n }\n\n destroy(): void {\n this._destroyed = true;\n this._clearRoomTimers();\n\n // Clean up retained presence\n if (this._client && this._roomId) {\n const topics = mqttTopics(this._appId, this._roomId, this.selfId);\n this._client.publish(topics.peerPresence, '', { retain: true, qos: 1 });\n }\n\n this._client?.end(true);\n this._client = null;\n this._knownPeers.clear();\n this._lobbyRooms.clear();\n this._onPeerDiscovered = [];\n this._onPeerLeft = [];\n this._onSignal = [];\n this._onLobby = [];\n }\n\n // ── Private ──\n\n private _ensureInit(): Promise<void> {\n if (!this._initPromise) {\n this._initPromise = this._doInit();\n }\n return this._initPromise;\n }\n\n private async _doInit(): Promise<void> {\n const mqtt = await import('mqtt');\n const brokers = this._config.brokerUrls ?? DEFAULT_MQTT_BROKERS;\n // Pick a random broker from the available pool\n const brokerUrl = brokers[Math.floor(Math.random() * brokers.length)];\n\n return new Promise<void>((resolve, reject) => {\n const connectFn = mqtt.default?.connect ?? mqtt.connect;\n this._client = connectFn(brokerUrl, {\n clientId: `carver_${this.selfId}`,\n clean: true,\n connectTimeout: 10_000,\n keepalive: 30,\n }) as MqttClient;\n\n this._client.on('connect', () => {\n if (!this._destroyed) resolve();\n });\n\n this._client.on('error', (err: Error) => {\n if (!this._initPromise) return; // already resolved\n reject(err);\n });\n\n this._client.on('message', (topic: string, payload: Buffer) => {\n this._handleMessage(topic, payload);\n });\n });\n }\n\n private _publishPresence(): void {\n if (!this._client || !this._roomId) return;\n const topics = mqttTopics(this._appId, this._roomId, this.selfId);\n this._client.publish(\n topics.peerPresence,\n JSON.stringify({ peerId: this.selfId, meta: this._peerMeta, ts: Date.now() }),\n { retain: true, qos: 1 },\n );\n }\n\n private _handleMessage(topic: string, payload: Buffer): void {\n const raw = payload.toString();\n\n // ── Presence message ──\n const presenceMatch = topic.match(/\\/room\\/[^/]+\\/presence\\/([^/]+)$/);\n if (presenceMatch) {\n const peerId = presenceMatch[1];\n if (peerId === this.selfId) return;\n\n if (!raw) {\n // Empty retained = peer left\n if (this._knownPeers.has(peerId)) {\n this._knownPeers.delete(peerId);\n for (const cb of this._onPeerLeft) cb(peerId);\n }\n return;\n }\n try {\n const msg = JSON.parse(raw);\n const isNew = !this._knownPeers.has(peerId);\n this._knownPeers.set(peerId, { meta: msg.meta ?? {}, lastSeen: msg.ts ?? Date.now() });\n if (isNew) {\n for (const cb of this._onPeerDiscovered) cb(peerId, msg.meta ?? {});\n }\n } catch { /* ignore malformed */ }\n return;\n }\n\n // ── Signal message (SDP / ICE) ──\n const signalMatch = topic.match(/\\/room\\/[^/]+\\/signal\\/([^/]+)$/);\n if (signalMatch) {\n try {\n const msg = JSON.parse(raw);\n if (msg.from && msg.from !== this.selfId) {\n for (const cb of this._onSignal) cb(msg.from, msg.data);\n }\n } catch { /* ignore malformed */ }\n return;\n }\n\n // ── Lobby announcement ──\n const lobbyMatch = topic.match(/\\/lobby\\/([^/]+)$/);\n if (lobbyMatch) {\n const roomId = lobbyMatch[1];\n if (!raw) {\n this._lobbyRooms.delete(roomId);\n } else {\n try {\n const ann = JSON.parse(raw) as RoomAnnouncement;\n if (Date.now() - ann.lastSeen < ROOM_ANNOUNCE_EXPIRY_MS) {\n this._lobbyRooms.set(roomId, ann);\n } else {\n this._lobbyRooms.delete(roomId);\n }\n } catch { /* ignore */ }\n }\n const rooms = Array.from(this._lobbyRooms.values());\n for (const cb of this._onLobby) cb(rooms);\n }\n }\n\n private _checkPeerExpiry(): void {\n const now = Date.now();\n for (const [peerId, data] of this._knownPeers) {\n if (now - data.lastSeen > PEER_EXPIRY_MS) {\n this._knownPeers.delete(peerId);\n for (const cb of this._onPeerLeft) cb(peerId);\n }\n }\n }\n\n private _clearRoomTimers(): void {\n if (this._presenceTimer) { clearInterval(this._presenceTimer); this._presenceTimer = null; }\n for (const t of this._warmupTimers) clearTimeout(t);\n this._warmupTimers = [];\n if (this._lobbyAnnounceTimer) { clearInterval(this._lobbyAnnounceTimer); this._lobbyAnnounceTimer = null; }\n if (this._peerExpiryTimer) { clearInterval(this._peerExpiryTimer); this._peerExpiryTimer = null; }\n }\n}\n","import type {\n SignalingStrategy,\n PeerMetadata,\n RoomAnnouncement,\n FirebaseStrategyConfig,\n} from \"./types\";\nimport {\n generatePeerId,\n firebasePaths,\n removeFromArray,\n ROOM_ANNOUNCE_EXPIRY_MS,\n ROOM_ANNOUNCE_INTERVAL_MS,\n} from \"./utils\";\n\n/**\n * Firebase Realtime Database signaling strategy.\n *\n * Requires the `firebase` package as a peer dependency.\n * Pass either a `databaseURL` (auto-creates a namespaced Firebase app)\n * or an existing `firebaseApp` instance.\n *\n * Presence cleanup is automatic via Firebase onDisconnect().\n */\nexport class FirebaseStrategy implements SignalingStrategy {\n readonly selfId: string;\n\n private _appId: string;\n private _config: FirebaseStrategyConfig;\n private _db: any = null;\n private _firebaseApp: any = null;\n private _ownApp = false;\n private _roomId: string | null = null;\n private _peerMeta: PeerMetadata = {};\n /** Monotonic counter to detect stale leaveRoom completions */\n private _joinGeneration = 0;\n\n // Lazy init\n private _initPromise: Promise<void> | null = null;\n\n // Firebase module references (filled after dynamic import)\n private _fb: {\n ref: any;\n set: any;\n push: any;\n remove: any;\n onValue: any;\n onChildAdded: any;\n onChildRemoved: any;\n onDisconnect: any;\n } | null = null;\n\n // Unsubscribe handles for Firebase listeners\n private _listeners: (() => void)[] = [];\n\n // Callbacks\n private _onPeerDiscovered: ((peerId: string, meta: PeerMetadata) => void)[] = [];\n private _onPeerLeft: ((peerId: string) => void)[] = [];\n private _onSignal: ((fromPeerId: string, data: unknown) => void)[] = [];\n private _onLobby: ((rooms: RoomAnnouncement[]) => void)[] = [];\n\n // State\n private _knownPeers = new Set<string>();\n private _lobbyAnnounceTimer: ReturnType<typeof setInterval> | null = null;\n private _lastAnnouncement: RoomAnnouncement | null = null;\n private _lobbyWired = false;\n private _destroyed = false;\n\n constructor(appId: string, config: FirebaseStrategyConfig) {\n this.selfId = generatePeerId();\n this._appId = appId;\n this._config = config;\n }\n\n // ── Public API ──\n\n async init(): Promise<void> {\n return this._ensureInit();\n }\n\n async joinRoom(roomId: string, peerMeta: PeerMetadata): Promise<void> {\n await this._ensureInit();\n if (!this._db || !this._fb) throw new Error('Firebase not initialized');\n\n // Bump generation so any in-flight leaveRoom from a prior call won't\n // null out _roomId after we set it here (React StrictMode race fix).\n this._joinGeneration++;\n\n this._roomId = roomId;\n this._peerMeta = peerMeta;\n const { ref, set, onChildAdded, onChildRemoved, onDisconnect, remove } = this._fb;\n const paths = firebasePaths(this._appId, roomId, this.selfId);\n\n // Clean stale signals from our inbox before listening (prevents\n // replaying SDP from a previous session that wasn't cleaned up).\n await remove(ref(this._db, paths.peerSignalInbox)).catch(() => {});\n\n // 1. Write presence with auto-cleanup on disconnect\n const presenceRef = ref(this._db, paths.peerPresence);\n await set(presenceRef, {\n peerId: this.selfId,\n meta: peerMeta,\n ts: Date.now(),\n });\n onDisconnect(presenceRef).remove();\n\n // 2. Listen for peers joining\n const peersRef = ref(this._db, paths.peers);\n const addedUnsub = onChildAdded(peersRef, (snapshot: any) => {\n const data = snapshot.val();\n if (!data || data.peerId === this.selfId) return;\n if (!this._knownPeers.has(data.peerId)) {\n this._knownPeers.add(data.peerId);\n for (const cb of this._onPeerDiscovered) cb(data.peerId, data.meta ?? {});\n }\n });\n this._listeners.push(() => addedUnsub());\n\n // 3. Listen for peers leaving\n const removedUnsub = onChildRemoved(peersRef, (snapshot: any) => {\n const data = snapshot.val();\n const peerId = data?.peerId ?? snapshot.key;\n if (peerId && this._knownPeers.has(peerId)) {\n this._knownPeers.delete(peerId);\n for (const cb of this._onPeerLeft) cb(peerId);\n }\n });\n this._listeners.push(() => removedUnsub());\n\n // 4. Listen for signals addressed to us\n const signalRef = ref(this._db, paths.peerSignalInbox);\n const signalUnsub = onChildAdded(signalRef, (snapshot: any) => {\n const msg = snapshot.val();\n if (!msg || msg.from === this.selfId) return;\n for (const cb of this._onSignal) cb(msg.from, msg.data);\n // Remove processed signal to keep the inbox clean\n remove(snapshot.ref);\n });\n this._listeners.push(() => signalUnsub());\n }\n\n async leaveRoom(): Promise<void> {\n if (!this._db || !this._fb || !this._roomId) return;\n\n // Capture current state so async cleanup targets the correct room\n // even if joinRoom() is called concurrently (React StrictMode).\n const leavingRoomId = this._roomId;\n const generation = this._joinGeneration;\n\n const { ref, remove } = this._fb;\n const paths = firebasePaths(this._appId, leavingRoomId, this.selfId);\n\n // Detach listeners\n for (const unsub of this._listeners) unsub();\n this._listeners = [];\n\n // Remove presence and signal inbox\n await Promise.all([\n remove(ref(this._db, paths.peerPresence)),\n remove(ref(this._db, paths.peerSignalInbox)),\n ]).catch(() => {});\n\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n\n this._knownPeers.clear();\n\n // Only null out _roomId if no new joinRoom() has run since we started.\n // This prevents the StrictMode race: old leaveRoom completing after\n // new joinRoom already set _roomId to the fresh value.\n if (this._joinGeneration === generation) {\n this._roomId = null;\n }\n }\n\n signal(targetPeerId: string, data: unknown): void {\n if (!this._db || !this._fb || !this._roomId) return;\n const { ref, push } = this._fb;\n\n // Atomic push: single operation writes the key + data together.\n // Avoids the push() + set() two-step that can cause onChildAdded to\n // fire with null if the listener catches the intermediate state.\n const inboxPath = firebasePaths(this._appId, this._roomId, targetPeerId).peerSignalInbox;\n push(ref(this._db, inboxPath), {\n from: this.selfId,\n data: sanitizeForFirebase(data),\n ts: Date.now(),\n });\n }\n\n subscribeToLobby(cb: (rooms: RoomAnnouncement[]) => void): () => void {\n this._onLobby.push(cb);\n\n // Wire the underlying RTDB listener exactly once — repeated subscribe/\n // unsubscribe cycles (React StrictMode, route changes) must not stack\n // duplicate onValue listeners.\n if (this._lobbyWired) {\n return () => {\n removeFromArray(this._onLobby, cb);\n };\n }\n this._lobbyWired = true;\n\n this._ensureInit().then(() => {\n if (!this._db || !this._fb || this._destroyed) return;\n const { ref, onValue } = this._fb;\n const paths = firebasePaths(this._appId, '', '');\n const lobbyRef = ref(this._db, paths.lobby);\n\n const unsub = onValue(lobbyRef, (snapshot: any) => {\n const data = snapshot.val();\n if (!data) {\n for (const lcb of this._onLobby) lcb([]);\n return;\n }\n const now = Date.now();\n const rooms: RoomAnnouncement[] = Object.values(data).filter(\n (r: any) => r && now - (r.lastSeen ?? 0) < ROOM_ANNOUNCE_EXPIRY_MS,\n ) as RoomAnnouncement[];\n for (const lcb of this._onLobby) lcb(rooms);\n });\n this._listeners.push(() => unsub());\n });\n\n return () => {\n removeFromArray(this._onLobby, cb);\n };\n }\n\n announceRoom(announcement: RoomAnnouncement): void {\n if (!this._db || !this._fb) return;\n const { ref, set } = this._fb;\n const paths = firebasePaths(this._appId, announcement.roomId, '');\n\n this._lastAnnouncement = announcement;\n announcement.lastSeen = Date.now();\n set(ref(this._db, paths.roomLobbyEntry), sanitizeForFirebase(announcement));\n\n // Periodic heartbeat\n if (this._lobbyAnnounceTimer) clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = setInterval(() => {\n announcement.lastSeen = Date.now();\n set(ref(this._db, paths.roomLobbyEntry), sanitizeForFirebase(announcement));\n }, ROOM_ANNOUNCE_INTERVAL_MS);\n }\n\n updateRoomOccupancy(roomId: string, playerCount: number, state?: 'lobby' | 'playing' | 'ended'): void {\n const ann = this._lastAnnouncement;\n if (!ann || ann.roomId !== roomId || !this._db || !this._fb) return;\n ann.playerCount = playerCount;\n if (state) ann.state = state;\n ann.lastSeen = Date.now();\n const { ref, set } = this._fb;\n const paths = firebasePaths(this._appId, roomId, '');\n set(ref(this._db, paths.roomLobbyEntry), sanitizeForFirebase(ann));\n }\n\n removeRoomAnnouncement(roomId: string): void {\n if (!this._db || !this._fb) return;\n const { ref, remove } = this._fb;\n remove(ref(this._db, firebasePaths(this._appId, roomId, '').roomLobbyEntry));\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n }\n\n onPeerDiscovered(cb: (peerId: string, meta: PeerMetadata) => void): () => void {\n this._onPeerDiscovered.push(cb);\n return () => { removeFromArray(this._onPeerDiscovered, cb); };\n }\n\n onPeerLeft(cb: (peerId: string) => void): () => void {\n this._onPeerLeft.push(cb);\n return () => { removeFromArray(this._onPeerLeft, cb); };\n }\n\n onSignal(cb: (fromPeerId: string, data: unknown) => void): () => void {\n this._onSignal.push(cb);\n return () => { removeFromArray(this._onSignal, cb); };\n }\n\n destroy(): void {\n this._destroyed = true;\n for (const unsub of this._listeners) unsub();\n this._listeners = [];\n\n if (this._lobbyAnnounceTimer) {\n clearInterval(this._lobbyAnnounceTimer);\n this._lobbyAnnounceTimer = null;\n }\n\n // Best-effort cleanup\n if (this._db && this._fb && this._roomId) {\n const { ref, remove } = this._fb;\n const paths = firebasePaths(this._appId, this._roomId, this.selfId);\n remove(ref(this._db, paths.peerPresence)).catch(() => {});\n remove(ref(this._db, paths.peerSignalInbox)).catch(() => {});\n }\n\n // Delete own Firebase app if we created it\n if (this._ownApp && this._firebaseApp) {\n import('firebase/app').then(({ deleteApp }) => {\n deleteApp(this._firebaseApp).catch(() => {});\n });\n }\n\n this._db = null;\n this._firebaseApp = null;\n this._fb = null;\n this._knownPeers.clear();\n this._onPeerDiscovered = [];\n this._onPeerLeft = [];\n this._onSignal = [];\n this._onLobby = [];\n }\n\n // ── Private ──\n\n private _ensureInit(): Promise<void> {\n if (!this._initPromise) {\n this._initPromise = this._doInit();\n }\n return this._initPromise;\n }\n\n private async _doInit(): Promise<void> {\n const { initializeApp, getApps } = await import('firebase/app');\n const {\n getDatabase,\n ref,\n set,\n push,\n remove,\n onValue,\n onChildAdded,\n onChildRemoved,\n onDisconnect,\n } = await import('firebase/database');\n\n this._fb = { ref, set, push, remove, onValue, onChildAdded, onChildRemoved, onDisconnect };\n\n if (this._config.firebaseApp) {\n this._firebaseApp = this._config.firebaseApp;\n this._ownApp = false;\n } else {\n const appName = `carver_${this._appId}`;\n const existing = getApps().find((a: any) => a.name === appName);\n if (existing) {\n this._firebaseApp = existing;\n this._ownApp = false;\n } else {\n this._firebaseApp = initializeApp({ databaseURL: this._config.databaseURL }, appName);\n this._ownApp = true;\n }\n }\n\n this._db = getDatabase(this._firebaseApp);\n }\n}\n\n/**\n * Firebase RTDB deletes any key whose value is `null` (treats null as \"remove\").\n * ICE candidates from `toJSON()` can contain `null` fields (e.g. usernameFragment).\n * We recursively replace `null` with a sentinel so Firebase preserves the key.\n * On the receiving end, `_handleSignal` doesn't need to reverse this because\n * `new RTCIceCandidate()` / `new RTCSessionDescription()` accept missing fields.\n */\nfunction sanitizeForFirebase(obj: unknown): unknown {\n if (obj === null) return '__null__';\n if (Array.isArray(obj)) return obj.map(sanitizeForFirebase);\n if (typeof obj === 'object' && obj !== null) {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (value === undefined) continue; // RTDB rejects undefined anywhere in the payload\n result[key] = value === null ? '__null__' : sanitizeForFirebase(value);\n }\n return result;\n }\n return obj;\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","/** Default STUN servers (free, public) */\nconst DEFAULT_STUN_SERVERS: RTCIceServer[] = [\n { urls: 'stun:stun.l.google.com:19302' },\n { urls: 'stun:stun1.l.google.com:19302' },\n { urls: 'stun:stun2.l.google.com:19302' },\n { urls: 'stun:stun.cloudflare.com:3478' },\n];\n\n/**\n * Build RTCConfiguration from user-provided ICE servers.\n *\n * If the user provides `iceServers`, those are used as-is (STUN + TURN).\n * Otherwise, default public STUN servers are used.\n *\n * TURN servers should be included in the `iceServers` array by the user:\n * ```ts\n * iceServers: [\n * { urls: 'stun:stun.cloudflare.com:3478' },\n * { urls: 'turn:turn.cloudflare.com:3478', username: '...', credential: '...' },\n * ]\n * ```\n */\nexport function buildICEConfig(options?: {\n iceServers?: RTCIceServer[];\n iceTransportPolicy?: RTCIceTransportPolicy;\n}): RTCConfiguration {\n const servers: RTCIceServer[] =\n options?.iceServers && options.iceServers.length > 0\n ? options.iceServers\n : DEFAULT_STUN_SERVERS;\n\n return {\n iceServers: servers,\n iceCandidatePoolSize: 10,\n iceTransportPolicy: options?.iceTransportPolicy ?? 'all',\n };\n}\n","import type { ChannelOptions } from \"../../types\";\nimport type { PeerState } from \"../types\";\n\nexport interface PeerConnectionEvents {\n onStateChange: (state: PeerState) => void;\n onDataChannel: (channel: RTCDataChannel) => void;\n onIceCandidate: (candidate: RTCIceCandidate) => void;\n}\n\n/**\n * Manages a single RTCPeerConnection to one remote peer.\n *\n * ICE candidates that arrive before the remote description is set are\n * buffered and flushed automatically once setRemoteDescription completes.\n * This is critical for Firebase/MQTT signaling where offer, answer, and\n * candidates can arrive nearly simultaneously.\n */\nexport class PeerConnection {\n readonly peerId: string;\n private _connection: RTCPeerConnection;\n private _channels = new Map<string, RTCDataChannel>();\n private _events: PeerConnectionEvents;\n private _state: PeerState = 'connecting';\n private _remoteDescriptionSet = false;\n private _pendingCandidates: RTCIceCandidateInit[] = [];\n\n constructor(\n peerId: string,\n config: RTCConfiguration,\n events: PeerConnectionEvents,\n ) {\n this.peerId = peerId;\n this._events = events;\n this._connection = new RTCPeerConnection(config);\n\n this._connection.onicecandidate = (e) => {\n if (e.candidate) {\n this._events.onIceCandidate(e.candidate);\n }\n };\n\n this._connection.oniceconnectionstatechange = () => {\n this._updateState();\n };\n\n this._connection.onconnectionstatechange = () => {\n this._updateState();\n };\n\n this._connection.ondatachannel = (e) => {\n const channel = e.channel;\n this._channels.set(channel.label, channel);\n this._events.onDataChannel(channel);\n };\n }\n\n get state(): PeerState {\n return this._state;\n }\n\n get connection(): RTCPeerConnection {\n return this._connection;\n }\n\n private _updateState(): void {\n const iceState = this._connection.iceConnectionState;\n const connState = this._connection.connectionState;\n\n let newState: PeerState;\n if (connState === 'connected' || iceState === 'connected') {\n newState = 'connected';\n } else if (connState === 'failed' || iceState === 'failed') {\n newState = 'failed';\n } else if (connState === 'closed' || iceState === 'closed' || iceState === 'disconnected') {\n newState = 'disconnected';\n } else {\n newState = 'connecting';\n }\n\n if (newState !== this._state) {\n this._state = newState;\n this._events.onStateChange(newState);\n }\n }\n\n async createOffer(): Promise<RTCSessionDescriptionInit> {\n const offer = await this._connection.createOffer();\n await this._connection.setLocalDescription(offer);\n return offer;\n }\n\n async handleOffer(offer: RTCSessionDescriptionInit): Promise<RTCSessionDescriptionInit> {\n await this._connection.setRemoteDescription(new RTCSessionDescription(offer));\n this._remoteDescriptionSet = true;\n await this._flushPendingCandidates();\n const answer = await this._connection.createAnswer();\n await this._connection.setLocalDescription(answer);\n return answer;\n }\n\n async handleAnswer(answer: RTCSessionDescriptionInit): Promise<void> {\n await this._connection.setRemoteDescription(new RTCSessionDescription(answer));\n this._remoteDescriptionSet = true;\n await this._flushPendingCandidates();\n }\n\n async addIceCandidate(candidate: RTCIceCandidateInit): Promise<void> {\n if (!this._remoteDescriptionSet) {\n // Buffer until remote description is set -- prevents silent drops\n this._pendingCandidates.push(candidate);\n return;\n }\n try {\n await this._connection.addIceCandidate(new RTCIceCandidate(candidate));\n } catch {\n // Ignore ICE candidate errors (can happen during race conditions)\n }\n }\n\n private async _flushPendingCandidates(): Promise<void> {\n const candidates = this._pendingCandidates;\n this._pendingCandidates = [];\n for (const c of candidates) {\n try {\n await this._connection.addIceCandidate(new RTCIceCandidate(c));\n } catch {\n // Ignore errors on individual candidates\n }\n }\n }\n\n createDataChannel(name: string, options?: ChannelOptions): RTCDataChannel {\n // If a channel with this label already exists (e.g. received via\n // ondatachannel from the remote peer), reuse it instead of creating\n // a duplicate that fragments send/receive across two channels.\n const existing = this._channels.get(name);\n if (existing && existing.readyState !== 'closed') {\n return existing;\n }\n\n const dcOptions: RTCDataChannelInit = {};\n if (options?.reliable === false) {\n dcOptions.ordered = options?.ordered ?? false;\n dcOptions.maxRetransmits = options?.maxRetransmits ?? 0;\n } else {\n dcOptions.ordered = options?.ordered ?? true;\n }\n const channel = this._connection.createDataChannel(name, dcOptions);\n this._channels.set(name, channel);\n return channel;\n }\n\n getDataChannel(name: string): RTCDataChannel | undefined {\n return this._channels.get(name);\n }\n\n close(): void {\n for (const channel of this._channels.values()) {\n try { channel.close(); } catch { /* ignore */ }\n }\n this._channels.clear();\n this._pendingCandidates = [];\n this._remoteDescriptionSet = false;\n try { this._connection.close(); } catch { /* ignore */ }\n this._state = 'disconnected';\n }\n}\n","import type {\n CarverTransport,\n CarverChannel,\n ChannelOptions,\n TransportConfig,\n Player,\n Room,\n RoomState,\n} from \"../../types\";\nimport type { TransportCallbacks, RateLimitConfig } from \"../types\";\nimport type { SignalingStrategy, PeerMetadata } from \"../strategy/types\";\nimport { buildICEConfig } from \"./ice\";\nimport { PeerConnection } from \"./peer\";\n\nconst ROOM_CONTROL_CHANNEL = 'carver:room-control';\n\ninterface ChannelState<T> {\n name: string;\n options: ChannelOptions;\n receivers: ((data: T, peerId: string) => void)[];\n}\n\n/** Room control messages exchanged over the room-control data channel */\ntype RoomControlMessage =\n | { type: 'player-updated'; player: Player }\n | { type: 'room-updated'; room: Partial<Room> }\n | { type: 'kick'; peerId: string; reason?: string }\n | { type: 'host-changed'; newHostId: string }\n | { type: 'request-ready'; ready: boolean }\n | { type: 'request-metadata'; metadata: Record<string, unknown> }\n | { type: 'request-room-metadata'; metadata: Record<string, unknown> }\n | { type: 'request-room-state'; state: RoomState }\n | { type: 'request-max-players'; maxPlayers: number }\n | { type: 'request-lock' }\n | { type: 'request-unlock' }\n | { type: 'request-transfer-host'; peerId: string }\n | { type: 'sync-state'; room: Room; players: Player[] };\n\n/** Deterministic host election: lowest peerId alphabetically */\nfunction electHost(peerIds: string[]): string {\n return [...peerIds].sort()[0];\n}\n\n/**\n * Implements CarverTransport using WebRTC data channels for game data\n * and a pluggable SignalingStrategy for peer discovery + SDP/ICE relay.\n *\n * No WebSocket server required. The strategy handles signaling through\n * MQTT brokers, Firebase RTDB, or any other network.\n */\nexport class WebRTCTransport implements CarverTransport {\n private _strategy: SignalingStrategy;\n private _peers = new Map<string, PeerConnection>();\n private _peerSet = new Set<string>();\n private _peerId: string;\n private _hostId = '';\n private _isHost = false;\n private _callbacks: TransportCallbacks = {\n onPeerJoin: [],\n onPeerLeave: [],\n onPeerUpdated: [],\n onHostChanged: [],\n };\n private _roomUpdatedCallbacks: ((room: Room) => void)[] = [];\n private _channels = new Map<string, ChannelState<any>>();\n private _iceConfig: RTCConfiguration;\n private _rateLimitConfig: RateLimitConfig = { maxMessagesPerSecond: 60, windowMs: 1000 };\n private _rateLimitCounters = new Map<string, { count: number; resetAt: number }>();\n private _connected = false;\n private _room: Room | null = null;\n private _playerMap = new Map<string, Player>();\n private _initialPeers: Player[] = [];\n private _strategyUnsubs: (() => void)[] = [];\n\n /**\n * @param strategy Shared SignalingStrategy instance (managed by MultiplayerProvider)\n * @param iceServers Optional ICE servers (STUN + TURN). Defaults to public STUN.\n * @param iceTransportPolicy 'all' (default) or 'relay' (force TURN only).\n */\n constructor(\n strategy: SignalingStrategy,\n iceServers?: RTCIceServer[],\n iceTransportPolicy?: RTCIceTransportPolicy,\n ) {\n this._strategy = strategy;\n this._peerId = strategy.selfId;\n this._iceConfig = buildICEConfig({ iceServers, iceTransportPolicy });\n }\n\n // ── CarverTransport getters ──\n\n get peerId(): string { return this._peerId; }\n get peers(): ReadonlySet<string> { return this._peerSet; }\n get hostId(): string { return this._hostId; }\n get isHost(): boolean { return this._isHost; }\n get room(): Room | undefined { return this._room ?? undefined; }\n get initialPlayers(): Player[] { return this._initialPeers; }\n\n // ── Event registration ──\n\n onPeerJoin(cb: (peerId: string) => void): void { this._callbacks.onPeerJoin.push(cb); }\n onPeerLeave(cb: (peerId: string) => void): void { this._callbacks.onPeerLeave.push(cb); }\n onPeerUpdated(cb: (player: Player) => void): void { this._callbacks.onPeerUpdated.push(cb); }\n onRoomUpdated(cb: (room: Room) => void): void { this._roomUpdatedCallbacks.push(cb); }\n onHostChanged(cb: (newHostId: string) => void): void { this._callbacks.onHostChanged.push(cb); }\n\n // ── Channel management ──\n\n createChannel<T>(name: string, options?: ChannelOptions): CarverChannel<T> {\n // Idempotent: return existing channel if already created\n const existing = this._channels.get(name);\n if (existing) {\n return {\n send: (data: T, target?: string | string[]) => this._sendOnChannel(name, data, target),\n onReceive: (cb: (data: T, peerId: string) => void) => { existing.receivers.push(cb); },\n close: () => { this._channels.delete(name); },\n };\n }\n\n const state: ChannelState<T> = {\n name,\n options: options ?? { reliable: true, ordered: true },\n receivers: [],\n };\n this._channels.set(name, state);\n\n // Create data channels on existing peers if already connected\n if (this._connected) {\n for (const peer of this._peers.values()) {\n this._createDataChannelOnPeer(peer, name, state.options);\n }\n }\n\n return {\n send: (data: T, target?: string | string[]) => this._sendOnChannel(name, data, target),\n onReceive: (cb: (data: T, peerId: string) => void) => { state.receivers.push(cb); },\n close: () => { this._channels.delete(name); },\n };\n }\n\n // ── Connect / Disconnect ──\n\n async connect(roomId: string, config?: TransportConfig): Promise<void> {\n // Override ICE config if user passed custom servers\n if (config?.iceServers) {\n this._iceConfig = buildICEConfig({\n iceServers: config.iceServers,\n iceTransportPolicy: config.iceTransportPolicy,\n });\n }\n\n // Pre-register ALL standard channels so the initiator includes them\n // in the initial WebRTC offer. Channels created after the peer connection\n // is established won't get a proper data channel on the remote side.\n this._setupRoomControlChannel();\n this._preRegisterChannel('carver:events', { reliable: true, ordered: true });\n this._preRegisterChannel('carver:snapshots', { reliable: false, ordered: false });\n this._preRegisterChannel('carver:acks', { reliable: true, ordered: true });\n this._preRegisterChannel('carver:inputs', { reliable: true, ordered: true });\n this._preRegisterChannel('carver:network-state', { reliable: true, ordered: true });\n\n // Bind strategy callbacks (store unsubs for cleanup)\n this._strategyUnsubs.push(\n this._strategy.onPeerDiscovered((peerId, meta) => {\n this._onStrategyPeerDiscovered(peerId, meta);\n }),\n );\n this._strategyUnsubs.push(\n this._strategy.onPeerLeft((peerId) => {\n this._removePeer(peerId);\n this._playerMap.delete(peerId);\n this._electAndSetHost();\n for (const cb of this._callbacks.onPeerLeave) cb(peerId);\n }),\n );\n this._strategyUnsubs.push(\n this._strategy.onSignal((fromPeerId, data) => {\n this._handleSignal(fromPeerId, data);\n }),\n );\n\n // Join room via strategy (publishes presence, subscribes to room)\n await this._strategy.joinRoom(roomId, {\n displayName: config?.displayName,\n ...(config?.playerMetadata ?? {}),\n });\n\n // Create self Player\n const selfPlayer: Player = {\n peerId: this._peerId,\n displayName: config?.displayName ?? `Player-${this._peerId.slice(0, 4)}`,\n isHost: false,\n isSelf: true,\n isReady: false,\n isConnected: true,\n metadata: config?.playerMetadata ?? {},\n latencyMs: 0,\n joinedAt: Date.now(),\n };\n this._playerMap.set(this._peerId, selfPlayer);\n\n // Elect host (may just be us if we're the first in the room)\n this._electAndSetHost();\n\n // Create initial Room object\n this._room = {\n id: roomId,\n name: roomId,\n hostId: this._hostId,\n playerCount: this._playerMap.size,\n maxPlayers: config?.maxPlayers ?? 8,\n isPrivate: false,\n metadata: {},\n createdAt: Date.now(),\n state: 'lobby',\n };\n\n this._initialPeers = Array.from(this._playerMap.values());\n this._connected = true;\n }\n\n disconnect(): void {\n this._connected = false;\n\n // Unsubscribe from strategy callbacks\n for (const unsub of this._strategyUnsubs) unsub();\n this._strategyUnsubs = [];\n\n // Close all peer connections\n for (const peer of this._peers.values()) peer.close();\n this._peers.clear();\n this._peerSet.clear();\n this._channels.clear();\n this._rateLimitCounters.clear();\n this._playerMap.clear();\n\n // Leave room via strategy (don't destroy -- provider manages lifecycle)\n this._strategy.leaveRoom().catch(() => {});\n\n this._hostId = '';\n this._isHost = false;\n this._room = null;\n }\n\n /** Expose strategy for lobby hooks */\n get strategy(): SignalingStrategy { return this._strategy; }\n\n // ── Channel pre-registration ──\n\n /**\n * Register a channel name and options without creating data channels yet.\n * When _connectToPeer runs, it iterates this._channels and creates data\n * channels for every registered name in the initial WebRTC offer.\n * Later, when EventSync/SnapshotSync call createChannel(), the idempotent\n * check returns the pre-registered entry and they just attach receivers.\n */\n private _preRegisterChannel(name: string, options: ChannelOptions): void {\n if (this._channels.has(name)) return;\n this._channels.set(name, { name, options, receivers: [] });\n }\n\n // ── Room management (over WebRTC data channels) ──\n\n setReady(ready: boolean): void {\n this._sendControlMessage({ type: 'request-ready', ready });\n }\n\n setMetadata(metadata: Record<string, unknown>): void {\n this._sendControlMessage({ type: 'request-metadata', metadata });\n }\n\n setRoomMetadata(metadata: Record<string, unknown>): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-room-metadata', metadata });\n }\n\n kick(peerId: string, reason?: string): void {\n if (!this._isHost) return;\n // Broadcast kick so the target peer and everyone else knows\n this._broadcastControlMessage({ type: 'kick', peerId, reason });\n }\n\n transferHost(peerId: string): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-transfer-host', peerId });\n }\n\n setRoomState(state: RoomState): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-room-state', state });\n }\n\n setMaxPlayers(n: number): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-max-players', maxPlayers: n });\n }\n\n lockRoom(): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-lock' });\n }\n\n unlockRoom(): void {\n if (!this._isHost) return;\n this._sendControlMessage({ type: 'request-unlock' });\n }\n\n /** No-op: lobby uses strategy.subscribeToLobby() directly */\n requestRoomList(): void {}\n\n // ── Private: Strategy callbacks ──\n\n private _onStrategyPeerDiscovered(peerId: string, meta: PeerMetadata): void {\n this._connectToPeer(peerId);\n this._peerSet.add(peerId);\n\n const player: Player = {\n peerId,\n displayName: (meta.displayName as string) ?? `Player-${peerId.slice(0, 4)}`,\n isHost: false,\n isSelf: false,\n isReady: false,\n isConnected: true,\n metadata: meta as Record<string, unknown>,\n latencyMs: 0,\n joinedAt: Date.now(),\n };\n this._playerMap.set(peerId, player);\n this._electAndSetHost();\n\n for (const cb of this._callbacks.onPeerJoin) cb(peerId);\n for (const cb of this._callbacks.onPeerUpdated) cb(player);\n }\n\n // ── Private: Room control channel ──\n\n private _setupRoomControlChannel(): void {\n const ch = this.createChannel<RoomControlMessage>(ROOM_CONTROL_CHANNEL, {\n reliable: true,\n ordered: true,\n });\n ch.onReceive((msg, peerId) => {\n this._handleControlMessage(msg, peerId);\n });\n }\n\n private _handleControlMessage(msg: RoomControlMessage, fromPeerId: string): void {\n switch (msg.type) {\n case 'player-updated': {\n this._playerMap.set(msg.player.peerId, msg.player);\n for (const cb of this._callbacks.onPeerUpdated) cb(msg.player);\n break;\n }\n case 'room-updated': {\n if (this._room) {\n Object.assign(this._room, msg.room);\n for (const cb of this._roomUpdatedCallbacks) cb(this._room);\n }\n break;\n }\n case 'kick': {\n if (msg.peerId === this._peerId) {\n // We were kicked\n this.disconnect();\n }\n break;\n }\n case 'host-changed': {\n this._hostId = msg.newHostId;\n this._isHost = msg.newHostId === this._peerId;\n for (const cb of this._callbacks.onHostChanged) cb(msg.newHostId);\n break;\n }\n case 'sync-state': {\n // Full state sync from host (sent to newly connected peers)\n this._room = msg.room;\n for (const p of msg.players) {\n this._playerMap.set(p.peerId, { ...p, isSelf: p.peerId === this._peerId });\n for (const cb of this._callbacks.onPeerUpdated) cb(p);\n }\n for (const cb of this._roomUpdatedCallbacks) cb(msg.room);\n break;\n }\n\n // Host processes requests from peers\n case 'request-ready': {\n if (!this._isHost) break;\n const p = this._playerMap.get(fromPeerId);\n if (p) {\n p.isReady = msg.ready;\n this._broadcastControlMessage({ type: 'player-updated', player: p });\n }\n break;\n }\n case 'request-metadata': {\n if (!this._isHost) break;\n const pm = this._playerMap.get(fromPeerId);\n if (pm) {\n pm.metadata = { ...pm.metadata, ...msg.metadata };\n this._broadcastControlMessage({ type: 'player-updated', player: pm });\n }\n break;\n }\n case 'request-room-metadata': {\n if (!this._isHost || !this._room) break;\n this._room.metadata = { ...this._room.metadata, ...msg.metadata };\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-room-state': {\n if (!this._isHost || !this._room) break;\n this._room.state = msg.state;\n this._strategy.updateRoomOccupancy?.(this._room.id, this._room.playerCount, this._room.state);\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-max-players': {\n if (!this._isHost || !this._room) break;\n this._room.maxPlayers = msg.maxPlayers;\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-lock': {\n if (!this._isHost || !this._room) break;\n (this._room as any).locked = true;\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-unlock': {\n if (!this._isHost || !this._room) break;\n (this._room as any).locked = false;\n this._broadcastControlMessage({ type: 'room-updated', room: this._room });\n break;\n }\n case 'request-transfer-host': {\n if (!this._isHost) break;\n this._hostId = msg.peerId;\n this._isHost = false;\n this._broadcastControlMessage({ type: 'host-changed', newHostId: msg.peerId });\n break;\n }\n }\n }\n\n private _sendControlMessage(msg: RoomControlMessage): void {\n if (this._isHost && msg.type.startsWith('request-')) {\n // Host processes locally and broadcasts result\n this._handleControlMessage(msg, this._peerId);\n return;\n }\n // Non-host: send to host\n if (this._hostId && this._hostId !== this._peerId) {\n this._sendOnChannel(ROOM_CONTROL_CHANNEL, msg, this._hostId);\n }\n }\n\n private _broadcastControlMessage(msg: RoomControlMessage): void {\n this._sendOnChannel(ROOM_CONTROL_CHANNEL, msg);\n // Handle locally too so host updates its own state\n this._handleControlMessage(msg, this._peerId);\n }\n\n // ── Private: Host election ──\n\n private _electAndSetHost(): void {\n const allIds = [this._peerId, ...this._peerSet];\n const newHostId = electHost(allIds);\n const changed = newHostId !== this._hostId;\n this._hostId = newHostId;\n this._isHost = newHostId === this._peerId;\n\n for (const [id, p] of this._playerMap) {\n p.isHost = id === newHostId;\n }\n if (this._room) {\n this._room.hostId = newHostId;\n this._room.playerCount = this._playerMap.size;\n // Keep the lobby announcement's occupancy fresh (no-op on non-announcers)\n this._strategy.updateRoomOccupancy?.(this._room.id, this._room.playerCount, this._room.state);\n }\n\n if (changed) {\n for (const cb of this._callbacks.onHostChanged) cb(newHostId);\n }\n }\n\n // ── Private: WebRTC peer management ──\n\n /** Grace timers for transient ICE 'disconnected' states */\n private _disconnectTimers = new Map<string, ReturnType<typeof setTimeout>>();\n /** Sends queued while a data channel is not yet open: key = peerId\u0000channel */\n private _pendingSends = new Map<string, (string | ArrayBuffer | Uint8Array)[]>();\n\n private _connectToPeer(peerId: string): void {\n if (this._peers.has(peerId)) return;\n\n const peer = new PeerConnection(peerId, this._iceConfig, {\n onStateChange: (state) => {\n if (state === 'connected') {\n // ICE recovered — cancel any pending transient-disconnect teardown\n const timer = this._disconnectTimers.get(peerId);\n if (timer) {\n clearTimeout(timer);\n this._disconnectTimers.delete(peerId);\n }\n }\n if (state === 'connected' && this._isHost && this._room) {\n // Send full state sync to the new peer\n const syncMsg: RoomControlMessage = {\n type: 'sync-state',\n room: this._room,\n players: Array.from(this._playerMap.values()),\n };\n setTimeout(() => {\n this._sendOnChannel(ROOM_CONTROL_CHANNEL, syncMsg, peerId);\n }, 100);\n }\n if (state === 'failed') {\n this._teardownPeer(peerId);\n } else if (state === 'disconnected' && !this._disconnectTimers.has(peerId)) {\n // ICE 'disconnected' is frequently transient. Tearing down\n // instantly left half-alive sessions (old closures kept\n // receiving while sends routed to a replacement connection).\n // Grace period: only tear down if it doesn't recover.\n this._disconnectTimers.set(peerId, setTimeout(() => {\n this._disconnectTimers.delete(peerId);\n const p = this._peers.get(peerId);\n if (p && p.state !== 'connected') this._teardownPeer(peerId);\n }, 5000));\n }\n },\n onDataChannel: (channel) => {\n this._setupDataChannelReceiver(channel, peerId);\n },\n onIceCandidate: (candidate) => {\n this._strategy.signal(peerId, { type: 'ice-candidate', candidate: candidate.toJSON() });\n },\n });\n\n this._peers.set(peerId, peer);\n this._peerSet.add(peerId);\n\n // Deterministic initiator: lower peerId creates the offer\n if (this._peerId < peerId) {\n for (const [name, state] of this._channels) {\n this._createDataChannelOnPeer(peer, name, state.options);\n }\n peer.createOffer().then((offer) => {\n this._strategy.signal(peerId, { type: 'offer', sdp: offer });\n });\n }\n }\n\n private async _handleSignal(peerId: string, data: unknown): Promise<void> {\n try {\n const signal = data as {\n type: string;\n sdp?: RTCSessionDescriptionInit;\n candidate?: RTCIceCandidateInit;\n };\n\n let peer = this._peers.get(peerId);\n\n if (signal.type === 'offer') {\n if (!peer) {\n this._connectToPeer(peerId);\n peer = this._peers.get(peerId)!;\n }\n const answer = await peer.handleOffer(signal.sdp!);\n this._strategy.signal(peerId, { type: 'answer', sdp: answer });\n } else if (signal.type === 'answer' && peer) {\n await peer.handleAnswer(signal.sdp!);\n } else if (signal.type === 'ice-candidate' && peer) {\n await peer.addIceCandidate(signal.candidate!);\n }\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.error('[CarverJS] Signal handling failed:', err);\n }\n }\n }\n\n // ── Private: Data channel helpers ──\n\n private _createDataChannelOnPeer(peer: PeerConnection, name: string, options: ChannelOptions): void {\n const channel = peer.createDataChannel(name, options);\n this._setupDataChannelReceiver(channel, peer.peerId);\n }\n\n private _setupDataChannelReceiver(dataChannel: RTCDataChannel, peerId: string): void {\n const channelName = dataChannel.label;\n dataChannel.onmessage = (event) => {\n if (!this._checkRateLimit(peerId)) return;\n const channelState = this._channels.get(channelName);\n if (!channelState) return;\n try {\n const data =\n typeof event.data === 'string' ? JSON.parse(event.data) : event.data;\n for (const receiver of channelState.receivers) receiver(data, peerId);\n } catch {\n // Ignore malformed messages\n }\n };\n // Flush any sends that were queued before this channel was usable\n dataChannel.onopen = () => this._flushPendingSends(peerId, channelName);\n if (dataChannel.readyState === 'open') this._flushPendingSends(peerId, channelName);\n }\n\n private _sendOnChannel<T>(channelName: string, data: T, target?: string | string[]): void {\n const serialized =\n typeof data === 'object' &&\n data !== null &&\n !(data instanceof ArrayBuffer) &&\n !(data instanceof Uint8Array)\n ? JSON.stringify(data)\n : data;\n\n const targets = target\n ? Array.isArray(target) ? target : [target]\n : Array.from(this._peers.keys());\n\n for (const pid of targets) {\n const peer = this._peers.get(pid);\n if (!peer) continue;\n const ch = peer.getDataChannel(channelName);\n if (ch?.readyState === 'open') {\n try { ch.send(serialized as string); } catch { /* closed between check and send */ }\n } else {\n // Channel not open yet (the answering side waits for ondatachannel).\n // Queue instead of silently dropping — flushed on channel open.\n const key = pid + '\u0000' + channelName;\n const q = this._pendingSends.get(key) ?? [];\n if (q.length < 200) q.push(serialized as string | ArrayBuffer | Uint8Array);\n this._pendingSends.set(key, q);\n }\n }\n }\n\n private _flushPendingSends(peerId: string, channelName: string): void {\n const key = peerId + '\u0000' + channelName;\n const q = this._pendingSends.get(key);\n if (!q || q.length === 0) return;\n const ch = this._peers.get(peerId)?.getDataChannel(channelName);\n if (ch?.readyState !== 'open') return;\n this._pendingSends.delete(key);\n for (const msg of q) {\n try { ch.send(msg as string); } catch { break; }\n }\n }\n\n private _teardownPeer(peerId: string): void {\n this._removePeer(peerId);\n this._playerMap.delete(peerId);\n this._electAndSetHost();\n for (const cb of this._callbacks.onPeerLeave) cb(peerId);\n }\n\n private _removePeer(peerId: string): void {\n const peer = this._peers.get(peerId);\n if (peer) { peer.close(); this._peers.delete(peerId); }\n this._peerSet.delete(peerId);\n this._rateLimitCounters.delete(peerId);\n const timer = this._disconnectTimers.get(peerId);\n if (timer) { clearTimeout(timer); this._disconnectTimers.delete(peerId); }\n for (const key of [...this._pendingSends.keys()]) {\n if (key.startsWith(peerId + '\u0000')) this._pendingSends.delete(key);\n }\n }\n\n private _checkRateLimit(peerId: string): boolean {\n const now = Date.now();\n let c = this._rateLimitCounters.get(peerId);\n if (!c || now >= c.resetAt) {\n c = { count: 0, resetAt: now + this._rateLimitConfig.windowMs };\n this._rateLimitCounters.set(peerId, c);\n }\n c.count++;\n return c.count <= this._rateLimitConfig.maxMessagesPerSecond;\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","import type { CarverTransport, CarverChannel, EventPacket } from \"../types\";\n\n/**\n * Layer 1: Event-based messaging over a reliable+ordered channel.\n * Used for turn-based games, chat, and infrequent state changes.\n */\nexport class EventSync {\n private _transport: CarverTransport;\n private _channel: CarverChannel<string>;\n private _handlers = new Map<string, ((payload: unknown, peerId: string) => void)[]>();\n private _hostValidation: boolean;\n\n constructor(transport: CarverTransport, options?: { hostValidation?: boolean }) {\n this._transport = transport;\n this._hostValidation = options?.hostValidation ?? false;\n\n // Create a single reliable+ordered channel for events\n this._channel = transport.createChannel<string>('carver:events', {\n reliable: true,\n ordered: true,\n });\n\n // Listen for incoming events\n this._channel.onReceive((rawData: string, peerId: string) => {\n try {\n const packet: EventPacket = typeof rawData === 'string' ? JSON.parse(rawData) : rawData as unknown as EventPacket;\n\n // If host validation is enabled and we're the host, rebroadcast\n if (this._hostValidation && this._transport.isHost && packet.sender !== this._transport.peerId) {\n // Rebroadcast to all peers (except the original sender)\n const targets = Array.from(this._transport.peers).filter(p => p !== peerId);\n if (targets.length > 0) {\n this._channel.send(JSON.stringify(packet), targets);\n }\n }\n\n // If host validation is enabled and we're NOT the host,\n // only accept events from host (who rebroadcasts validated events)\n if (this._hostValidation && !this._transport.isHost && peerId !== this._transport.hostId) {\n return;\n }\n\n // Fire handlers for this event type\n const handlers = this._handlers.get(packet.type);\n if (handlers) {\n for (const handler of handlers) {\n handler(packet.payload, packet.sender);\n }\n }\n } catch {\n // Ignore malformed events\n }\n });\n }\n\n /**\n * Send a typed event to a specific peer or all peers.\n */\n sendEvent(type: string, payload: unknown, target?: string): void {\n const packet: EventPacket = {\n type,\n payload,\n sender: this._transport.peerId,\n target,\n };\n const serialized = JSON.stringify(packet);\n\n if (this._hostValidation && !this._transport.isHost) {\n // Route through host for validation\n this._channel.send(serialized, this._transport.hostId);\n } else if (target) {\n this._channel.send(serialized, target);\n } else {\n // Broadcast to all peers\n this._channel.send(serialized);\n }\n }\n\n /**\n * Broadcast a typed event to all connected peers.\n */\n broadcast(type: string, payload: unknown): void {\n this.sendEvent(type, payload);\n }\n\n /**\n * Register a handler for a specific event type.\n * Returns an unsubscribe function.\n */\n onEvent(type: string, callback: (payload: unknown, peerId: string) => void): () => void {\n let handlers = this._handlers.get(type);\n if (!handlers) {\n handlers = [];\n this._handlers.set(type, handlers);\n }\n handlers.push(callback);\n\n return () => {\n const arr = this._handlers.get(type);\n if (arr) {\n const idx = arr.indexOf(callback);\n if (idx >= 0) arr.splice(idx, 1);\n if (arr.length === 0) this._handlers.delete(type);\n }\n };\n }\n\n /**\n * Clean up the event channel.\n */\n destroy(): void {\n this._channel.close();\n this._handlers.clear();\n }\n}\n","import type {\n CarverTransport,\n CarverChannel,\n EntityState,\n PlayerInput,\n} from \"../types\";\nimport { Codec, SnapshotBuffer } from \"./codec\";\n\n/**\n * Host-side authority: reads networked actor states, serializes with delta compression,\n * and broadcasts to all clients at the configured broadcast rate.\n */\nexport class HostAuthority {\n private _transport: CarverTransport;\n private _codec: Codec;\n private _snapshotBuffer: SnapshotBuffer;\n private _snapshotChannel: CarverChannel<Uint8Array>;\n private _ackChannel: CarverChannel<string>;\n private _tick = 0;\n private _broadcastRate: number;\n private _broadcastAccumulator = 0;\n private _keyframeInterval: number;\n\n // Per-client last ACK'd tick for delta compression\n private _clientBaselines = new Map<string, number>();\n // Per-client last keyframe tick for scheduling\n private _clientLastKeyframeTick = new Map<string, number>();\n\n // Interest management callback (optional)\n private _interestFilter:\n | ((entityId: string, peerId: string) => boolean)\n | null = null;\n\n constructor(\n transport: CarverTransport,\n codec: Codec,\n snapshotBuffer: SnapshotBuffer,\n options?: {\n broadcastRate?: number;\n keyframeInterval?: number;\n },\n ) {\n this._transport = transport;\n this._codec = codec;\n this._snapshotBuffer = snapshotBuffer;\n this._broadcastRate = options?.broadcastRate ?? 20;\n this._keyframeInterval = options?.keyframeInterval ?? 300;\n\n // Unreliable channel for snapshots (fast, may drop)\n this._snapshotChannel = transport.createChannel<Uint8Array>(\n \"carver:snapshots\",\n {\n reliable: false,\n ordered: false,\n maxRetransmits: 0,\n },\n );\n\n // Reliable channel for ACKs\n this._ackChannel = transport.createChannel<string>(\"carver:acks\", {\n reliable: true,\n ordered: true,\n });\n\n // Listen for client ACKs\n this._ackChannel.onReceive((data: string, peerId: string) => {\n try {\n const ackTick =\n typeof data === \"string\"\n ? parseInt(data, 10)\n : (data as unknown as number);\n if (ackTick === -1) {\n // Client requesting keyframe\n this._clientBaselines.delete(peerId);\n } else {\n this._clientBaselines.set(peerId, ackTick);\n }\n } catch {\n /* ignore malformed ACKs */\n }\n });\n\n // Handle new peer joins — they need a keyframe\n transport.onPeerJoin((peerId) => {\n this._clientBaselines.delete(peerId); // Will force keyframe\n });\n\n transport.onPeerLeave((peerId) => {\n this._clientBaselines.delete(peerId);\n });\n }\n\n /** Set optional interest management filter */\n setInterestFilter(\n filter: ((entityId: string, peerId: string) => boolean) | null,\n ): void {\n this._interestFilter = filter;\n }\n\n /**\n * Called every fixed tick by the sync engine.\n * Collects entity states and decides whether to broadcast.\n * `hostInput` (prediction mode) is embedded in the snapshot packet as `hi`.\n */\n tick(\n currentTick: number,\n entities: Map<string, EntityState>,\n delta: number,\n hostInput?: PlayerInput,\n ): void {\n this._tick = currentTick;\n\n // Store snapshot in ring buffer\n this._snapshotBuffer.store(currentTick, new Map(entities));\n\n // Check if we should broadcast this tick\n this._broadcastAccumulator += delta;\n const broadcastInterval = 1 / this._broadcastRate;\n if (this._broadcastAccumulator < broadcastInterval) return;\n this._broadcastAccumulator -= broadcastInterval;\n\n // Broadcast to each connected client\n for (const peerId of this._transport.peers) {\n this._broadcastToClient(peerId, currentTick, entities, hostInput);\n }\n }\n\n /** Force a keyframe broadcast to all clients (e.g., after host migration) */\n forceKeyframe(\n currentTick: number,\n entities: Map<string, EntityState>,\n hostInput?: PlayerInput,\n ): void {\n this._clientBaselines.clear();\n this._clientLastKeyframeTick.clear();\n this._snapshotBuffer.store(currentTick, new Map(entities));\n for (const peerId of this._transport.peers) {\n this._broadcastToClient(peerId, currentTick, entities, hostInput);\n }\n }\n\n destroy(): void {\n this._snapshotChannel.close();\n this._ackChannel.close();\n this._clientBaselines.clear();\n this._clientLastKeyframeTick.clear();\n }\n\n private _broadcastToClient(\n peerId: string,\n currentTick: number,\n entities: Map<string, EntityState>,\n hostInput?: PlayerInput,\n ): void {\n // Apply interest management filter\n let clientEntities = entities;\n if (this._interestFilter) {\n clientEntities = new Map<string, EntityState>();\n for (const [id, entity] of entities) {\n if (this._interestFilter(id, peerId)) {\n clientEntities.set(id, entity);\n }\n }\n }\n\n // Determine baseline for delta compression (per-client keyframe scheduling)\n const clientBaseTick = this._clientBaselines.get(peerId);\n const clientLastKeyframe = this._clientLastKeyframeTick.get(peerId) ?? 0;\n const needsKeyframe =\n clientBaseTick === undefined ||\n currentTick - clientLastKeyframe >= this._keyframeInterval;\n\n let baseline: Map<string, EntityState> | undefined;\n if (!needsKeyframe && clientBaseTick !== undefined) {\n baseline = this._snapshotBuffer.get(clientBaseTick);\n }\n\n if (needsKeyframe) {\n this._clientLastKeyframeTick.set(peerId, currentTick);\n }\n\n // Serialize (delta or keyframe)\n const packet = this._codec.serializeDelta(\n currentTick,\n needsKeyframe ? -1 : (clientBaseTick ?? -1),\n clientEntities,\n baseline,\n hostInput,\n );\n\n if (packet) {\n this._snapshotChannel.send(packet, peerId);\n }\n }\n}\n","import type {\n CarverTransport,\n CarverChannel,\n EntityState,\n EntityState2D,\n EntityState3D,\n NetworkQuality,\n SnapshotListener,\n} from \"../types\";\nimport { Codec } from \"./codec\";\n\ninterface BufferedSnapshot {\n tick: number;\n entities: Map<string, EntityState>;\n receivedAt: number;\n}\n\n/**\n * Client-side state receiver: buffers incoming snapshots and interpolates\n * between them for smooth rendering.\n */\nexport class ClientReceiver {\n private _transport: CarverTransport;\n private _codec: Codec;\n private _snapshotChannel: CarverChannel<Uint8Array>;\n private _ackChannel: CarverChannel<string>;\n\n // Snapshot buffer (ring buffer of last N snapshots)\n private _buffer: BufferedSnapshot[] = [];\n private _bufferSize: number;\n\n // Interpolation settings\n private _method: \"hermite\" | \"linear\";\n private _extrapolateMs: number;\n\n // Current interpolated state\n private _interpolatedState = new Map<string, EntityState>();\n\n // Network quality tracking\n private _lastSnapshotTime = 0;\n private _networkQuality: NetworkQuality = \"good\";\n private _packetLossCount = 0;\n private _packetCount = 0;\n\n // Is2D mode\n private _is2D: boolean;\n\n // Entity state: full accumulated state from keyframes + deltas\n private _fullState = new Map<string, EntityState>();\n\n // Listeners fired after each snapshot is merged into the full world state\n private _snapshotListeners: SnapshotListener[] = [];\n\n constructor(\n transport: CarverTransport,\n codec: Codec,\n options?: {\n bufferSize?: number;\n method?: \"hermite\" | \"linear\";\n extrapolateMs?: number;\n is2D?: boolean;\n },\n ) {\n this._transport = transport;\n this._codec = codec;\n this._bufferSize = options?.bufferSize ?? 3;\n this._method = options?.method ?? \"hermite\";\n this._extrapolateMs = options?.extrapolateMs ?? 250;\n this._is2D = options?.is2D ?? false;\n\n // Listen on the unreliable snapshot channel\n this._snapshotChannel = transport.createChannel<Uint8Array>(\n \"carver:snapshots\",\n {\n reliable: false,\n ordered: false,\n maxRetransmits: 0,\n },\n );\n\n this._ackChannel = transport.createChannel<string>(\"carver:acks\", {\n reliable: true,\n ordered: true,\n });\n\n this._snapshotChannel.onReceive((data: Uint8Array) => {\n this._handleSnapshot(data);\n });\n }\n\n /** Get the current interpolated entity states */\n get state(): Map<string, EntityState> {\n return this._interpolatedState;\n }\n\n get networkQuality(): NetworkQuality {\n return this._networkQuality;\n }\n\n /**\n * Called every render frame to interpolate between buffered snapshots.\n * @param renderTime - current render time in ms\n */\n interpolate(renderTime: number): Map<string, EntityState> {\n if (this._buffer.length < 2) {\n // Not enough snapshots to interpolate, return latest\n return this._buffer.length > 0\n ? this._buffer[this._buffer.length - 1].entities\n : this._interpolatedState;\n }\n\n // Find two snapshots to interpolate between\n // We render \"behind\" by one buffer interval\n const interpDelay = (this._bufferSize - 1) * (1000 / 20); // Assume ~20 pps\n const targetTime = renderTime - interpDelay;\n\n let from: BufferedSnapshot | null = null;\n let to: BufferedSnapshot | null = null;\n\n for (let i = 0; i < this._buffer.length - 1; i++) {\n if (\n this._buffer[i].receivedAt <= targetTime &&\n this._buffer[i + 1].receivedAt > targetTime\n ) {\n from = this._buffer[i];\n to = this._buffer[i + 1];\n break;\n }\n }\n\n if (!from || !to) {\n // Extrapolation case: we're past all buffered snapshots\n const latest = this._buffer[this._buffer.length - 1];\n const timeSinceLatest = renderTime - latest.receivedAt;\n\n if (timeSinceLatest > this._extrapolateMs) {\n // Too far behind, just use latest snapshot\n this._updateNetworkQuality(\"poor\");\n return latest.entities;\n }\n\n if (this._buffer.length >= 2) {\n from = this._buffer[this._buffer.length - 2];\n to = latest;\n this._updateNetworkQuality(\"degraded\");\n } else {\n return latest.entities;\n }\n } else {\n this._updateNetworkQuality(\"good\");\n }\n\n // Compute interpolation factor\n const range = to.receivedAt - from.receivedAt;\n const t =\n range > 0\n ? Math.min(1, Math.max(0, (targetTime - from.receivedAt) / range))\n : 1;\n\n // Interpolate all entities\n const result = new Map<string, EntityState>();\n const allIds = new Set([...from.entities.keys(), ...to.entities.keys()]);\n\n for (const id of allIds) {\n const fromEntity = from.entities.get(id);\n const toEntity = to.entities.get(id);\n\n if (toEntity && toEntity.c?.__removed) continue; // Removed entity\n\n if (fromEntity && toEntity) {\n result.set(id, this._interpolateEntity(fromEntity, toEntity, t));\n } else if (toEntity) {\n result.set(id, toEntity);\n }\n }\n\n this._interpolatedState = result;\n return result;\n }\n\n /** Request a keyframe from the host */\n requestKeyframe(): void {\n this._ackChannel.send(\"-1\");\n }\n\n /** Register a listener fired after each snapshot is merged into the full world state */\n onSnapshot(cb: SnapshotListener): void {\n this._snapshotListeners.push(cb);\n }\n\n destroy(): void {\n this._snapshotChannel.close();\n this._ackChannel.close();\n this._buffer = [];\n this._interpolatedState.clear();\n this._fullState.clear();\n this._snapshotListeners = [];\n }\n\n private _handleSnapshot(data: Uint8Array): void {\n try {\n const { tick, baseTick, entities, hostInput } =\n this._codec.deserializePacket(data);\n const now = performance.now();\n\n if (baseTick === -1) {\n // Keyframe: replace full state\n this._fullState.clear();\n for (const entity of entities) {\n this._fullState.set(entity.id, entity);\n }\n } else {\n // Delta: apply changes to full state\n for (const entity of entities) {\n if (entity.c?.__removed) {\n this._fullState.delete(entity.id);\n } else {\n this._fullState.set(entity.id, entity);\n }\n }\n }\n\n // Buffer the full state snapshot\n const fullStateClone = new Map(this._fullState);\n this._buffer.push({\n tick,\n entities: fullStateClone,\n receivedAt: now,\n });\n\n // Keep buffer bounded\n while (this._buffer.length > this._bufferSize * 2) {\n this._buffer.shift();\n }\n\n // Send ACK\n this._ackChannel.send(String(tick));\n\n // Notify snapshot listeners with the merged full world state\n for (const cb of this._snapshotListeners) {\n cb(tick, fullStateClone, hostInput);\n }\n\n // Track timing for network quality\n this._lastSnapshotTime = now;\n this._packetCount++;\n } catch {\n this._packetLossCount++;\n }\n }\n\n private _interpolateEntity(\n from: EntityState,\n to: EntityState,\n t: number,\n ): EntityState {\n if (this._is2D || !(\"z\" in from)) {\n return this._interpolateEntity2D(\n from as EntityState2D,\n to as EntityState2D,\n t,\n );\n }\n return this._interpolateEntity3D(\n from as EntityState3D,\n to as EntityState3D,\n t,\n );\n }\n\n private _interpolateEntity2D(\n from: EntityState2D,\n to: EntityState2D,\n t: number,\n ): EntityState2D {\n if (this._method === \"hermite\") {\n return {\n id: to.id,\n x: hermite(from.x, from.vx, to.x, to.vx, t),\n y: hermite(from.y, from.vy, to.y, to.vy, t),\n a: lerpAngle(from.a, to.a, t),\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n va: lerp(from.va, to.va, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n // Linear\n return {\n id: to.id,\n x: lerp(from.x, to.x, t),\n y: lerp(from.y, to.y, t),\n a: lerpAngle(from.a, to.a, t),\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n va: lerp(from.va, to.va, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n\n private _interpolateEntity3D(\n from: EntityState3D,\n to: EntityState3D,\n t: number,\n ): EntityState3D {\n // Quaternion SLERP for rotation\n const [qx, qy, qz, qw] = slerp(\n from.qx,\n from.qy,\n from.qz,\n from.qw,\n to.qx,\n to.qy,\n to.qz,\n to.qw,\n t,\n );\n\n if (this._method === \"hermite\") {\n return {\n id: to.id,\n x: hermite(from.x, from.vx, to.x, to.vx, t),\n y: hermite(from.y, from.vy, to.y, to.vy, t),\n z: hermite(from.z, from.vz, to.z, to.vz, t),\n qx,\n qy,\n qz,\n qw,\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n vz: lerp(from.vz, to.vz, t),\n wx: lerp(from.wx, to.wx, t),\n wy: lerp(from.wy, to.wy, t),\n wz: lerp(from.wz, to.wz, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n\n // Linear\n return {\n id: to.id,\n x: lerp(from.x, to.x, t),\n y: lerp(from.y, to.y, t),\n z: lerp(from.z, to.z, t),\n qx,\n qy,\n qz,\n qw,\n vx: lerp(from.vx, to.vx, t),\n vy: lerp(from.vy, to.vy, t),\n vz: lerp(from.vz, to.vz, t),\n wx: lerp(from.wx, to.wx, t),\n wy: lerp(from.wy, to.wy, t),\n wz: lerp(from.wz, to.wz, t),\n c: interpolateCustom(from.c, to.c, t),\n };\n }\n\n private _updateNetworkQuality(quality: NetworkQuality): void {\n this._networkQuality = quality;\n }\n}\n\n// ── Math utilities ──\n\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nfunction lerpAngle(a: number, b: number, t: number): number {\n let diff = b - a;\n // Wrap to [-PI, PI]\n while (diff > Math.PI) diff -= Math.PI * 2;\n while (diff < -Math.PI) diff += Math.PI * 2;\n return a + diff * t;\n}\n\n/**\n * Hermite spline interpolation using velocity for smooth curves.\n * h(t) = (2t^3 - 3t^2 + 1)p0 + (t^3 - 2t^2 + t)v0 + (-2t^3 + 3t^2)p1 + (t^3 - t^2)v1\n */\nfunction hermite(\n p0: number,\n v0: number,\n p1: number,\n v1: number,\n t: number,\n): number {\n const t2 = t * t;\n const t3 = t2 * t;\n return (\n (2 * t3 - 3 * t2 + 1) * p0 +\n (t3 - 2 * t2 + t) * v0 +\n (-2 * t3 + 3 * t2) * p1 +\n (t3 - t2) * v1\n );\n}\n\n/**\n * Quaternion SLERP (Spherical Linear Interpolation).\n */\nfunction slerp(\n ax: number,\n ay: number,\n az: number,\n aw: number,\n bx: number,\n by: number,\n bz: number,\n bw: number,\n t: number,\n): [number, number, number, number] {\n // Compute dot product\n let dot = ax * bx + ay * by + az * bz + aw * bw;\n\n // Ensure shortest path\n if (dot < 0) {\n bx = -bx;\n by = -by;\n bz = -bz;\n bw = -bw;\n dot = -dot;\n }\n\n if (dot > 0.9995) {\n // Very close, use linear interpolation\n return [lerp(ax, bx, t), lerp(ay, by, t), lerp(az, bz, t), lerp(aw, bw, t)];\n }\n\n const theta = Math.acos(Math.min(1, Math.max(-1, dot)));\n const sinTheta = Math.sin(theta);\n const wa = Math.sin((1 - t) * theta) / sinTheta;\n const wb = Math.sin(t * theta) / sinTheta;\n\n return [\n ax * wa + bx * wb,\n ay * wa + by * wb,\n az * wa + bz * wb,\n aw * wa + bw * wb,\n ];\n}\n\n/**\n * Interpolate custom properties: lerp numbers, instant-swap others.\n */\nfunction interpolateCustom(\n from: Record<string, unknown> | undefined,\n to: Record<string, unknown> | undefined,\n t: number,\n): Record<string, unknown> | undefined {\n if (!from && !to) return undefined;\n if (!from) return to;\n if (!to) return from;\n\n const result: Record<string, unknown> = {};\n const allKeys = new Set([...Object.keys(from), ...Object.keys(to)]);\n\n for (const key of allKeys) {\n const fromVal = from[key];\n const toVal = to[key];\n if (typeof fromVal === \"number\" && typeof toVal === \"number\") {\n result[key] = lerp(fromVal, toVal, t);\n } else {\n // Instant swap: use target value after halfway\n result[key] = t >= 0.5 ? toVal : fromVal;\n }\n }\n\n return result;\n}\n","import type {\n CarverTransport,\n EntityState,\n PlayerInput,\n SnapshotListener,\n SnapshotSource,\n} from \"../types\";\nimport { Codec, SnapshotBuffer } from \"../core/codec\";\nimport { HostAuthority } from \"../core/HostAuthority\";\nimport { ClientReceiver } from \"../core/ClientReceiver\";\n\nexport interface SnapshotSyncOptions {\n broadcastRate?: number;\n keyframeInterval?: number;\n bufferSize?: number;\n interpolationMethod?: \"hermite\" | \"linear\";\n extrapolateMs?: number;\n is2D?: boolean;\n}\n\n/**\n * Layer 2: Snapshot interpolation sync engine.\n * Host broadcasts state at fixed intervals, clients interpolate.\n */\nexport class SnapshotSync implements SnapshotSource {\n private _transport: CarverTransport;\n private _hostAuthority: HostAuthority | null = null;\n private _clientReceiver: ClientReceiver | null = null;\n private _codec: Codec;\n private _snapshotBuffer: SnapshotBuffer;\n\n // Snapshot listeners survive host migration (forwarder re-attached on demote)\n private _snapshotListeners: SnapshotListener[] = [];\n\n constructor(\n transport: CarverTransport,\n codec: Codec,\n snapshotBuffer: SnapshotBuffer,\n options?: SnapshotSyncOptions,\n ) {\n this._transport = transport;\n this._codec = codec;\n this._snapshotBuffer = snapshotBuffer;\n\n if (transport.isHost) {\n this._hostAuthority = new HostAuthority(\n transport,\n codec,\n snapshotBuffer,\n {\n broadcastRate: options?.broadcastRate,\n keyframeInterval: options?.keyframeInterval,\n },\n );\n } else {\n this._clientReceiver = new ClientReceiver(transport, codec, {\n bufferSize: options?.bufferSize,\n method: options?.interpolationMethod,\n extrapolateMs: options?.extrapolateMs,\n is2D: options?.is2D,\n });\n this._attachSnapshotForwarder(this._clientReceiver);\n }\n }\n\n get isHost(): boolean {\n return this._hostAuthority !== null;\n }\n\n get hostAuthority(): HostAuthority | null {\n return this._hostAuthority;\n }\n\n get clientReceiver(): ClientReceiver | null {\n return this._clientReceiver;\n }\n\n /** Host: called every fixed tick to potentially broadcast state */\n hostTick(\n tick: number,\n entities: Map<string, EntityState>,\n delta: number,\n hostInput?: PlayerInput,\n ): void {\n this._hostAuthority?.tick(tick, entities, delta, hostInput);\n }\n\n /** Register a listener fired after each merged snapshot (client side). */\n onSnapshot(cb: SnapshotListener): void {\n this._snapshotListeners.push(cb);\n }\n\n /** Client: called every render frame to interpolate */\n clientInterpolate(renderTime: number): Map<string, EntityState> {\n return this._clientReceiver?.interpolate(renderTime) ?? new Map();\n }\n\n /** Set interest filter on host authority */\n setInterestFilter(\n filter: ((entityId: string, peerId: string) => boolean) | null,\n ): void {\n this._hostAuthority?.setInterestFilter(filter);\n }\n\n /** Handle host migration: switch from client to host mode */\n promoteToHost(options?: SnapshotSyncOptions): void {\n this._clientReceiver?.destroy();\n this._clientReceiver = null;\n this._hostAuthority = new HostAuthority(\n this._transport,\n this._codec,\n this._snapshotBuffer,\n {\n broadcastRate: options?.broadcastRate,\n keyframeInterval: options?.keyframeInterval,\n },\n );\n }\n\n /** Handle host migration: switch from host to client mode */\n demoteToClient(options?: SnapshotSyncOptions): void {\n this._hostAuthority?.destroy();\n this._hostAuthority = null;\n this._clientReceiver = new ClientReceiver(\n this._transport,\n this._codec,\n {\n bufferSize: options?.bufferSize,\n method: options?.interpolationMethod,\n extrapolateMs: options?.extrapolateMs,\n is2D: options?.is2D,\n },\n );\n this._attachSnapshotForwarder(this._clientReceiver);\n }\n\n destroy(): void {\n this._hostAuthority?.destroy();\n this._clientReceiver?.destroy();\n this._hostAuthority = null;\n this._clientReceiver = null;\n this._snapshotListeners = [];\n }\n\n // ── Private ──\n\n /** Forward receiver snapshots to registered listeners (survives host migration). */\n private _attachSnapshotForwarder(receiver: ClientReceiver): void {\n receiver.onSnapshot((t, e, hi) => {\n for (const l of this._snapshotListeners) l(t, e, hi);\n });\n }\n}\n","/**\n * InputBuffer — unified ring-buffer for local and peer inputs.\n *\n * Ported from LumberNet's LumberInputBuffer. Stores:\n * - local player tick-keyed inputs (storeTick / getTick / hasTick)\n * - last-received input per remote peer (setRemote / getRemote / allRemotes)\n * - per-peer tick-keyed inputs for accurate rollback resimulation (getRemoteAtTick)\n *\n * Generic over per-tick payload I. Caller supplies the neutral payload.\n */\n\nimport type { PlayerInput } from \"../types\";\n\nexport class InputBuffer<I extends PlayerInput = PlayerInput> {\n private readonly _historySize: number;\n private readonly _neutral: I;\n\n /** Local player tick-keyed inputs (ring buffer). */\n private readonly _local = new Map<number, I>();\n\n /** Last-received input per remote peer. */\n private readonly _remotes = new Map<string, I>();\n\n /** Per-peer tick-keyed inputs for accurate rollback re-simulation. */\n private readonly _peerTicks = new Map<string, Map<number, I>>();\n\n constructor(neutralInput: I, historySize = 120) {\n this._neutral = { ...neutralInput } as I;\n this._historySize = historySize;\n }\n\n // ── Local input ──\n\n /** Record a snapshot of the local input at the given tick. Evicts the entry exactly historySize back. */\n storeTick(tick: number, input: I): void {\n this._local.set(tick, { ...input } as I);\n this._local.delete(tick - this._historySize);\n }\n\n /** Return the local input at `tick`, or a neutral copy if out of range. */\n getTick(tick: number): I {\n return this._local.get(tick) ?? ({ ...this._neutral } as I);\n }\n\n /** True if we have a stored local input for this tick (used to avoid spurious justPressed after snap/rejoin). */\n hasTick(tick: number): boolean {\n return this._local.has(tick);\n }\n\n /** Neutral payload with every boolean field forced false (use for justPressed when prev tick is unknown). */\n getJustPressedZero(): I {\n const out = {} as I;\n for (const key in this._neutral) {\n const v = this._neutral[key];\n (out as Record<string, boolean | number | undefined>)[key] =\n typeof v === \"boolean\" ? false : v;\n }\n return out;\n }\n\n // ── Remote (peer) inputs ──\n\n /**\n * Record a remote peer's input. If `tick` is given (the sender's local tick),\n * also store it in the per-peer ring buffer for rollback.\n */\n setRemote(peerId: string, input: I, tick?: number): void {\n this._remotes.set(peerId, input);\n if (tick !== undefined) {\n let peerMap = this._peerTicks.get(peerId);\n if (!peerMap) {\n peerMap = new Map();\n this._peerTicks.set(peerId, peerMap);\n }\n peerMap.set(tick, input);\n peerMap.delete(tick - this._historySize);\n }\n }\n\n /** Last-known input for a peer, or a neutral copy if never received. */\n getRemote(peerId: string): I {\n return this._remotes.get(peerId) ?? ({ ...this._neutral } as I);\n }\n\n /** Snapshot of all remote peers' last-known inputs (shallow copy of the map). */\n allRemotes(): Map<string, I> {\n return new Map(this._remotes);\n }\n\n /**\n * Return a peer's exact input at the given tick (for rollback accuracy),\n * falling back to their last-known input when history does not reach that far.\n */\n getRemoteAtTick(peerId: string, tick: number): I {\n return this._peerTicks.get(peerId)?.get(tick) ?? this.getRemote(peerId);\n }\n\n /** Override the last-known input for a peer (does NOT touch tick history). */\n overrideRemote(peerId: string, input: I): void {\n this._remotes.set(peerId, input);\n }\n\n /** Number of currently tracked remote peers. */\n get peerCount(): number {\n return this._remotes.size;\n }\n\n /** Iterate tracked peer IDs. */\n peerIds(): IterableIterator<string> {\n return this._remotes.keys();\n }\n\n /**\n * Keep only these peer IDs; remove any other remotes (e.g. after leave/rejoin).\n * Call when the room's peer list changes so stale peers stop receiving input.\n */\n setPeerIds(peerIds: ReadonlySet<string> | string[]): void {\n const set = peerIds instanceof Set ? peerIds : new Set(peerIds);\n for (const id of this._remotes.keys()) {\n if (!set.has(id)) {\n this._remotes.delete(id);\n this._peerTicks.delete(id);\n }\n }\n }\n\n // ── Lifecycle ──\n\n /** Clear local history, remote last-known inputs, and per-peer tick history. */\n clear(): void {\n this._local.clear();\n this._remotes.clear();\n this._peerTicks.clear();\n }\n}\n","/**\n * Input utilities for prediction mode.\n * Ported from LumberNet's InputUtils.\n */\n\nimport type { PlayerInput } from \"../types\";\n\n/**\n * Given the input state at the current tick and the previous tick, return a new\n * input object where each boolean field is `true` only if it transitioned\n * false -> true (a \"rising edge\" / \"just pressed\").\n *\n * Non-boolean fields are passed through unchanged from `curr`.\n * Iterates `curr` keys only; keys present only in `prev` are absent from the result.\n *\n * PredictionSync calls this automatically and passes the result as `justPressed`\n * to every onPhysicsStep callback, so games normally do not call it directly.\n */\nexport function computeJustPressed<I extends PlayerInput>(curr: I, prev: I): I {\n const out = {} as I;\n for (const key in curr) {\n const c = curr[key];\n (out as Record<string, boolean | number | undefined>)[key] =\n typeof c === \"boolean\" ? c === true && prev[key] !== true : c;\n }\n return out;\n}\n","/**\n * Rollback — full-world rollback for prediction mode.\n *\n * Ported from LumberNet's LumberRollback, adapted to CarverJS entity state\n * (2D and 3D). On each accepted server snapshot the client:\n * 1. captures the pre-rollback visual pose (raw physics + accumulated error),\n * 2. hard-applies server state to EVERY networked entity,\n * 3. resimulates from serverTick + 1 to localTick replaying per-tick inputs\n * (or hard-snaps the tick when drift exceeds maxRewindTicks),\n * 4. converts the visual discontinuity into per-entity error offsets.\n *\n * Pure module: no transport, no React, no three.js. Quaternion math is\n * hand-rolled below.\n */\n\nimport type { InputBuffer } from \"../core/InputBuffer\";\nimport { computeJustPressed } from \"../core/InputUtils\";\nimport type {\n EntityState,\n ErrorOffset,\n PhysicsStepCallback,\n PlayerInput,\n PredictionWorldDriver,\n} from \"../types\";\n\n// ── Quaternion helpers ──\n\nexport interface Quat {\n x: number;\n y: number;\n z: number;\n w: number;\n}\n\nconst IDENTITY_QUAT: Quat = { x: 0, y: 0, z: 0, w: 1 };\n\n/** Hamilton product (a ⊗ b). */\nexport function quatMultiply(a: Quat, b: Quat): Quat {\n return {\n x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,\n y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,\n z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,\n w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,\n };\n}\n\n/** Conjugate (inputs assumed normalized). */\nexport function quatInvert(q: Quat): Quat {\n return { x: -q.x, y: -q.y, z: -q.z, w: q.w };\n}\n\n/** Normalize; degenerate (near-zero) quaternions return identity. */\nexport function quatNormalize(q: Quat): Quat {\n const mag = Math.hypot(q.x, q.y, q.z, q.w);\n if (mag < 1e-12) return { ...IDENTITY_QUAT };\n return { x: q.x / mag, y: q.y / mag, z: q.z / mag, w: q.w / mag };\n}\n\n/** Rotation angle in radians: 2*acos(clamp(|w|, 0, 1)). */\nexport function quatAngle(q: Quat): number {\n return 2 * Math.acos(Math.min(1, Math.abs(q.w)));\n}\n\n/** Scale the rotation angle toward identity by `factor`, preserving the axis. */\nexport function quatScaleAngle(q: Quat, factor: number): Quat {\n let n = quatNormalize(q);\n if (n.w < 0) n = { x: -n.x, y: -n.y, z: -n.z, w: -n.w };\n const angle = 2 * Math.acos(Math.min(1, n.w));\n if (angle < 1e-6) return { ...IDENTITY_QUAT };\n const s = Math.sin(angle / 2);\n const ax = n.x / s;\n const ay = n.y / s;\n const az = n.z / s;\n const na = angle * factor;\n const ns = Math.sin(na / 2);\n return { x: ax * ns, y: ay * ns, z: az * ns, w: Math.cos(na / 2) };\n}\n\n// ── Rollback ──\n\nexport interface RollbackParams {\n /** Tick embedded in the accepted server snapshot. */\n serverTick: number;\n /** Authoritative full-world state from the snapshot. */\n serverState: ReadonlyMap<string, EntityState>;\n /** Client's current simulation tick. */\n localTick: number;\n /** This peer's id (local inputs are replayed from the local ring buffer). */\n localPeerId: string;\n /** Input buffer holding local and per-peer tick history. */\n inputs: InputBuffer;\n /** Currently accumulated visual error offsets (kept continuous across rollbacks). */\n currentErrors: ReadonlyMap<string, ErrorOffset>;\n /** World access for capture/apply/step. */\n driver: PredictionWorldDriver;\n /** Game physics-step callback, re-invoked during resimulation. */\n callback: PhysicsStepCallback | null;\n /** Fixed timestep in seconds. */\n dt: number;\n /** Snap target offset: snap target = serverTick + driftTargetTicks. */\n driftTargetTicks: number;\n /** Max |localTick - (serverTick + driftTargetTicks)| before hard tick snap. */\n maxRewindTicks: number;\n /** Per-axis positional jump above which correction is suppressed (teleport). */\n snapThreshold: number;\n}\n\nexport interface RollbackResult {\n /** New local tick (differs from localTick only when a hard snap occurred). */\n newLocalTick: number;\n snapped: boolean;\n /** Per-entity visual error offsets (pre-visual minus post-resim). */\n errors: Map<string, ErrorOffset>;\n}\n\ninterface PreVisualPose {\n x: number;\n y: number;\n z: number;\n a: number;\n q: Quat;\n is3D: boolean;\n}\n\n/**\n * Apply a server snapshot to the whole world and resimulate forward.\n * Returns the new local tick and per-entity visual error offsets.\n */\nexport function applyRollback(params: RollbackParams): RollbackResult {\n const {\n serverTick,\n serverState,\n localTick,\n localPeerId,\n inputs,\n currentErrors,\n driver,\n callback,\n dt,\n driftTargetTicks,\n maxRewindTicks,\n snapThreshold,\n } = params;\n\n // Step 0: pre-rollback visual pose (raw physics + accumulated error)\n const preState = driver.captureState();\n const preMap = new Map<string, PreVisualPose>();\n for (const [id, s] of preState) {\n const e = currentErrors.get(id);\n const ex = e?.x ?? 0;\n const ey = e?.y ?? 0;\n if (\"z\" in s) {\n const errQ: Quat = e\n ? { x: e.qx, y: e.qy, z: e.qz, w: e.qw }\n : { ...IDENTITY_QUAT };\n preMap.set(id, {\n x: s.x + ex,\n y: s.y + ey,\n z: s.z + (e?.z ?? 0),\n a: 0,\n q: quatMultiply(errQ, { x: s.qx, y: s.qy, z: s.qz, w: s.qw }),\n is3D: true,\n });\n } else {\n preMap.set(id, {\n x: s.x + ex,\n y: s.y + ey,\n z: 0,\n a: s.a + (e?.a ?? 0),\n q: { ...IDENTITY_QUAT },\n is3D: false,\n });\n }\n }\n\n // Step 1: hard-apply server state to the WHOLE world (local player included)\n driver.applyState(serverState.values());\n\n // Step 2: snap-vs-resim decision\n const targetTick = serverTick + driftTargetTicks;\n const tickDiff = localTick - targetTick;\n let newLocalTick = localTick;\n let snapped = false;\n\n if (Math.abs(tickDiff) > maxRewindTicks) {\n newLocalTick = targetTick;\n snapped = true;\n } else {\n // Step 3: resimulate from serverTick + 1 to localTick replaying tick-exact inputs\n for (let i = serverTick + 1; i <= localTick; i++) {\n if (callback) {\n const tickInputs = new Map<string, PlayerInput>();\n const justPressed = new Map<string, PlayerInput>();\n for (const peerId of inputs.peerIds()) {\n if (peerId === localPeerId) continue;\n const curr = inputs.getRemoteAtTick(peerId, i);\n tickInputs.set(peerId, curr);\n justPressed.set(\n peerId,\n computeJustPressed(curr, inputs.getRemoteAtTick(peerId, i - 1)),\n );\n }\n const localCurr = inputs.getTick(i);\n tickInputs.set(localPeerId, localCurr);\n justPressed.set(\n localPeerId,\n computeJustPressed(localCurr, inputs.getTick(i - 1)),\n );\n callback(tickInputs, justPressed, i, true, dt);\n }\n driver.stepWorld?.();\n }\n }\n\n // Step 4: error vectors = pre-rollback visual pose minus post-resim state\n const postState = driver.captureState();\n const errors = new Map<string, ErrorOffset>();\n for (const [id, post] of postState) {\n const pre = preMap.get(id);\n if (!pre) continue;\n\n const errX = pre.x - post.x;\n const errY = pre.y - post.y;\n let errZ = 0;\n let errA = 0;\n let q: Quat = { ...IDENTITY_QUAT };\n\n if (\"z\" in post) {\n errZ = pre.z - post.z;\n let dq = quatNormalize(\n quatMultiply(\n pre.q,\n quatInvert({ x: post.qx, y: post.qy, z: post.qz, w: post.qw }),\n ),\n );\n if (dq.w < 0) dq = { x: -dq.x, y: -dq.y, z: -dq.z, w: -dq.w };\n q = dq;\n } else {\n const ad = pre.a - post.a;\n // Wrap to (-PI, PI]\n errA = ad - Math.PI * 2 * Math.floor((ad + Math.PI) / (Math.PI * 2));\n }\n\n // Large per-axis jump -> suppress ALL correction (intentional teleport)\n if (\n Math.abs(errX) > snapThreshold ||\n Math.abs(errY) > snapThreshold ||\n Math.abs(errZ) > snapThreshold\n ) {\n errors.set(id, { x: 0, y: 0, z: 0, a: 0, qx: 0, qy: 0, qz: 0, qw: 1 });\n } else {\n errors.set(id, {\n x: errX,\n y: errY,\n z: errZ,\n a: errA,\n qx: q.x,\n qy: q.y,\n qz: q.z,\n qw: q.w,\n });\n }\n }\n\n return { newLocalTick, snapped, errors };\n}\n","/**\n * Layer 3: Full-world prediction with full-world rollback.\n * Ported from LumberNet, built on top of Layer 2 (SnapshotSync) as the\n * authoritative state channel.\n *\n * Flow:\n * Every peer (host included): broadcast tick-stamped input to ALL peers each\n * fixed tick on carver:inputs, simulate EVERY networked entity forward with\n * last-known remote inputs (hold-last-input extrapolation).\n *\n * Host: stays authoritative; SnapshotSync broadcasts delta-compressed,\n * ACK-driven snapshots with the host's own input embedded (`hi`).\n *\n * Client: on each accepted snapshot, reset ALL networked entities to server\n * state, resimulate from serverTick + 1 to localTick replaying per-tick\n * inputs for every peer, and convert the visual discontinuity into\n * per-entity error offsets decayed per render frame.\n *\n * Role is checked dynamically via transport.isHost at every use site (host\n * migration is best-effort).\n */\n\nimport type {\n CarverTransport,\n CarverChannel,\n EntityState,\n ErrorOffset,\n InputPacket,\n PhysicsStepCallback,\n PlayerInput,\n PredictionSyncOptions,\n PredictionWorldDriver,\n SnapshotSource,\n} from \"../types\";\nimport { TickKeeper } from \"../core/TickKeeper\";\nimport { InputBuffer } from \"../core/InputBuffer\";\nimport { computeJustPressed } from \"../core/InputUtils\";\nimport { applyRollback, quatAngle, quatScaleAngle } from \"./Rollback\";\n\nconst DEFAULT_OPTIONS: Required<PredictionSyncOptions> = {\n maxRewindTicks: 15,\n snapThreshold: 150,\n errorDecay: 0.85,\n maxErrorPerFrame: 0,\n neutralInput: {},\n inputHistorySize: 120,\n driftTargetTicks: 4,\n};\n\ninterface PendingSnapshot {\n t: number;\n entities: Map<string, EntityState>;\n hostInput: PlayerInput | undefined;\n}\n\nexport class PredictionSync {\n private _transport: CarverTransport;\n private _tickKeeper: TickKeeper;\n private _options: Required<PredictionSyncOptions>;\n\n // Reliable ordered all-to-all input channel\n private _inputChannel: CarverChannel<InputPacket>;\n\n // Local + per-peer tick-stamped input history\n private _inputs: InputBuffer;\n\n // Local input; persists across ticks until replaced (hold-input semantics)\n private _currentInput: PlayerInput | null = null;\n\n // Newest pending server snapshot awaiting rollback (only the newest survives)\n private _pending: PendingSnapshot | null = null;\n\n // Per-entity accumulated visual error offsets\n private _errors = new Map<string, ErrorOffset>();\n\n private _serverTick = 0;\n private _lastAppliedServerTick = 0;\n\n private _worldDriver: PredictionWorldDriver | null = null;\n private _onPhysicsStep: PhysicsStepCallback | null = null;\n\n constructor(\n transport: CarverTransport,\n tickKeeper: TickKeeper,\n snapshots: SnapshotSource,\n options?: PredictionSyncOptions,\n ) {\n this._transport = transport;\n this._tickKeeper = tickKeeper;\n this._options = { ...DEFAULT_OPTIONS, ...options };\n\n this._inputs = new InputBuffer(\n this._options.neutralInput,\n this._options.inputHistorySize,\n );\n\n // All-to-all input broadcast channel (registered regardless of role)\n this._inputChannel = transport.createChannel<InputPacket>(\"carver:inputs\", {\n reliable: true,\n ordered: true,\n });\n\n this._inputChannel.onReceive(\n (data: InputPacket | string, peerId: string) => {\n try {\n const packet =\n typeof data === \"string\" ? (JSON.parse(data) as InputPacket) : data;\n if (\n typeof packet.t === \"number\" &&\n packet.i !== null &&\n typeof packet.i === \"object\"\n ) {\n // Key by the transport-provided sender id; never trust packet.p\n this._inputs.setRemote(peerId, packet.i, packet.t);\n }\n } catch (err) {\n if (typeof console !== \"undefined\")\n console.debug(\"[CarverJS] Malformed input packet:\", err);\n }\n },\n );\n\n // Accepted snapshots become pending rollbacks (clients only)\n snapshots.onSnapshot((tick, entities, hostInput) => {\n if (this._transport.isHost) return;\n if (tick <= this._lastAppliedServerTick) return;\n this._serverTick = tick;\n this._tickKeeper.setServerTick(tick);\n if (!this._pending || tick > this._pending.t) {\n this._pending = { t: tick, entities, hostInput };\n }\n });\n\n // Drop input state for departed peers\n transport.onPeerLeave(() => {\n this._inputs.setPeerIds(this._transport.peers);\n });\n }\n\n // ── Wiring ──\n\n /** Set the game simulation callback (forward sim + rollback resim). */\n setPhysicsStep(cb: PhysicsStepCallback): void {\n this._onPhysicsStep = cb;\n }\n\n /** Set the world driver used for forward stepping and rollback. */\n setWorldDriver(driver: PredictionWorldDriver): void {\n this._worldDriver = driver;\n }\n\n // ── Input ──\n\n /** Set the local player's input. PERSISTS across ticks until replaced. */\n setInput(input: PlayerInput): void {\n this._currentInput = input;\n }\n\n /** Local input stored at the given tick (neutral fallback). Used by the host to embed `hi`. */\n getLocalInput(tick: number): PlayerInput {\n return this._inputs.getTick(tick);\n }\n\n // ── Frame lifecycle ──\n\n /**\n * Apply the newest pending server snapshot (full-world rollback).\n * Call once per render frame BEFORE tickKeeper.update().\n * No-op on host or when nothing is pending.\n */\n beginFrame(): void {\n if (this._transport.isHost || !this._pending) return;\n\n const pending = this._pending;\n this._pending = null;\n this._lastAppliedServerTick = pending.t;\n\n // Consume the host's embedded input: last-known AND tick history at the snapshot tick\n if (pending.hostInput !== undefined) {\n this._inputs.setRemote(\n this._transport.hostId,\n pending.hostInput,\n pending.t,\n );\n }\n\n // Rollback is impossible without world access (bookkeeping above still happened)\n if (!this._worldDriver) return;\n\n const result = applyRollback({\n serverTick: pending.t,\n serverState: pending.entities,\n localTick: this._tickKeeper.tick,\n localPeerId: this._transport.peerId,\n inputs: this._inputs,\n currentErrors: this._errors,\n driver: this._worldDriver,\n callback: this._onPhysicsStep,\n dt: this._tickKeeper.tickDelta,\n driftTargetTicks: this._options.driftTargetTicks,\n maxRewindTicks: this._options.maxRewindTicks,\n snapThreshold: this._options.snapThreshold,\n });\n this._errors = result.errors;\n if (result.newLocalTick !== this._tickKeeper.tick) {\n this._tickKeeper.snapTick(result.newLocalTick);\n }\n }\n\n /**\n * Run one forward fixed tick (host AND client): store + broadcast input,\n * build per-tick input maps, invoke the callback, then step the world.\n */\n tick(tick: number): void {\n const localInput = this._currentInput ?? { ...this._options.neutralInput };\n\n // Store a copy so each tick gets its own history entry\n this._inputs.storeTick(tick, localInput);\n\n // Broadcast to ALL peers every tick (reliable-ordered guarantees tick history)\n this._inputChannel.send({\n t: tick,\n i: localInput,\n p: this._transport.peerId,\n });\n\n // Build per-tick maps: last-known remote inputs (hold-last-input extrapolation)\n const prevTick = tick - 1;\n const tickInputs = this._inputs.allRemotes();\n tickInputs.delete(this._transport.peerId); // defensive: never simulate self as remote\n const justPressed = new Map<string, PlayerInput>();\n for (const [peerId, inp] of tickInputs) {\n justPressed.set(\n peerId,\n computeJustPressed(inp, this._inputs.getRemoteAtTick(peerId, prevTick)),\n );\n }\n tickInputs.set(this._transport.peerId, localInput);\n justPressed.set(\n this._transport.peerId,\n this._inputs.hasTick(prevTick)\n ? computeJustPressed(localInput, this._inputs.getTick(prevTick))\n : this._inputs.getJustPressedZero(), // suppress spurious edges after snap/rejoin\n );\n\n if (this._onPhysicsStep) {\n this._onPhysicsStep(\n tickInputs,\n justPressed,\n tick,\n false,\n this._tickKeeper.tickDelta,\n );\n }\n\n // Callback first (applies forces), then step\n this._worldDriver?.stepWorld?.();\n }\n\n /**\n * Decay stored error offsets and return the portion to ADD to rendered\n * transforms this frame. Call exactly once per render frame.\n */\n getRenderErrorOffsets(): Map<string, ErrorOffset> {\n const result = new Map<string, ErrorOffset>();\n const decay = this._options.errorDecay;\n const maxErr = this._options.maxErrorPerFrame;\n\n for (const [id, e] of this._errors) {\n // Decay\n e.x *= decay;\n e.y *= decay;\n e.z *= decay;\n e.a *= decay;\n let q = quatScaleAngle({ x: e.qx, y: e.qy, z: e.qz, w: e.qw }, decay);\n\n // Zero-clamp\n if (Math.abs(e.x) < 0.1) e.x = 0;\n if (Math.abs(e.y) < 0.1) e.y = 0;\n if (Math.abs(e.z) < 0.1) e.z = 0;\n if (Math.abs(e.a) < 0.001) e.a = 0;\n if (quatAngle(q) < 0.001) q = { x: 0, y: 0, z: 0, w: 1 };\n e.qx = q.x;\n e.qy = q.y;\n e.qz = q.z;\n e.qw = q.w;\n\n // Applied portion (position cap only; angular error always applied in full)\n let ax = e.x;\n let ay = e.y;\n let az = e.z;\n if (maxErr > 0) {\n const mag = Math.hypot(e.x, e.y, e.z);\n if (mag > maxErr) {\n const s = maxErr / mag;\n ax = e.x * s;\n ay = e.y * s;\n az = e.z * s;\n e.x -= ax;\n e.y -= ay;\n e.z -= az;\n } else {\n // Fully applied and consumed\n e.x = 0;\n e.y = 0;\n e.z = 0;\n }\n }\n\n const quatIsIdentity =\n e.qx === 0 && e.qy === 0 && e.qz === 0 && e.qw === 1;\n\n if (ax !== 0 || ay !== 0 || az !== 0 || e.a !== 0 || !quatIsIdentity) {\n result.set(id, {\n x: ax,\n y: ay,\n z: az,\n a: e.a,\n qx: e.qx,\n qy: e.qy,\n qz: e.qz,\n qw: e.qw,\n });\n }\n\n if (e.x === 0 && e.y === 0 && e.z === 0 && e.a === 0 && quatIsIdentity) {\n this._errors.delete(id);\n }\n }\n\n return result;\n }\n\n // ── State ──\n\n /** Tick of the newest RECEIVED snapshot. */\n get serverTick(): number {\n return this._serverTick;\n }\n\n /** Tick of the newest APPLIED (rolled-back) snapshot, 0 initially. */\n get lastAppliedServerTick(): number {\n return this._lastAppliedServerTick;\n }\n\n destroy(): void {\n this._inputChannel.close();\n this._inputs.clear();\n this._errors.clear();\n this._pending = null;\n this._currentInput = null;\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":["import_react","import_react","import_react","import_react","import_react","import_react","import_react","IDENTITY_QUAT","import_react","import_react"]}