From 3535c519604e608db1c8ef1baac3fb6333f91823 Mon Sep 17 00:00:00 2001 From: Nathan Mande Date: Sun, 1 Dec 2024 20:21:06 +0200 Subject: [PATCH] refactor(web): use routing to start games --- apps/web/src/app.tsx | 22 ++-- apps/web/src/routes/home.route.tsx | 17 ++- apps/web/src/routes/play.route.tsx | 25 ++++ .../src/shared/components/game.component.tsx | 85 -------------- .../shared/components/main-menu.component.tsx | 111 ++++++++++++------ apps/web/src/shared/enum/game.enum.ts | 6 +- apps/web/src/shared/enum/index.ts | 1 + apps/web/src/shared/hooks/use-game.hook.ts | 73 ++++++------ apps/web/src/shared/layouts/index.ts | 1 + apps/web/src/shared/layouts/main.layout.tsx | 12 ++ apps/web/src/shared/stores/game.store.ts | 12 -- .../utils/{events.ts => events.util.ts} | 0 apps/web/src/shared/utils/index.ts | 3 +- apps/web/src/shared/utils/url.util.ts | 13 ++ 14 files changed, 196 insertions(+), 185 deletions(-) create mode 100644 apps/web/src/routes/play.route.tsx delete mode 100644 apps/web/src/shared/components/game.component.tsx create mode 100644 apps/web/src/shared/layouts/index.ts create mode 100644 apps/web/src/shared/layouts/main.layout.tsx delete mode 100644 apps/web/src/shared/stores/game.store.ts rename apps/web/src/shared/utils/{events.ts => events.util.ts} (100%) create mode 100644 apps/web/src/shared/utils/url.util.ts diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx index 710337f..5b713a5 100644 --- a/apps/web/src/app.tsx +++ b/apps/web/src/app.tsx @@ -1,15 +1,17 @@ -import { FC } from "react"; -import { Routes as NativeRoutes, Route } from "react-router"; +import { FC, Fragment } from "react"; +import { Routes, Route } from "react-router"; -import { MainMenuComponent } from "./shared/components"; +import { MainLayout } from "./shared/layouts"; import { HomeRoute } from "./routes/home.route"; +import { PlayRoute } from "./routes/play.route"; export const App: FC = () => ( - <> - - } /> - - - - + + + }> + } /> + } /> + + + ); diff --git a/apps/web/src/routes/home.route.tsx b/apps/web/src/routes/home.route.tsx index 00667c0..61673da 100644 --- a/apps/web/src/routes/home.route.tsx +++ b/apps/web/src/routes/home.route.tsx @@ -1,21 +1,32 @@ import { useMainMenuStore } from "../shared/stores"; export const HomeRoute = () => { - const { openMenu } = useMainMenuStore(); + const { openMenu, openNewGameSection } = useMainMenuStore(); return (

Chess Dimension

-

Basic 3D chess game built with Three.js

+

+ 3D chess game built with{" "} + Three.js +

+ + + Or open the main menu with{" "} + Esc +
); }; diff --git a/apps/web/src/routes/play.route.tsx b/apps/web/src/routes/play.route.tsx new file mode 100644 index 0000000..47242b0 --- /dev/null +++ b/apps/web/src/routes/play.route.tsx @@ -0,0 +1,25 @@ +import { FC, useCallback, useEffect, useMemo } from "react"; + +import { useGame } from "../shared/hooks"; +import { getGameModeFromUrl } from "../shared/utils"; +import { useLocation } from "react-router"; + +export const PlayRoute: FC = () => { + const location = useLocation(); + + const { state: gameState, init: initGame, dispose: disposeGame } = useGame(); + + useEffect(() => { + if (!gameState.app && !gameState.isPending && !gameState.isReady) { + getGameModeFromUrl(); + initGame(); + } + + return () => { + if (gameState.app && !gameState.isPending && gameState.isReady) + disposeGame(); + }; + }, [disposeGame, gameState, initGame, location]); + + return null; +}; diff --git a/apps/web/src/shared/components/game.component.tsx b/apps/web/src/shared/components/game.component.tsx deleted file mode 100644 index 20f387b..0000000 --- a/apps/web/src/shared/components/game.component.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { SOCKET_PERFORM_MOVE_TOKEN } from "@chess-d/shared"; -import { FC, useEffect, useMemo } from "react"; -import { merge, Subscription } from "rxjs"; - -import { useAi, useGame, useSocket } from "../hooks"; -import { PlayerModel } from "../models"; - -export const GameComponent: FC = () => { - const { - setup: setupGame, - app, - movePiece, - gameUpdatedCallbackRegister - } = useGame(); - const { - setup: setupAI, - workerThread: aiWorkerThread, - player: opponentPlayer - } = useAi(); - const { socket } = useSocket(); - - // TODO: Players color should be defined by the user. - const currentPlayer = useMemo(() => new PlayerModel(), []); - - // Setting up the game. - useEffect(() => { - if (!app) setupGame(); - }, [app, setupGame]); - - // Setting up the AI player. - useEffect(() => { - if (app && !aiWorkerThread) setupAI(app); - - return () => { - aiWorkerThread?.worker?.terminate?.(); - }; - }, [app, setupAI, aiWorkerThread]); - - // Setting up the socket player. - useEffect(() => { - if (app && !socket.connected) { - socket.connect(); - socket.on("disconnect", (reason, description) => { - console.log("disconnect ==>", reason, description); - }); - } - - return () => { - socket.disconnect(); - }; - }, [app, socket]); - - // Setting up the socket player. - useEffect(() => { - let playersActionsSubscription: Subscription | undefined; - if (currentPlayer && opponentPlayer) - playersActionsSubscription = merge( - currentPlayer.pieceMoved$$, - opponentPlayer.pieceMoved$$ - ).subscribe((move) => { - movePiece(move); - }); - - return () => { - playersActionsSubscription?.unsubscribe(); - }; - }, [currentPlayer, movePiece, opponentPlayer]); - - useEffect(() => { - gameUpdatedCallbackRegister((payload) => { - console.log("Game updated", payload); - opponentPlayer?.notify$$?.next(payload); - currentPlayer?.notify$$?.next(payload); - - socket?.emit(SOCKET_PERFORM_MOVE_TOKEN, payload); - }); - }, [ - currentPlayer?.notify$$, - opponentPlayer?.notify$$, - gameUpdatedCallbackRegister, - socket - ]); - - return null; -}; diff --git a/apps/web/src/shared/components/main-menu.component.tsx b/apps/web/src/shared/components/main-menu.component.tsx index 4a31439..93eb808 100644 --- a/apps/web/src/shared/components/main-menu.component.tsx +++ b/apps/web/src/shared/components/main-menu.component.tsx @@ -1,17 +1,45 @@ -import { FC } from "react"; -import { Link, useBeforeUnload } from "react-router"; +import { FC, useCallback, useEffect } from "react"; +import { Link, useLocation } from "react-router"; -import { useMainMenuStore } from "../stores"; +import { GameMode } from "../enum"; import { stopEventPropagation } from "../utils"; +import { useMainMenuStore } from "../stores"; export interface MainMenuComponentProps {} +/** @internal */ +const GameModeOptions: { + label: string; + title: string; + mode: keyof typeof GameMode; +}[] = [ + { label: "AI", mode: "ai", title: "Play against the computer" }, + { + label: "Human", + mode: "human", + title: "Play against another human player" + }, + { label: "Free Mode", mode: "free", title: "Play against yourself" }, + { + label: "Simulation", + mode: "simulation", + title: "Watch the AIs playing against each other" + } +]; + /** @internal */ const MainSection: FC = () => { const { openNewGameSection } = useMainMenuStore(); return (