UNPKG

@lobstar/preact

Version:

A collection of Preact hooks to use Lobstar library for network and lobby management for multiplayer web games

174 lines (173 loc) 6.47 kB
import { useRef, useEffect, useCallback, useState } from "preact/hooks"; import { GameSessionManager, SESSION_STATES, } from "@lobstar/core"; const createSessionId = () => { return Math.random().toString(36).substring(2, 9); }; /** * Core hook that initializes and provides access to the GameSessionManager */ export function useGameSession(options) { const sessionRef = useRef(null); const [sessionId, setSessionId] = useState(createSessionId()); const debug = options?.debug || false; // Only track session state here, leave player tracking to usePlayers const [sessionState, setSessionState] = useState(SESSION_STATES.DISCONNECTED); const log = useCallback((message) => { if (debug) { console.log(`[useGameSession:${sessionId}] ${message}`); } }, [debug, sessionId]); // Function to reset the session completely const resetSession = useCallback(() => { log("Resetting session - forcing new session manager on next use"); if (sessionRef.current) { log("Calling leave() on current session before reset"); sessionRef.current.leave(); sessionRef.current = null; } // Reset session state setSessionState(SESSION_STATES.DISCONNECTED); // Create a new session instance setSessionId(createSessionId()); }, [log]); useEffect(() => { // Initialize the session manager log("Initializing new GameSessionManager"); sessionRef.current = new GameSessionManager(options); // Setup event listeners for debugging const unsubScribeState = sessionRef.current.on("stateChange", ({ state, previousState }) => { log(`State changed: ${previousState} -> ${state}`); setSessionState(state); }); const unsubPlayersUpdate = sessionRef.current.on("playersUpdate", ({ players: updatedPlayers }) => { log(`Players updated: ${Object.keys(updatedPlayers).length} players`); log(`Players: ${JSON.stringify(Object.values(updatedPlayers).map((p) => ({ id: p.id, name: p.name, ready: p.isReady })))}`); }); const unsubKicked = sessionRef.current.on("kicked", () => { log("Player was kicked from session - forcing session reset"); resetSession(); }); // Clean up on unmount return () => { log("Component unmounting, cleaning up session"); // Unsubscribe from all events unsubScribeState(); unsubPlayersUpdate(); unsubKicked(); if (sessionRef.current) { log("Calling leave() on session manager"); sessionRef.current.leave(); sessionRef.current = null; } }; }, [log, sessionId, resetSession]); const host = useCallback(async (playerName, lobbyId) => { if (!sessionRef.current) { log("Cannot host: sessionRef is null"); return ""; } log(`Hosting game as "${playerName}" ${lobbyId ? `with lobby ID ${lobbyId}` : "with generated ID"}`); try { return await sessionRef.current.host(playerName, lobbyId); } catch (error) { resetSession(); throw error; } }, [log, resetSession]); const join = useCallback(async (lobbyId, playerName) => { if (!sessionRef.current) { log("Cannot join: sessionRef is null"); return; } log(`Joining lobby ${lobbyId} as "${playerName}"`); try { await sessionRef.current.join(lobbyId, playerName); } catch (error) { resetSession(); throw error; } }, [log, resetSession]); const leave = useCallback(() => { if (!sessionRef.current) { log("Cannot leave: sessionRef is null"); return; } log("Leaving session"); sessionRef.current.leave(); // Force recreation of the session manager on next use resetSession(); }, [log, resetSession]); const setReady = useCallback((isReady) => { if (!sessionRef.current) { log(`Cannot set ready to ${isReady}: sessionRef is null`); return; } log(`Setting ready state to ${isReady}`); sessionRef.current.setReady(isReady); }, [log]); const startGame = useCallback(() => { if (!sessionRef.current) { log("Cannot start game: sessionRef is null"); return; } log("Starting game"); sessionRef.current.startGame(); }, [log]); const endGame = useCallback(() => { if (!sessionRef.current) { log("Cannot end game: sessionRef is null"); return; } log("Ending game"); sessionRef.current.endGame(); }, [log]); const kickPlayer = useCallback((playerId) => { if (!sessionRef.current) { log(`Cannot kick player ${playerId}: sessionRef is null`); return; } log(`Kicking player ${playerId}`); sessionRef.current.kickPlayer(playerId); }, [log]); const sendMessage = useCallback((peerId, data) => { if (!sessionRef.current) { log(`Cannot send message to ${peerId}: sessionRef is null`); return; } log(`Sending message to ${peerId}`); sessionRef.current.sendMessage(peerId, data); }, [log]); const sendMessageToHost = useCallback((data) => { if (!sessionRef.current) { log("Cannot send message to host: sessionRef is null"); return; } log("Sending message to host"); sessionRef.current.sendMessageToHost(data); }, [log]); const broadcastMessage = useCallback((data, excludeSelf) => { if (!sessionRef.current) { log("Cannot broadcast message: sessionRef is null"); return; } log(`Broadcasting message ${excludeSelf ? "(excluding self)" : ""}`); sessionRef.current.broadcastMessage(data, excludeSelf); }, [log]); return { session: sessionRef.current, host, join, leave, setReady, startGame, endGame, kickPlayer, sendMessage, sendMessageToHost, broadcastMessage, // Only expose session state here sessionState, }; }