diff --git a/apps/api/src/ws/handlers/gameHandlers.ts b/apps/api/src/ws/handlers/gameHandlers.ts index 5ced050..ee06ce8 100644 --- a/apps/api/src/ws/handlers/gameHandlers.ts +++ b/apps/api/src/ws/handlers/gameHandlers.ts @@ -1,6 +1,6 @@ import type { WebSocket } from "ws"; import type { User } from "better-auth"; -import type { WsGameAnswer, WsGameReady } from "@lila/shared"; +import type { WsGameAnswer } from "@lila/shared"; import { finishGame, getLobbyByCodeWithPlayers } from "@lila/db"; import { broadcastToLobby, getConnections } from "../connections.js"; import { lobbyGameStore, timers } from "../gameState.js"; @@ -52,32 +52,6 @@ export const handleGameAnswer = async ( } }; -export const handleGameReady = async ( - ws: WebSocket, - msg: WsGameReady, - _user: User, -): Promise => { - const state = await lobbyGameStore.get(msg.lobbyId); - if (!state) throw new NotFoundError("Game not found"); - - const currentQuestion = state.questions[state.currentIndex]; - if (!currentQuestion) throw new NotFoundError("No active question"); - - ws.send( - JSON.stringify({ - type: "game:question", - question: { - questionId: currentQuestion.questionId, - prompt: currentQuestion.prompt, - gloss: currentQuestion.gloss, - options: currentQuestion.options, - }, - questionNumber: state.currentIndex + 1, - totalQuestions: state.questions.length, - }), - ); -}; - export const resolveRound = async ( lobbyId: string, questionIndex: number, diff --git a/apps/api/src/ws/router.ts b/apps/api/src/ws/router.ts index d4b04f4..1a1dad4 100644 --- a/apps/api/src/ws/router.ts +++ b/apps/api/src/ws/router.ts @@ -6,7 +6,7 @@ import { handleLobbyLeave, handleLobbyStart, } from "./handlers/lobbyHandlers.js"; -import { handleGameAnswer, handleGameReady } from "./handlers/gameHandlers.js"; +import { handleGameAnswer } from "./handlers/gameHandlers.js"; import { AppError } from "../errors/AppError.js"; export type AuthenticatedUser = { session: Session; user: User }; @@ -60,9 +60,6 @@ export const handleMessage = async ( case "game:answer": await handleGameAnswer(ws, msg, auth.user); break; - case "game:ready": - await handleGameReady(ws, msg, auth.user); - break; default: assertExhaustive(msg); } diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts index 96c3044..ce1cdf1 100644 --- a/apps/web/src/routeTree.gen.ts +++ b/apps/web/src/routeTree.gen.ts @@ -10,24 +10,15 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as PlayRouteImport } from './routes/play' -import { Route as MultiplayerRouteImport } from './routes/multiplayer' import { Route as LoginRouteImport } from './routes/login' import { Route as AboutRouteImport } from './routes/about' import { Route as IndexRouteImport } from './routes/index' -import { Route as MultiplayerIndexRouteImport } from './routes/multiplayer/index' -import { Route as MultiplayerLobbyCodeRouteImport } from './routes/multiplayer/lobby.$code' -import { Route as MultiplayerGameCodeRouteImport } from './routes/multiplayer/game.$code' const PlayRoute = PlayRouteImport.update({ id: '/play', path: '/play', getParentRoute: () => rootRouteImport, } as any) -const MultiplayerRoute = MultiplayerRouteImport.update({ - id: '/multiplayer', - path: '/multiplayer', - getParentRoute: () => rootRouteImport, -} as any) const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', @@ -43,89 +34,38 @@ const IndexRoute = IndexRouteImport.update({ path: '/', getParentRoute: () => rootRouteImport, } as any) -const MultiplayerIndexRoute = MultiplayerIndexRouteImport.update({ - id: '/', - path: '/', - getParentRoute: () => MultiplayerRoute, -} as any) -const MultiplayerLobbyCodeRoute = MultiplayerLobbyCodeRouteImport.update({ - id: '/lobby/$code', - path: '/lobby/$code', - getParentRoute: () => MultiplayerRoute, -} as any) -const MultiplayerGameCodeRoute = MultiplayerGameCodeRouteImport.update({ - id: '/game/$code', - path: '/game/$code', - getParentRoute: () => MultiplayerRoute, -} as any) export interface FileRoutesByFullPath { '/': typeof IndexRoute '/about': typeof AboutRoute '/login': typeof LoginRoute - '/multiplayer': typeof MultiplayerRouteWithChildren '/play': typeof PlayRoute - '/multiplayer/': typeof MultiplayerIndexRoute - '/multiplayer/game/$code': typeof MultiplayerGameCodeRoute - '/multiplayer/lobby/$code': typeof MultiplayerLobbyCodeRoute } export interface FileRoutesByTo { '/': typeof IndexRoute '/about': typeof AboutRoute '/login': typeof LoginRoute '/play': typeof PlayRoute - '/multiplayer': typeof MultiplayerIndexRoute - '/multiplayer/game/$code': typeof MultiplayerGameCodeRoute - '/multiplayer/lobby/$code': typeof MultiplayerLobbyCodeRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/about': typeof AboutRoute '/login': typeof LoginRoute - '/multiplayer': typeof MultiplayerRouteWithChildren '/play': typeof PlayRoute - '/multiplayer/': typeof MultiplayerIndexRoute - '/multiplayer/game/$code': typeof MultiplayerGameCodeRoute - '/multiplayer/lobby/$code': typeof MultiplayerLobbyCodeRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: - | '/' - | '/about' - | '/login' - | '/multiplayer' - | '/play' - | '/multiplayer/' - | '/multiplayer/game/$code' - | '/multiplayer/lobby/$code' + fullPaths: '/' | '/about' | '/login' | '/play' fileRoutesByTo: FileRoutesByTo - to: - | '/' - | '/about' - | '/login' - | '/play' - | '/multiplayer' - | '/multiplayer/game/$code' - | '/multiplayer/lobby/$code' - id: - | '__root__' - | '/' - | '/about' - | '/login' - | '/multiplayer' - | '/play' - | '/multiplayer/' - | '/multiplayer/game/$code' - | '/multiplayer/lobby/$code' + to: '/' | '/about' | '/login' | '/play' + id: '__root__' | '/' | '/about' | '/login' | '/play' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute AboutRoute: typeof AboutRoute LoginRoute: typeof LoginRoute - MultiplayerRoute: typeof MultiplayerRouteWithChildren PlayRoute: typeof PlayRoute } @@ -138,13 +78,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof PlayRouteImport parentRoute: typeof rootRouteImport } - '/multiplayer': { - id: '/multiplayer' - path: '/multiplayer' - fullPath: '/multiplayer' - preLoaderRoute: typeof MultiplayerRouteImport - parentRoute: typeof rootRouteImport - } '/login': { id: '/login' path: '/login' @@ -166,51 +99,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRouteImport } - '/multiplayer/': { - id: '/multiplayer/' - path: '/' - fullPath: '/multiplayer/' - preLoaderRoute: typeof MultiplayerIndexRouteImport - parentRoute: typeof MultiplayerRoute - } - '/multiplayer/lobby/$code': { - id: '/multiplayer/lobby/$code' - path: '/lobby/$code' - fullPath: '/multiplayer/lobby/$code' - preLoaderRoute: typeof MultiplayerLobbyCodeRouteImport - parentRoute: typeof MultiplayerRoute - } - '/multiplayer/game/$code': { - id: '/multiplayer/game/$code' - path: '/game/$code' - fullPath: '/multiplayer/game/$code' - preLoaderRoute: typeof MultiplayerGameCodeRouteImport - parentRoute: typeof MultiplayerRoute - } } } -interface MultiplayerRouteChildren { - MultiplayerIndexRoute: typeof MultiplayerIndexRoute - MultiplayerGameCodeRoute: typeof MultiplayerGameCodeRoute - MultiplayerLobbyCodeRoute: typeof MultiplayerLobbyCodeRoute -} - -const MultiplayerRouteChildren: MultiplayerRouteChildren = { - MultiplayerIndexRoute: MultiplayerIndexRoute, - MultiplayerGameCodeRoute: MultiplayerGameCodeRoute, - MultiplayerLobbyCodeRoute: MultiplayerLobbyCodeRoute, -} - -const MultiplayerRouteWithChildren = MultiplayerRoute._addFileChildren( - MultiplayerRouteChildren, -) - const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, AboutRoute: AboutRoute, LoginRoute: LoginRoute, - MultiplayerRoute: MultiplayerRouteWithChildren, PlayRoute: PlayRoute, } export const routeTree = rootRouteImport diff --git a/apps/web/src/routes/multiplayer.tsx b/apps/web/src/routes/multiplayer.tsx deleted file mode 100644 index 9acb22f..0000000 --- a/apps/web/src/routes/multiplayer.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { createFileRoute, Outlet, redirect } from "@tanstack/react-router"; -import { WsProvider } from "../lib/ws-provider.js"; -import { authClient } from "../lib/auth-client.js"; - -export const Route = createFileRoute("/multiplayer")({ - component: MultiplayerLayout, - beforeLoad: async () => { - const { data: session } = await authClient.getSession(); - if (!session) { - throw redirect({ to: "/login" }); - } - }, -}); - -function MultiplayerLayout() { - return ( - - - - ); -} diff --git a/apps/web/src/routes/multiplayer/game.$code.tsx b/apps/web/src/routes/multiplayer/game.$code.tsx deleted file mode 100644 index 2b46605..0000000 --- a/apps/web/src/routes/multiplayer/game.$code.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/multiplayer/game/$code')({ - component: RouteComponent, -}) - -function RouteComponent() { - return
Hello "/multiplayer/game/$code"!
-} diff --git a/apps/web/src/routes/multiplayer/index.tsx b/apps/web/src/routes/multiplayer/index.tsx deleted file mode 100644 index 55f2da6..0000000 --- a/apps/web/src/routes/multiplayer/index.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import { useState } from "react"; -import type { Lobby } from "@lila/shared"; - -const API_URL = (import.meta.env["VITE_API_URL"] as string) || ""; - -type LobbySuccessResponse = { success: true; data: Lobby }; -type LobbyErrorResponse = { success: false; error: string }; -type LobbyApiResponse = LobbySuccessResponse | LobbyErrorResponse; - -export const Route = createFileRoute("/multiplayer/")({ - component: MultiplayerPage, -}); - -function MultiplayerPage() { - const navigate = useNavigate(); - const [joinCode, setJoinCode] = useState(""); - const [isCreating, setIsCreating] = useState(false); - const [isJoining, setIsJoining] = useState(false); - const [error, setError] = useState(null); - - const handleCreate = async (): Promise => { - setIsCreating(true); - setError(null); - try { - const response = await fetch(`${API_URL}/api/v1/lobbies`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - credentials: "include", - }); - const data = (await response.json()) as LobbyApiResponse; - if (!data.success) { - setError(data.error); - return; - } - void navigate({ - to: "/multiplayer/lobby/$code", - params: { code: data.data.code }, - }); - } catch { - setError("Could not connect to server. Please try again."); - } finally { - setIsCreating(false); - } - }; - - const handleJoin = async (): Promise => { - const code = joinCode.trim().toUpperCase(); - if (!code) { - setError("Please enter a lobby code."); - return; - } - setIsJoining(true); - setError(null); - try { - const response = await fetch(`${API_URL}/api/v1/lobbies/${code}/join`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - credentials: "include", - }); - const data = (await response.json()) as LobbyApiResponse; - if (!data.success) { - setError(data.error); - return; - } - void navigate({ - to: "/multiplayer/lobby/$code", - params: { code: data.data.code }, - }); - } catch { - setError("Could not connect to server. Please try again."); - } finally { - setIsJoining(false); - } - }; - - return ( -
-
-

- Multiplayer -

- - {error &&

{error}

} - - {/* Create lobby */} -
-

- Create a lobby -

-

- Start a new game and invite friends with a code. -

- -
- -
- - {/* Join lobby */} -
-

Join a lobby

-

- Enter the code shared by your host. -

- setJoinCode(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter") { - void handleJoin().catch((err) => { - console.error("Join lobby error:", err); - }); - } - }} - maxLength={10} - disabled={isCreating || isJoining} - /> - -
-
-
- ); -} diff --git a/apps/web/src/routes/multiplayer/lobby.$code.tsx b/apps/web/src/routes/multiplayer/lobby.$code.tsx deleted file mode 100644 index 32d44d9..0000000 --- a/apps/web/src/routes/multiplayer/lobby.$code.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/multiplayer/lobby/$code')({ - component: RouteComponent, -}) - -function RouteComponent() { - return
Hello "/multiplayer/lobby/$code"!
-} diff --git a/packages/shared/src/schemas/lobby.ts b/packages/shared/src/schemas/lobby.ts index 7b7b7d5..b2e3c55 100644 --- a/packages/shared/src/schemas/lobby.ts +++ b/packages/shared/src/schemas/lobby.ts @@ -52,12 +52,6 @@ export const WsLobbyStartSchema = z.object({ export type WsLobbyStart = z.infer; -export const WsGameReadySchema = z.object({ - type: z.literal("game:ready"), - lobbyId: z.uuid(), -}); -export type WsGameReady = z.infer; - export const WsGameAnswerSchema = z.object({ type: z.literal("game:answer"), lobbyId: z.uuid(), @@ -72,7 +66,6 @@ export const WsClientMessageSchema = z.discriminatedUnion("type", [ WsLobbyLeaveSchema, WsLobbyStartSchema, WsGameAnswerSchema, - WsGameReadySchema, ]); export type WsClientMessage = z.infer;