239 lines
6.7 KiB
TypeScript
239 lines
6.7 KiB
TypeScript
import {
|
|
ActionDispatchProps,
|
|
EventBarModes,
|
|
Hit,
|
|
MouseCursor,
|
|
ShipProps,
|
|
Target,
|
|
TargetPreview,
|
|
} from "../interfaces/frontend"
|
|
import { GameSettings } from "@components/Lobby/SettingsFrame/Setting"
|
|
import { getPayloadwithChecksum } from "@lib/getPayloadwithChecksum"
|
|
import { socket } from "@lib/socket"
|
|
import {
|
|
initlialMouseCursor,
|
|
initlialTarget,
|
|
initlialTargetPreview,
|
|
} from "@lib/utils/helpers"
|
|
import {
|
|
GamePropsSchema,
|
|
optionalGamePropsSchema,
|
|
PlayerSchema,
|
|
} from "@lib/zodSchemas"
|
|
import { produce } from "immer"
|
|
import { SetStateAction } from "react"
|
|
import { toast } from "react-toastify"
|
|
import { create } from "zustand"
|
|
import { devtools } from "zustand/middleware"
|
|
|
|
const initialState: optionalGamePropsSchema & {
|
|
userStates: {
|
|
isReady: boolean
|
|
isConnected: boolean
|
|
}[]
|
|
menu: keyof EventBarModes
|
|
mode: number
|
|
ships: ShipProps[]
|
|
hits: Hit[]
|
|
target: Target
|
|
targetPreview: TargetPreview
|
|
mouseCursor: MouseCursor
|
|
} = {
|
|
menu: "actions",
|
|
mode: 0,
|
|
payload: null,
|
|
hash: null,
|
|
ships: [],
|
|
hits: [],
|
|
target: initlialTarget,
|
|
targetPreview: initlialTargetPreview,
|
|
mouseCursor: initlialMouseCursor,
|
|
userStates: Array.from(Array(2), () => ({
|
|
isReady: false,
|
|
isConnected: false,
|
|
})),
|
|
}
|
|
|
|
export type State = typeof initialState
|
|
|
|
export type Action = {
|
|
DispatchAction: (props: ActionDispatchProps) => void
|
|
setTarget: (target: SetStateAction<Target>) => void
|
|
setTargetPreview: (targetPreview: SetStateAction<TargetPreview>) => void
|
|
setMouseCursor: (mouseCursor: SetStateAction<MouseCursor>) => void
|
|
setPlayer: (payload: { users: PlayerSchema[] }) => string | null
|
|
setSetting: (settings: GameSettings) => string | null
|
|
full: (newProps: GamePropsSchema) => void
|
|
leave: (cb: () => void) => void
|
|
setIsReady: (payload: { i: number; isReady: boolean }) => void
|
|
starting: () => void
|
|
addShip: (props: ShipProps) => void
|
|
removeShip: (props: ShipProps) => void
|
|
setIsConnected: (payload: { i: number; isConnected: boolean }) => void
|
|
reset: () => void
|
|
}
|
|
|
|
export const useGameProps = create<State & Action>()(
|
|
devtools(
|
|
(set) => ({
|
|
...initialState,
|
|
DispatchAction: (action) =>
|
|
set(
|
|
produce((state: State) => {
|
|
// switch (action.type) {
|
|
// case "fireMissile":
|
|
// case "htorpedo":
|
|
// case "vtorpedo": {
|
|
// state.hits.push(...action.payload)
|
|
// }
|
|
// }
|
|
})
|
|
),
|
|
setTarget: (dispatch) =>
|
|
set(
|
|
produce((state: State) => {
|
|
if (typeof dispatch === "function")
|
|
state.target = dispatch(state.target)
|
|
else state.target = dispatch
|
|
})
|
|
),
|
|
setTargetPreview: (dispatch) =>
|
|
set(
|
|
produce((state: State) => {
|
|
if (typeof dispatch === "function")
|
|
state.targetPreview = dispatch(state.targetPreview)
|
|
else state.targetPreview = dispatch
|
|
})
|
|
),
|
|
setMouseCursor: (dispatch) =>
|
|
set(
|
|
produce((state: State) => {
|
|
if (typeof dispatch === "function")
|
|
state.mouseCursor = dispatch(state.mouseCursor)
|
|
else state.mouseCursor = dispatch
|
|
})
|
|
),
|
|
addShip: (props) =>
|
|
set(
|
|
produce((state: State) => {
|
|
state.ships.push(props)
|
|
})
|
|
),
|
|
removeShip: ({ size, variant, x, y }) =>
|
|
set(
|
|
produce((state: State) => {
|
|
const indexToRemove = state.ships.findIndex(
|
|
(ship) =>
|
|
ship.size === size &&
|
|
ship.variant === variant &&
|
|
ship.x === x &&
|
|
ship.y === y
|
|
)
|
|
state.ships.splice(indexToRemove, 1)
|
|
})
|
|
),
|
|
setPlayer: (payload) => {
|
|
let hash: string | null = null
|
|
set(
|
|
produce((state: State) => {
|
|
if (!state.payload) return
|
|
state.payload.users = payload.users
|
|
const body = getPayloadwithChecksum(state.payload)
|
|
if (!body.hash) {
|
|
toast.warn("Something is wrong... ", {
|
|
toastId: "st_wrong",
|
|
theme: "colored",
|
|
})
|
|
return
|
|
}
|
|
hash = body.hash
|
|
state.hash = hash
|
|
})
|
|
)
|
|
return hash
|
|
},
|
|
setSetting: (settings) => {
|
|
let hash: string | null = null
|
|
set(
|
|
produce((state: State) => {
|
|
if (!state.payload?.game) return
|
|
Object.assign(state.payload.game, settings)
|
|
const body = getPayloadwithChecksum(state.payload)
|
|
if (!body.hash) {
|
|
toast.warn("Something is wrong... ", {
|
|
toastId: "st_wrong",
|
|
theme: "colored",
|
|
})
|
|
return
|
|
}
|
|
hash = body.hash
|
|
state.hash = hash
|
|
})
|
|
)
|
|
return hash
|
|
},
|
|
full: (newGameProps) =>
|
|
set((state) => {
|
|
if (state.hash === newGameProps.hash) {
|
|
console.log("Everything up to date.")
|
|
} else {
|
|
console.log("Update was needed.", state.hash, newGameProps.hash)
|
|
|
|
if (
|
|
state.payload?.game?.id &&
|
|
state.payload?.game?.id !== newGameProps.payload?.game?.id
|
|
) {
|
|
console.warn(
|
|
"Different gameId detected on update: ",
|
|
state.payload?.game?.id,
|
|
newGameProps.payload?.game?.id
|
|
)
|
|
}
|
|
|
|
return newGameProps
|
|
}
|
|
return state
|
|
}),
|
|
leave: (cb) => {
|
|
socket.emit("leave", (ack) => {
|
|
if (!ack) {
|
|
toast.error("Something is wrong...")
|
|
}
|
|
cb()
|
|
})
|
|
},
|
|
setIsReady: ({ i, isReady }) =>
|
|
set(
|
|
produce((state: State) => {
|
|
state.userStates[i].isReady = isReady
|
|
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) => {
|
|
state.userStates[i].isConnected = isConnected
|
|
if (isConnected) return
|
|
state.userStates[i].isReady = false
|
|
})
|
|
),
|
|
reset: () => {
|
|
set(initialState)
|
|
},
|
|
}),
|
|
{
|
|
name: "gameState",
|
|
}
|
|
)
|
|
)
|