Fix some game logic
This commit is contained in:
parent
b4fd992611
commit
b067747d48
15 changed files with 90 additions and 98 deletions
|
@ -29,6 +29,8 @@ export function FontAwesomeIcon(
|
|||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby={props.titleId}
|
||||
data-prefix={props.icon.prefix}
|
||||
data-icon={props.icon.iconName}
|
||||
|
@ -45,8 +47,6 @@ export function FontAwesomeIcon(
|
|||
)}
|
||||
color={props.color}
|
||||
style={props.style}
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox={`0 0 ${props.icon.icon[0]} ${props.icon.icon[1]}`}
|
||||
>
|
||||
<Show when={props.title}>
|
||||
|
|
|
@ -234,7 +234,7 @@ function EventBar(props: { clear: () => void }) {
|
|||
iconColor: "green",
|
||||
callback: async () => {
|
||||
socket.emit("gameState", "aborted")
|
||||
await navigator("/")
|
||||
navigator("/")
|
||||
reset()
|
||||
},
|
||||
},
|
||||
|
@ -307,7 +307,7 @@ function EventBar(props: { clear: () => void }) {
|
|||
</Show>
|
||||
<For each={items()[menu()]}>
|
||||
{(e, i) => (
|
||||
<Show when={isActiveIndex() && menu() !== "main" && i() !== 1}>
|
||||
<Show when={isActiveIndex() || menu() !== "main" || i() !== 1}>
|
||||
<Item {...e} />
|
||||
</Show>
|
||||
)}
|
||||
|
|
|
@ -94,12 +94,6 @@ function Gamefield() {
|
|||
reset()
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (gameId()) return
|
||||
const timeout = setTimeout(() => navigator("/"), 5000)
|
||||
return () => clearTimeout(timeout)
|
||||
})
|
||||
|
||||
return (
|
||||
<div id="gamefield">
|
||||
{/* <Bluetooth /> */}
|
||||
|
|
|
@ -20,6 +20,7 @@ function GamefieldPointer(
|
|||
"--y1": props.y - 1,
|
||||
"--y2": props.y + 2,
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={classNames("hit-svg", "target", props.type, ...props.edges, {
|
||||
|
@ -29,7 +30,7 @@ function GamefieldPointer(
|
|||
})}
|
||||
style={style()}
|
||||
>
|
||||
<FontAwesomeIcon icon={!isRadar ? faCrosshairs : faRadar} />
|
||||
<FontAwesomeIcon icon={!isRadar() ? faCrosshairs : faRadar} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ function Ships() {
|
|||
const { isActiveIndex, selfUser } = useSession()
|
||||
|
||||
return (
|
||||
<Show when={gameState() === "running" && isActiveIndex}>
|
||||
<Show when={gameState() !== "running" || !isActiveIndex()}>
|
||||
<For each={selfUser()?.ships()}>{(props) => <Ship {...props} />}</For>
|
||||
</Show>
|
||||
)
|
||||
|
|
|
@ -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 (
|
||||
<Switch>
|
||||
|
@ -36,7 +36,7 @@ function Targets() {
|
|||
when={gameState() === "starting" && mode() >= 0 && targetPreview().show}
|
||||
>
|
||||
<Ship
|
||||
{...ship}
|
||||
{...ship()}
|
||||
preview
|
||||
warn={score > 0}
|
||||
color={fields.length ? "red" : borders.length ? "orange" : undefined}
|
||||
|
|
|
@ -25,7 +25,6 @@ import {
|
|||
} from "../interfaces/frontend"
|
||||
|
||||
export const [hash, setHash] = createSignal<string | null>(null)
|
||||
export const [activeIndex, setActiveIndex] = createSignal<0 | 1>(0)
|
||||
export const [gamePin, setGamePin] = createSignal<string | null>(null)
|
||||
export const [gameId, setGameId] = createSignal<string>("")
|
||||
export const [gameState, setGameState] = createSignal<GameState>("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")
|
||||
|
|
|
@ -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<Session | null>
|
||||
selfIndex: () => 0 | 1 | -1
|
||||
activeIndex: Accessor<0 | 1>
|
||||
isActiveIndex: () => boolean
|
||||
selfUser: () => ReturnType<typeof initialUser> | null
|
||||
activeUser: () => ReturnType<typeof initialUser>
|
||||
ships: () => ShipProps[]
|
||||
}
|
||||
import { gameState, setMenu, setMode, users } from "./useGameProps"
|
||||
|
||||
const [state, setState] = createSignal<Session | null>(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<Concext>(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 (
|
||||
<SessionCtx.Provider value={contextValue}>
|
||||
{props.children}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -14,6 +14,7 @@ export default function sendResponse<T>(
|
|||
result: Result<T>,
|
||||
) {
|
||||
if (result.redirectUrl) {
|
||||
logging("Redirect | " + result.message, result.type ?? ["debug"], request)
|
||||
return redirect(result.redirectUrl)
|
||||
} else {
|
||||
logging(result.message, result.type ?? ["debug"], request)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {
|
||||
activeIndex,
|
||||
allowChat,
|
||||
allowMarkDraw,
|
||||
allowSpecials,
|
||||
|
@ -30,6 +29,5 @@ export function getPayloadFromProps() {
|
|||
ships: user.ships(),
|
||||
hits: user.hits(),
|
||||
})),
|
||||
activeIndex: activeIndex(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<string, string>,
|
||||
headers: request.headers as Record<string, string>,
|
||||
}),
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue