diff --git a/leaky-ships/components/Lobby/LobbyFrame.tsx b/leaky-ships/components/Lobby/LobbyFrame.tsx
index 6c15900..c488b59 100644
--- a/leaky-ships/components/Lobby/LobbyFrame.tsx
+++ b/leaky-ships/components/Lobby/LobbyFrame.tsx
@@ -47,13 +47,13 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
)
useEffect(() => {
- if (!launching || launchTime >= 1) return
- router.push("/gamefield")
+ if (!launching || launchTime > 0) return
+ socket.emit("starting")
}, [launching, launchTime, router])
useEffect(() => {
if (!launching) return setLaunchTime(3)
- if (launchTime === 0) return
+ if (launchTime < 0) return
const timeout = setTimeout(() => {
setLaunchTime((e) => e - 1)
@@ -67,16 +67,29 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
socket.emit("update", full)
}, [full, payload?.game?.id, isConnected])
+ useEffect(() => {
+ if (
+ typeof payload?.game?.state !== "string" ||
+ payload?.game?.state === "lobby"
+ )
+ return
+ router.push("gamefield")
+ })
+
return (
Chat
{launching ? (
- {"Game is starting in " + launchTime}
+
+ {launchTime < 0
+ ? "Game starts"
+ : "Game is starting in " + launchTime}
+
) : (
<>
- Game-PIN:{" "}
+ {"Game-PIN: "}
{isConnected ? (
{payload?.gamePin ?? "----"}
) : (
@@ -114,8 +127,8 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
disabled={launching}
onClick={() => {
leave(async () => {
- await router.push("/")
reset()
+ await router.push("/")
})
}}
>
diff --git a/leaky-ships/hooks/useDraw.ts b/leaky-ships/hooks/useDraw.ts
index 5c5b978..fbb249b 100644
--- a/leaky-ships/hooks/useDraw.ts
+++ b/leaky-ships/hooks/useDraw.ts
@@ -1,4 +1,4 @@
-import { Draw, DrawLineProps, Point } from "../interfaces/frontend"
+import { Draw, Point } from "../interfaces/frontend"
import { useDrawProps } from "./useDrawProps"
import { socket } from "@lib/socket"
import { useEffect, useRef, useState } from "react"
@@ -108,7 +108,7 @@ export const useDraw = () => {
drawLine({ prevPoint, currentPoint, ctx, color })
})
- socket.on("clear", clear)
+ socket.on("canvas-clear", clear)
return () => {
socket.removeAllListeners()
diff --git a/leaky-ships/hooks/useGameProps.ts b/leaky-ships/hooks/useGameProps.ts
index cf6d7f2..c50e27d 100644
--- a/leaky-ships/hooks/useGameProps.ts
+++ b/leaky-ships/hooks/useGameProps.ts
@@ -45,6 +45,7 @@ export type Action = {
full: (newProps: GamePropsSchema) => void
leave: (cb: () => void) => void
setIsReady: (payload: { i: number; isReady: boolean }) => void
+ starting: () => void
setIsConnected: (payload: { i: number; isConnected: boolean }) => void
reset: () => void
}
@@ -159,6 +160,17 @@ export const useGameProps = create()(
state.userStates[i].isConnected = true
})
),
+ starting: () =>
+ set(
+ produce((state: State) => {
+ if (state.payload?.game?.state !== "lobby") return
+ state.payload.game.state = "starting"
+ state.userStates = state.userStates.map((e) => ({
+ ...e,
+ isReady: false,
+ }))
+ })
+ ),
setIsConnected: ({ i, isConnected }) =>
set(
produce((state: State) => {
diff --git a/leaky-ships/hooks/useSocket.ts b/leaky-ships/hooks/useSocket.ts
index d5e2f3e..73eaf9b 100644
--- a/leaky-ships/hooks/useSocket.ts
+++ b/leaky-ships/hooks/useSocket.ts
@@ -1,5 +1,7 @@
+import { isAuthenticated } from "../pages/start"
import { useGameProps } from "./useGameProps"
import { socket } from "@lib/socket"
+import { GamePropsSchema } from "@lib/zodSchemas"
import status from "http-status"
import { useSession } from "next-auth/react"
import { useRouter } from "next/router"
@@ -16,6 +18,7 @@ function useSocket() {
setSetting,
full,
setIsReady,
+ starting,
setIsConnected,
} = useGameProps()
const { data: session } = useSession()
@@ -27,6 +30,10 @@ function useSocket() {
if (!isIndex) return { i: undefined, isIndex }
return { i, isIndex }
}, [payload?.users, session?.user?.id])
+ const isConnected = useMemo(
+ () => (isIndex ? userStates[i].isConnected : isConnectedState),
+ [i, isConnectedState, isIndex, userStates]
+ )
useEffect(() => {
if (!isIndex) return
@@ -37,8 +44,6 @@ function useSocket() {
}, [i, isConnectedState, isIndex, setIsConnected])
useEffect(() => {
- if (!session?.user.id) return
-
socket.on("connect", () => {
console.log("connected")
toast.dismiss("connect_error")
@@ -73,7 +78,7 @@ function useSocket() {
socket.on("playerEvent", (event) => {
const { type, i } = event
let message: string
- console.log(type)
+ console.log("playerEvent", type)
switch (type) {
case "disconnect":
setIsConnected({
@@ -115,6 +120,8 @@ function useSocket() {
socket.on("isReady", setIsReady)
+ socket.on("starting", starting)
+
socket.on("disconnect", () => {
console.log("disconnect")
setIsConnectedState(false)
@@ -125,27 +132,37 @@ function useSocket() {
}
}, [
full,
+ payload?.game?.id,
router,
session?.user.id,
setIsConnected,
setIsReady,
setPlayer,
setSetting,
+ starting,
userStates,
])
- // useEffect(() => {
- // if (!isConnected) return
- // let count = 0
- // const interval = setInterval(() => {
- // const start = Date.now()
- // socket.volatile.emit("ping", ++count, (count) => {
- // const duration = Date.now() - start
- // console.log("ping", count, duration)
- // })
- // }, 5000)
- // return () => clearInterval(interval)
- // }, [isConnected])
+ useEffect(() => {
+ if (!payload?.game?.id) {
+ socket.disconnect()
+ fetch("/api/game/running", {
+ method: "GET",
+ })
+ .then(isAuthenticated)
+ .then((game) => GamePropsSchema.parse(game))
+ .then((res) => full(res))
+ .catch()
+ return
+ }
+ if (isConnected) return
+ socket.connect()
+ const start = Date.now()
+ socket.volatile.emit("ping", () => {
+ const duration = Date.now() - start
+ console.log("ping", duration)
+ })
+ }, [full, isConnected, payload?.game?.id])
return { isConnected: isIndex ? userStates[i].isConnected : isConnectedState }
}
diff --git a/leaky-ships/interfaces/NextApiSocket.ts b/leaky-ships/interfaces/NextApiSocket.ts
index 269d545..42a147c 100644
--- a/leaky-ships/interfaces/NextApiSocket.ts
+++ b/leaky-ships/interfaces/NextApiSocket.ts
@@ -47,20 +47,22 @@ export interface ServerToClientEvents {
"get-canvas-state": () => void
"canvas-state-from-server": (state: string, userIndex: number) => void
"draw-line": (props: DrawLineProps, userIndex: number) => void
- clear: () => void
+ "canvas-clear": () => void
+ starting: () => void
}
export interface ClientToServerEvents {
update: (callback: (game: GamePropsSchema) => void) => void
isReady: (isReady: boolean) => void
isConnected: (isReady: boolean) => void
- ping: (count: number, callback: (count: number) => void) => void
+ ping: (callback: () => void) => void
join: (withAck: (ack: boolean) => void) => void
gameSetting: (payload: GameSettings, callback: (hash: string) => void) => void
leave: (withAck: (ack: boolean) => void) => void
"canvas-state": (state: string) => void
"draw-line": (props: DrawLineProps) => void
- clear: () => void
+ "canvas-clear": () => void
+ starting: () => void
}
interface InterServerEvents {
diff --git a/leaky-ships/lib/socket.ts b/leaky-ships/lib/socket.ts
index bf08521..cd10517 100644
--- a/leaky-ships/lib/socket.ts
+++ b/leaky-ships/lib/socket.ts
@@ -3,4 +3,5 @@ import { io } from "socket.io-client"
export const socket: cSocket = io({
path: "/api/ws",
+ autoConnect: false,
})
diff --git a/leaky-ships/pages/api/game/join.ts b/leaky-ships/pages/api/game/join.ts
index dcd7307..4c5b267 100644
--- a/leaky-ships/pages/api/game/join.ts
+++ b/leaky-ships/pages/api/game/join.ts
@@ -55,7 +55,7 @@ export default async function join(
if (games.length) {
return sendResponse(req, res, {
message: "Spieler ist bereits in Spiel!",
- statusCode: 409,
+ redirectUrl: "/api/game/running",
type: ["infoCyan"],
})
}
diff --git a/leaky-ships/pages/api/ws.ts b/leaky-ships/pages/api/ws.ts
index a8a6b5c..c8c620a 100644
--- a/leaky-ships/pages/api/ws.ts
+++ b/leaky-ships/pages/api/ws.ts
@@ -2,7 +2,6 @@ import {
NextApiResponseWithSocket,
sServer,
} from "../../interfaces/NextApiSocket"
-import { DrawLineProps } from "../../interfaces/frontend"
import {
composeBody,
gameSelects,
@@ -108,9 +107,7 @@ const SocketHandler = async (
socket.to(game.id).emit("gameSetting", payload, hash)
})
- socket.on("ping", (count, callback) => {
- callback(count)
- })
+ socket.on("ping", (callback) => callback())
socket.on("leave", async (cb) => {
if (!socket.data.gameId || !socket.data.user?.id) return cb(false)
@@ -192,23 +189,31 @@ const SocketHandler = async (
.emit("canvas-state-from-server", state, socket.data.index)
})
- socket.on(
- "draw-line",
- ({ prevPoint, currentPoint, color }: DrawLineProps) => {
- if (!socket.data.gameId || !socket.data.index) return
- socket
- .to(socket.data.gameId)
- .emit(
- "draw-line",
- { prevPoint, currentPoint, color },
- socket.data.index
- )
- }
- )
+ socket.on("draw-line", ({ prevPoint, currentPoint, color }) => {
+ if (!socket.data.gameId || !socket.data.index) return
+ socket
+ .to(socket.data.gameId)
+ .emit(
+ "draw-line",
+ { prevPoint, currentPoint, color },
+ socket.data.index
+ )
+ })
- socket.on("clear", () => {
+ socket.on("canvas-clear", () => {
if (!socket.data.gameId) return
- socket.to(socket.data.gameId).emit("clear")
+ socket.to(socket.data.gameId).emit("canvas-clear")
+ })
+
+ socket.on("starting", async () => {
+ if (socket.data.index !== 0 || !socket.data.gameId) return
+ await prisma.game.update({
+ where: { id: socket.data.gameId },
+ data: {
+ state: "starting",
+ },
+ })
+ io.to(socket.data.gameId).emit("starting")
})
socket.on("disconnecting", async () => {
@@ -225,7 +230,6 @@ const SocketHandler = async (
})
socket.on("disconnect", () => {
- // socket.rooms.size === 0
logging("Disconnect: " + socket.id, ["debug"], socket.request)
})
})
diff --git a/leaky-ships/prisma/generated/zod/index.ts b/leaky-ships/prisma/generated/zod/index.ts
index 54f56d5..679fa70 100644
--- a/leaky-ships/prisma/generated/zod/index.ts
+++ b/leaky-ships/prisma/generated/zod/index.ts
@@ -32,7 +32,7 @@ export const User_GameScalarFieldEnumSchema = z.enum(['id','createdAt','gameId',
export const VerificationTokenScalarFieldEnumSchema = z.enum(['identifier','token','expires']);
-export const GameStateSchema = z.enum(['launching','running','ended']);
+export const GameStateSchema = z.enum(['lobby','starting','running','ended']);
export type GameStateType = `${z.infer}`
diff --git a/leaky-ships/prisma/schema.prisma b/leaky-ships/prisma/schema.prisma
index 98c1c1a..0d572c9 100644
--- a/leaky-ships/prisma/schema.prisma
+++ b/leaky-ships/prisma/schema.prisma
@@ -69,7 +69,8 @@ model VerificationToken {
}
enum GameState {
- launching
+ lobby
+ starting
running
ended
}
@@ -78,7 +79,7 @@ model Game {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
- state GameState @default(launching)
+ state GameState @default(lobby)
allowSpectators Boolean @default(true)
allowSpecials Boolean @default(true)
allowChat Boolean @default(true)