From b067747d48348ebf97bb2350fcc75f578d71a666 Mon Sep 17 00:00:00 2001 From: aronmal Date: Sun, 3 Sep 2023 18:48:06 +0200 Subject: [PATCH] Fix some game logic --- .../src/components/FontAwesomeIcon.tsx | 4 +- .../src/components/Gamefield/EventBar.tsx | 4 +- .../src/components/Gamefield/Gamefield.tsx | 6 --- .../components/Gamefield/GamefieldPointer.tsx | 3 +- .../src/components/Gamefield/Ships.tsx | 2 +- .../src/components/Gamefield/Targets.tsx | 6 +-- leaky-ships/src/hooks/useGameProps.ts | 14 ------ leaky-ships/src/hooks/useSession.tsx | 43 ++++++++++++------- leaky-ships/src/hooks/useSocket.ts | 31 ++++--------- leaky-ships/src/interfaces/ApiSocket.ts | 6 +-- leaky-ships/src/lib/backend/sendResponse.ts | 1 + leaky-ships/src/lib/getPayloadFromProps.ts | 2 - leaky-ships/src/lib/zodSchemas.ts | 1 - leaky-ships/src/routes/api/game/running.ts | 40 +++++++++++++---- leaky-ships/src/routes/api/ws.ts | 25 +++++------ 15 files changed, 90 insertions(+), 98 deletions(-) diff --git a/leaky-ships/src/components/FontAwesomeIcon.tsx b/leaky-ships/src/components/FontAwesomeIcon.tsx index 4f7b248..59d8699 100644 --- a/leaky-ships/src/components/FontAwesomeIcon.tsx +++ b/leaky-ships/src/components/FontAwesomeIcon.tsx @@ -29,6 +29,8 @@ export function FontAwesomeIcon( return (
{/* */} diff --git a/leaky-ships/src/components/Gamefield/GamefieldPointer.tsx b/leaky-ships/src/components/Gamefield/GamefieldPointer.tsx index 7f8361c..fd102c9 100644 --- a/leaky-ships/src/components/Gamefield/GamefieldPointer.tsx +++ b/leaky-ships/src/components/Gamefield/GamefieldPointer.tsx @@ -20,6 +20,7 @@ function GamefieldPointer( "--y1": props.y - 1, "--y2": props.y + 2, } + return (
- +
) } diff --git a/leaky-ships/src/components/Gamefield/Ships.tsx b/leaky-ships/src/components/Gamefield/Ships.tsx index 1413010..3686cc9 100644 --- a/leaky-ships/src/components/Gamefield/Ships.tsx +++ b/leaky-ships/src/components/Gamefield/Ships.tsx @@ -7,7 +7,7 @@ function Ships() { const { isActiveIndex, selfUser } = useSession() return ( - + {(props) => } ) diff --git a/leaky-ships/src/components/Gamefield/Targets.tsx b/leaky-ships/src/components/Gamefield/Targets.tsx index 3dcf977..327c575 100644 --- a/leaky-ships/src/components/Gamefield/Targets.tsx +++ b/leaky-ships/src/components/Gamefield/Targets.tsx @@ -13,8 +13,8 @@ import Ship from "./Ship" function Targets() { const { activeUser, ships } = useSession() - const ship = shipProps(ships(), mode(), targetPreview()) - const { fields, borders, score } = intersectingShip(ships(), ship) + const ship = () => shipProps(ships(), mode(), targetPreview()) + const { fields, borders, score } = intersectingShip(ships(), ship()) return ( @@ -36,7 +36,7 @@ function Targets() { when={gameState() === "starting" && mode() >= 0 && targetPreview().show} > 0} color={fields.length ? "red" : borders.length ? "orange" : undefined} diff --git a/leaky-ships/src/hooks/useGameProps.ts b/leaky-ships/src/hooks/useGameProps.ts index 032a2cc..adc6bb5 100644 --- a/leaky-ships/src/hooks/useGameProps.ts +++ b/leaky-ships/src/hooks/useGameProps.ts @@ -25,7 +25,6 @@ import { } from "../interfaces/frontend" export const [hash, setHash] = createSignal(null) -export const [activeIndex, setActiveIndex] = createSignal<0 | 1>(0) export const [gamePin, setGamePin] = createSignal(null) export const [gameId, setGameId] = createSignal("") export const [gameState, setGameState] = createSignal("unknown") @@ -53,17 +52,6 @@ export const users = { }, } -// export function setActiveIndex(i: number, selfIndex: number) { -// if (!payload()) return -// payload().activeIndex = i -// if (i === selfIndex) { -// setMenu("moves") -// setMode(0) -// } else { -// setMenu("main") -// setMode(-1) -// } -// } export function DispatchMove(move: MoveDispatchProps, index: number) { const list = targetList(move, move.type) users.forEach((user, i) => { @@ -182,7 +170,6 @@ export function full(newProps: GamePropsSchema) { ) setHash(newProps.hash) - setActiveIndex(newProps.payload.activeIndex) setGamePin(newProps.payload.gamePin) setGameId(newProps.payload.game?.id ?? "") setGameState(newProps.payload.game?.state ?? "unknown") @@ -234,7 +221,6 @@ export function setIsConnectedFor({ export function reset() { setHash(null) - setActiveIndex(0) setGamePin(null) setGameId("") setGameState("unknown") diff --git a/leaky-ships/src/hooks/useSession.tsx b/leaky-ships/src/hooks/useSession.tsx index bdcd6c0..33641da 100644 --- a/leaky-ships/src/hooks/useSession.tsx +++ b/leaky-ships/src/hooks/useSession.tsx @@ -1,27 +1,15 @@ import { Session } from "@auth/core/types" import { getSession } from "@auth/solid-start" import { - Accessor, JSX, createContext, + createEffect, createSignal, useContext, } from "solid-js" import { createServerData$ } from "solid-start/server" -import { ShipProps } from "~/interfaces/frontend" -import { initialUser } from "~/lib/utils/helpers" import { authOptions } from "~/server/auth" -import { activeIndex, users } from "./useGameProps" - -interface Concext { - session: Accessor - selfIndex: () => 0 | 1 | -1 - activeIndex: Accessor<0 | 1> - isActiveIndex: () => boolean - selfUser: () => ReturnType | null - activeUser: () => ReturnType - ships: () => ShipProps[] -} +import { gameState, setMenu, setMode, users } from "./useGameProps" const [state, setState] = createSignal(null) const selfIndex = () => { @@ -35,15 +23,29 @@ const selfIndex = () => { } } +const activeIndex = () => { + if (gameState() !== "running") return 0 + const l1 = users[0].moves().length + const l2 = users[1].moves().length + return l1 > l2 ? 1 : 0 +} + const isActiveIndex = () => { const sI = selfIndex() return sI >= 0 && activeIndex() === sI } + const selfUser = () => { const i = selfIndex() if (i === -1) return null return users[i] } + +/** + * It should be the opposite of `activeIndex`. + * + * This is because `activeIndex` is attacking the `activeUser`. + */ const activeUser = () => users[activeIndex() === 0 ? 1 : 0] const ships = () => selfUser()?.ships() ?? [] @@ -56,7 +58,7 @@ const contextValue = { activeUser, ships, } -export const SessionCtx = createContext(contextValue) +export const SessionCtx = createContext(contextValue) export function SessionProvider(props: { children: JSX.Element }) { const session = createServerData$( @@ -67,6 +69,17 @@ export function SessionProvider(props: { children: JSX.Element }) { )() setState(session ?? null) + createEffect(() => { + if (gameState() !== "running") return + if (activeIndex() === selfIndex()) { + setMenu("moves") + setMode(0) + } else { + setMenu("main") + setMode(-1) + } + }) + return ( {props.children} diff --git a/leaky-ships/src/hooks/useSocket.ts b/leaky-ships/src/hooks/useSocket.ts index 6219231..2880de4 100644 --- a/leaky-ships/src/hooks/useSocket.ts +++ b/leaky-ships/src/hooks/useSocket.ts @@ -10,12 +10,9 @@ import { DispatchMove, full, gameId, - gameState, - setActiveIndex, + setGameState, setIsConnectedFor, setIsReadyFor, - setMenu, - setMode, setPlayer, setSetting, setShips, @@ -27,7 +24,7 @@ import { useSession } from "./useSession" function useSocket() { const [isConnectedState, setIsConnectedState] = createSignal(false) const { selfIndex } = useSession() - const navigate = useNavigate() + const navigator = useNavigate() const isConnected = () => { const i = selfIndex() @@ -54,7 +51,7 @@ function useSocket() { const connectError = (error: Error) => { console.log("Connection error:", error.message) - if (error.message === status["403"]) navigate("/") + if (error.message === status["403"]) navigator("/") if (error.message !== "xhr poll error") return // const toastId = "connect_error" // const isActive = toast.isActive(toastId) @@ -122,17 +119,6 @@ function useSocket() { }) } - const activeIndex = (i: 0 | 1) => { - setActiveIndex(i) - if (i === selfIndex()) { - setMenu("moves") - setMode(0) - } else { - setMenu("main") - setMode(-1) - } - } - const disconnect = () => { console.log("disconnect") setIsConnectedState(false) @@ -143,9 +129,8 @@ function useSocket() { socket.on("gameSetting", gameSetting) socket.on("playerEvent", playerEvent) socket.on("isReady", setIsReadyFor) - socket.on("gameState", gameState) + socket.on("gameState", setGameState) socket.on("dispatchMove", DispatchMove) - socket.on("activeIndex", activeIndex) socket.on("ships", setShips) socket.on("disconnect", disconnect) @@ -155,9 +140,8 @@ function useSocket() { socket.off("gameSetting", gameSetting) socket.off("playerEvent", playerEvent) socket.off("isReady", setIsReadyFor) - socket.off("gameState", gameState) + socket.off("gameState", setGameState) socket.off("dispatchMove", DispatchMove) - socket.off("activeIndex", activeIndex) socket.off("ships", setShips) socket.off("disconnect", disconnect) } @@ -172,7 +156,10 @@ function useSocket() { .then(isAuthenticated) .then((game) => GamePropsSchema.parse(game)) .then((res) => full(res)) - .catch((e) => console.log("Failed to get /api/game/running: ", e)) + .catch((e) => { + console.log("Failed to get /api/game/running: ", e) + navigator("/") + }) return } if (isConnected()) return diff --git a/leaky-ships/src/interfaces/ApiSocket.ts b/leaky-ships/src/interfaces/ApiSocket.ts index 76f48bb..ddf76ce 100644 --- a/leaky-ships/src/interfaces/ApiSocket.ts +++ b/leaky-ships/src/interfaces/ApiSocket.ts @@ -21,9 +21,6 @@ export interface SocketServer extends http.Server { } export interface ServerToClientEvents { - // noArg: () => void - // basicEmit: (a: number, b: string, c: Buffer) => void - // withAck: (d: string, ) => void gameSetting: (payload: GameSettings, hash: string) => void playerEvent: (event: PlayerEvent) => void isReady: (payload: { i: 0 | 1; isReady: boolean }) => void @@ -34,8 +31,7 @@ export interface ServerToClientEvents { "canvas-clear": () => void gameState: (newState: GameState) => void ships: (ships: ShipProps[], index: number) => void - activeIndex: (index: 0 | 1) => void - dispatchMove: (props: MoveDispatchProps, i: number) => void + dispatchMove: (props: MoveDispatchProps, i: 0 | 1) => void } export interface ClientToServerEvents { diff --git a/leaky-ships/src/lib/backend/sendResponse.ts b/leaky-ships/src/lib/backend/sendResponse.ts index 7b0283b..22af809 100644 --- a/leaky-ships/src/lib/backend/sendResponse.ts +++ b/leaky-ships/src/lib/backend/sendResponse.ts @@ -14,6 +14,7 @@ export default function sendResponse( result: Result, ) { if (result.redirectUrl) { + logging("Redirect | " + result.message, result.type ?? ["debug"], request) return redirect(result.redirectUrl) } else { logging(result.message, result.type ?? ["debug"], request) diff --git a/leaky-ships/src/lib/getPayloadFromProps.ts b/leaky-ships/src/lib/getPayloadFromProps.ts index 0fddcea..766b07e 100644 --- a/leaky-ships/src/lib/getPayloadFromProps.ts +++ b/leaky-ships/src/lib/getPayloadFromProps.ts @@ -1,5 +1,4 @@ import { - activeIndex, allowChat, allowMarkDraw, allowSpecials, @@ -30,6 +29,5 @@ export function getPayloadFromProps() { ships: user.ships(), hits: user.hits(), })), - activeIndex: activeIndex(), } } diff --git a/leaky-ships/src/lib/zodSchemas.ts b/leaky-ships/src/lib/zodSchemas.ts index 6a51ab0..08ff881 100644 --- a/leaky-ships/src/lib/zodSchemas.ts +++ b/leaky-ships/src/lib/zodSchemas.ts @@ -98,7 +98,6 @@ export const CreateSchema = z.object({ .nullable(), gamePin: z.string().nullable(), users: z.object({ 0: PlayerSchema, 1: PlayerSchema }), - activeIndex: z.literal(0).or(z.literal(1)), }) export const GamePropsSchema = z.object({ diff --git a/leaky-ships/src/routes/api/game/running.ts b/leaky-ships/src/routes/api/game/running.ts index b083545..d2b6b81 100644 --- a/leaky-ships/src/routes/api/game/running.ts +++ b/leaky-ships/src/routes/api/game/running.ts @@ -1,9 +1,10 @@ import { getSession } from "@auth/solid-start" -import { and, eq, exists, ne } from "drizzle-orm" +import { and, eq, exists, ne, notExists } from "drizzle-orm" import { APIEvent } from "solid-start/api" import db from "~/drizzle" import { games, user_games } from "~/drizzle/schemas/Tables" import { rejectionErrors } from "~/lib/backend/errors" +import logging from "~/lib/backend/logging" import sendResponse from "~/lib/backend/sendResponse" import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum" import { GamePropsSchema } from "~/lib/zodSchemas" @@ -87,7 +88,15 @@ export const getRunningGameToUser = async (userId: string) => { and( ne(game.state, "ended"), exists( - db.select().from(user_games).where(eq(user_games.userId, userId)), + db + .select() + .from(user_games) + .where( + and( + eq(user_games.gameId, game.id), + eq(user_games.userId, userId), + ), + ), ), ), ...gameSelects, @@ -122,17 +131,10 @@ export function composeBody( hits: [], }, } - let activeIndex: 0 | 1 = 0 - if (game.state === "running") { - const l1 = users[0]?.moves.length ?? 0 - const l2 = users[1]?.moves.length ?? 0 - activeIndex = l1 > l2 ? 1 : 0 - } const payload = { game: game, gamePin: gamePin?.pin ?? null, users: composedUsers, - activeIndex, } return getPayloadwithChecksum(payload) } @@ -144,6 +146,26 @@ export async function GET({ request }: APIEvent) { return sendResponse(request, rejectionErrors.unauthorized) } + const abandonedGames = await db + .delete(games) + .where( + notExists( + db.select().from(user_games).where(eq(user_games.gameId, games.id)), + ), + ) + .returning() + if (abandonedGames.length) { + logging( + "Games were deleted because of missing players. Id's: " + + JSON.stringify( + abandonedGames.map((e) => e.id), + null, + 2, + ), + ["error"], + ) + } + const { email, id } = session.user const game = await getRunningGameToUser(id) diff --git a/leaky-ships/src/routes/api/ws.ts b/leaky-ships/src/routes/api/ws.ts index 108969a..280a493 100644 --- a/leaky-ships/src/routes/api/ws.ts +++ b/leaky-ships/src/routes/api/ws.ts @@ -39,11 +39,12 @@ export async function GET({ // io.use(authenticate) io.use(async (socket, next) => { + const request = socket.request try { - const url = process.env.AUTH_URL! + socket.request.url + const url = process.env.AUTH_URL! + request.url const session = await getSession( new Request(url, { - headers: socket.request.headers as Record, + headers: request.headers as Record, }), authOptions, ) @@ -53,10 +54,10 @@ export async function GET({ const game = await getRunningGameToUser(socket.data.user?.id ?? "") if (!game) { logging( - "Forbidden, no game found: " + - JSON.stringify(Array.from(socket.rooms)), + "Authentication forbidden, no game found for user: " + + JSON.stringify([socket.data.user?.id, session.user]), ["debug"], - socket.request, + request, ) return next(new Error(status["403"])) } @@ -76,7 +77,7 @@ export async function GET({ next() } catch { - logging("Unkonwn error - " + status["401"], ["warn"], socket.request) + logging("Unkonwn error - " + status["401"], ["warn"], request) next(new Error(status["401"])) } }) @@ -87,7 +88,7 @@ export async function GET({ ", " + socket.id.cyan, ["infoGreen"], - socket.request, + request, ) socket.on("update", async (cb) => { @@ -224,8 +225,6 @@ export async function GET({ }) .where(eq(games.id, socket.data.gameId)) io.to(socket.data.gameId).emit("gameState", newState) - if (newState === "running") - io.to(socket.data.gameId).emit("activeIndex", 0) }) socket.on("ships", async (shipsData) => { @@ -280,18 +279,14 @@ export async function GET({ .values({ ...props, id: createId(), user_game_id: user_Game.id }) .returning() - const game = user_Game.game - const l1 = game.users[0].moves.length - const l2 = game.users[1].moves.length io.to(socket.data.gameId).emit("dispatchMove", props, socket.data.index) - io.to(socket.data.gameId).emit("activeIndex", l1 > l2 ? 1 : 0) }) socket.on("disconnecting", async () => { logging( "Disconnecting: " + JSON.stringify(Array.from(socket.rooms)), ["debug"], - socket.request, + request, ) if (!socket.data.gameId) return socket.to(socket.data.gameId).emit("playerEvent", { @@ -301,7 +296,7 @@ export async function GET({ }) socket.on("disconnect", () => { - logging("Disconnect: " + socket.id, ["debug"], socket.request) + logging("Disconnect: " + socket.id, ["debug"], request) }) }) }