import * as React from "react"; import { FunctionComponent, useEffect, useState } from "react"; import BoardView from "./components/BoardView"; import { context } from "./context"; import { RTMTWS } from "./rtmt/rtmt_websocket"; import { channel_game_move, channel_leave_game, channel_on_game_update, channel_on_game_user_leave, } from "./channel_names"; import Button from "./components/Button"; import InfoPanel from "./components/InfoPanel"; import { CommonMancalaGame, MancalaGame, Pit } from "mancala.js"; import { GameMove } from "./models/GameMove"; type ConnectionState = "connecting" | "error" | "connected" | "reconnecting"; const Home: FunctionComponent<{ initial?: number }> = ({ initial = 0 }) => { const [userKey, setUserKey] = useState(undefined); const [connectionState, setConnetionState] = useState("connecting"); const [searchingOpponent, setSearchingOpponent] = useState(false); const [game, setGame] = useState(undefined); const gameRef = React.useRef(game); const [crashMessage, setCrashMessage] = useState(undefined); const [userKeyWhoLeave, setUserKeyWhoLeave] = useState(undefined); const [animationPitIndex, setAnimationPitIndex] = useState(-1); const [intervalId, setIntervalId] = useState(-1); useEffect(() => { gameRef.current = game; }); const onConnectionDone = () => { setConnetionState("connected"); }; const onConnectionLost = () => { connectToServer("reconnecting"); }; const onConnectionError = (event: Event) => { setConnetionState("error"); }; const connectToServer = (connectionState: ConnectionState) => { setConnetionState(connectionState); context.userKeyStore.getUserKey((userKey: string) => { setUserKey(userKey); const rtmtws = context.rtmt as RTMTWS; if (rtmtws) { rtmtws.initWebSocket( userKey, onConnectionDone, onConnectionLost, onConnectionError ); } else { console.error("context.rtmt is not RTMTWS"); } }); }; const listenMessages = () => { context.rtmt.listenMessage(channel_on_game_update, (message: Object) => { const newGame: CommonMancalaGame = message as CommonMancalaGame; const mancalaGame = MancalaGame.createFromMancalaGame(newGame); if (gameRef.current && mancalaGame.history.length > 0) { const lastHistoryItem = mancalaGame.history[mancalaGame.history.length - 1]; if (lastHistoryItem.gameSteps.length > 0) { let stepIndex = 0; if (intervalId) { clearInterval(intervalId); } const id = setInterval(() => { if (stepIndex === lastHistoryItem.gameSteps.length) { clearInterval(id); setAnimationPitIndex(-1); setGame(mancalaGame); } else { const gameStep = lastHistoryItem.gameSteps[stepIndex]; const index = mancalaGame.board.getPitIndexCircularly( gameStep.index ); setAnimationPitIndex(index); } stepIndex++; }, 250); setIntervalId(intervalId); } } }); context.rtmt.listenMessage("on_game_start", (message: Object) => { const newGame: CommonMancalaGame = message as CommonMancalaGame; setSearchingOpponent(false); setGame(MancalaGame.createFromMancalaGame(newGame)); }); context.rtmt.listenMessage("on_game_crashed", (message: any) => { const newCrashMessage = message as string; console.error("on_game_crash"); console.error(newCrashMessage); setCrashMessage(newCrashMessage); }); context.rtmt.listenMessage(channel_on_game_user_leave, (message: any) => { const userKeyWhoLeave = message; setUserKeyWhoLeave(userKeyWhoLeave); }); }; React.useEffect(() => { listenMessages(); connectToServer("connecting"); }, []); const resetGameState = () => { setGame(undefined); setCrashMessage(undefined); setUserKeyWhoLeave(undefined); }; const newGameClick = () => { resetGameState(); setSearchingOpponent(true); context.rtmt.sendMessage("new_game", {}); }; const leaveGame = () => { context.rtmt.sendMessage(channel_leave_game, {}); }; const onHoleSelect = (index: number, hole: Pit) => { const gameMove: GameMove = { index: index }; context.rtmt.sendMessage(channel_game_move, gameMove); }; const showConnectionState = connectionState != "connected"; const connectionStateText = () => { let map: { [key: string]: string } = { connecting: context.texts.Connecting, connected: context.texts.Connected, error: context.texts.CannotConnect, reconnecting: context.texts.ConnectingAgain, }; return map[connectionState]; }; const renderNewGameButton = () => { const newGame = (