diff --git a/backend/src/game-modes/standard/logic-handlers.ts b/backend/src/game-modes/standard/logic-handlers.ts index 8cb7d423..cc0640b0 100644 --- a/backend/src/game-modes/standard/logic-handlers.ts +++ b/backend/src/game-modes/standard/logic-handlers.ts @@ -8,7 +8,7 @@ export const handleEmptyLogic = logicHandler(async () => { }); export const handleLogicWithTimer = logicHandler(async (loopParams: MatchLoopParams) => { - await handleTimeOutTicks(loopParams); + handleTimeOutTicks(loopParams); }); export const handlePowerUpLogic = logicHandler(async (loopParams: MatchLoopParams) => { @@ -17,7 +17,7 @@ export const handlePowerUpLogic = logicHandler(async (loopParams: MatchLoopParam const initialPowerUpAmount = state.settings.initialPowerUpAmount; const range = getRange(initialPowerUpAmount); - await handleTimeOutTicks(loopParams); + handleTimeOutTicks(loopParams); // TODO: Store PowerUp records instead of just IDs await Promise.all( diff --git a/backend/src/game-modes/standard/message-handlers/stage-message.ts b/backend/src/game-modes/standard/message-handlers/stage-message.ts index e717ad8a..a2410b91 100644 --- a/backend/src/game-modes/standard/message-handlers/stage-message.ts +++ b/backend/src/game-modes/standard/message-handlers/stage-message.ts @@ -55,7 +55,7 @@ export const handleRollDiceMessage = messageHandler(async (loopParams, message, } case MatchOpCode.ROLL_DICE: { if (player.hasRolledDice) return; - await rollDiceForPlayer(loopParams, sender.userId); + rollDiceForPlayer(loopParams, sender.userId); break; } } diff --git a/backend/src/game-modes/standard/transition-handlers.ts b/backend/src/game-modes/standard/transition-handlers.ts index adb5e27d..1bfefa15 100644 --- a/backend/src/game-modes/standard/transition-handlers.ts +++ b/backend/src/game-modes/standard/transition-handlers.ts @@ -1,4 +1,4 @@ -import { setActivePlayer, transitionHandler, handleRoundEnding } from "../../services"; +import { setActivePlayer, transitionHandler, handleRoundEnding, updatePlayersState } from "../../services"; import { MatchOpCode, PlayerActivePayloadBackend, PlayerOrderShufflePayloadBackend, StageTransitionPayloadBackend } from "../../types"; import { shuffleArray } from "../../utils"; @@ -11,6 +11,7 @@ export const handleBasicTransition = transitionHandler(async ({ state, dispatche round: state.round, }; dispatcher.broadcastMessage(MatchOpCode.STAGE_TRANSITION, JSON.stringify(payload)); + updatePlayersState(state, dispatcher); }); export const handleLobbyTransition = transitionHandler(async (loopParams, nextStage) => { @@ -34,6 +35,7 @@ export const handleLobbyTransition = transitionHandler(async (loopParams, nextSt dispatcher.broadcastMessage(MatchOpCode.PLAYER_ORDER_SHUFFLE, JSON.stringify(playerOrderShufflePayload)); dispatcher.broadcastMessage(MatchOpCode.PLAYER_ACTIVE, JSON.stringify(playerActivePayload)); dispatcher.broadcastMessage(MatchOpCode.STAGE_TRANSITION, JSON.stringify(stageTransitionPayload)); + updatePlayersState(state, dispatcher); }); export const handleRoundSummaryTransition = transitionHandler(handleRoundEnding); diff --git a/backend/src/services/player.ts b/backend/src/services/player.ts index d1f00801..89b77208 100644 --- a/backend/src/services/player.ts +++ b/backend/src/services/player.ts @@ -132,7 +132,7 @@ export const getFilteredPlayerIds = (players: Record, playerIds: .map((player) => player.userId); }; -export const rollDiceForPlayer = async (loopParams: MatchLoopParams, playerId: string) => { +export const rollDiceForPlayer = (loopParams: MatchLoopParams, playerId: string) => { const { state, dispatcher, nk } = loopParams; const player = state.players[playerId]; @@ -141,7 +141,7 @@ export const rollDiceForPlayer = async (loopParams: MatchLoopParams, playerId: s const { address, privateKey, viewKey } = getPlayerAccount(nk, playerId); - const diceValue = await rollDice(loopParams, player.diceAmount, player, { address, privateKey, viewKey }); + const diceValue = rollDice(loopParams, player.diceAmount, player, { address, privateKey, viewKey }); player.diceValue = diceValue; diff --git a/backend/src/services/timer.ts b/backend/src/services/timer.ts index d0152ba2..22b4de89 100644 --- a/backend/src/services/timer.ts +++ b/backend/src/services/timer.ts @@ -1,7 +1,6 @@ import { EMPTY_DATA } from "../constants"; import { MatchLoopParams, MatchOpCode, PlayerLostByTimeOutPayloadBackend } from "../types"; -import { getTicksFromSeconds } from "../utils"; -import { getDiceValues } from "../utils/die"; +import { getTicksFromSeconds, getDiceValues } from "../utils"; import { areAllPlayersReady, getActivePlayerId, @@ -11,23 +10,14 @@ import { setAllPlayersReady, } from "./player"; -export const handleStartTimer = (loopParams: MatchLoopParams) => { - const { state } = loopParams; - const timerDuration = state.settings.matchStageDuration[state.matchStage]; - - state.timerHasStarted = true; - state.ticksBeforeTimeOut = getTicksFromSeconds(timerDuration); -}; - -export const handleOutOfTime = async (loopParams: MatchLoopParams) => { +const handleOutOfTime = (loopParams: MatchLoopParams) => { const { state, dispatcher } = loopParams; const activePlayerId = getActivePlayerId(state.players); switch (state.matchStage) { case "rollDiceStage": { - // TODO: send loading to client - const playersWithNoDice = Object.values(state.players).filter((player) => player.hasRolledDice !== true); - await Promise.all(playersWithNoDice.map((player) => rollDiceForPlayer(loopParams, player.userId))); + const playersWithNoDice = Object.values(state.players).filter((player) => !player.hasRolledDice); + playersWithNoDice.forEach((player) => rollDiceForPlayer(loopParams, player.userId)); break; } case "playerTurnLoopStage": { @@ -53,19 +43,18 @@ export const handleOutOfTime = async (loopParams: MatchLoopParams) => { } }; -export const handleTimeOutTicks = async (loopParams: MatchLoopParams) => { +export const handleTimeOutTicks = (loopParams: MatchLoopParams) => { const { state } = loopParams; if (!state.timerHasStarted) { - handleStartTimer(loopParams); - return; + const timerDuration = state.settings.matchStageDuration[state.matchStage]; + + state.timerHasStarted = true; + state.ticksBeforeTimeOut = getTicksFromSeconds(timerDuration); + } else { + state.ticksBeforeTimeOut--; + if (state.ticksBeforeTimeOut <= 0) { + handleOutOfTime(loopParams); + } } - - state.ticksBeforeTimeOut--; - - if (state.ticksBeforeTimeOut <= 0) await handleOutOfTime(loopParams); -}; - -export const msecToSec = (n: number): number => { - return Math.floor(n / 1000); }; diff --git a/backend/src/toolkit-api/dice.ts b/backend/src/toolkit-api/dice.ts index ed72ae09..cbc92a37 100644 --- a/backend/src/toolkit-api/dice.ts +++ b/backend/src/toolkit-api/dice.ts @@ -3,7 +3,7 @@ import { Die, isRandomNumberResToolkit, MatchLoopParams, Player, RandomNumberBod import { getNumericHash, getRange, randomInt, tkUrl, isZkEnabled, httpError } from "../utils"; import { handleToolkitRequest } from "./request-handler"; -const requestRoll = async (loopParams: MatchLoopParams, seed: number, playerAccount: AleoAccount): Promise => { +const requestRoll = (loopParams: MatchLoopParams, seed: number, playerAccount: AleoAccount): number => { const { nk, ctx, logger } = loopParams; const { address, privateKey, viewKey } = playerAccount; @@ -20,7 +20,7 @@ const requestRoll = async (loopParams: MatchLoopParams, seed: number, playerAcco return parsedBody.randomNumber; }; -const localRoll = async (): Promise => { +const localRoll = (): number => { const value = randomInt(6, 1); return value; }; @@ -29,39 +29,31 @@ const localRoll = async (): Promise => { * * @description Roll dice gathers the hashes from other players and the seed from the player and requests a roll from the toolkit */ -// TODO: Investigate and discuss whether Promise.reject should be used instead of throwing an error -export const rollDice = async ( - loopParams: MatchLoopParams, - diceAmount: number, - player: Player, - playerAccount: AleoAccount -): Promise => { +export const rollDice = (loopParams: MatchLoopParams, diceAmount: number, player: Player, playerAccount: AleoAccount): Die[] => { const { state, ctx, logger } = loopParams; try { - const diceResponse = await Promise.all( - getRange(diceAmount).map((_value, index) => { - if (isZkEnabled(state, ctx)) { - const currentRngCounter = player.rngDiceCounter - index; + const diceResponse = getRange(diceAmount).map((_value, index) => { + if (isZkEnabled(state, ctx)) { + const currentRngCounter = player.rngDiceCounter - index; - // Get hashes from other players according to current RNG counter - const hashList = Object.values(state.players) - .filter((statePlayer) => statePlayer.userId !== player.userId) - .map((player) => player.hashChain[currentRngCounter]); + // Get hashes from other players according to current RNG counter + const hashList = Object.values(state.players) + .filter((statePlayer) => statePlayer.userId !== player.userId) + .map((player) => player.hashChain[currentRngCounter]); - // Include own seed hash - hashList.push(String(player.seed)); + // Include own seed hash + hashList.push(String(player.seed)); - const seedHash = getNumericHash(hashList); + const seedHash = getNumericHash(hashList); - const diceRoll = requestRoll(loopParams, seedHash, playerAccount); + const diceRoll = requestRoll(loopParams, seedHash, playerAccount); - return diceRoll; - } else { - return localRoll(); - } - }) - ); + return diceRoll; + } else { + return localRoll(); + } + }); const dice = diceResponse.map((die) => ({ rolledValue: die, diff --git a/frontend/src/components/get-power-ups/get-power-ups.tsx b/frontend/src/components/get-power-ups/get-power-ups.tsx index b55186f3..e8c709ca 100644 --- a/frontend/src/components/get-power-ups/get-power-ups.tsx +++ b/frontend/src/components/get-power-ups/get-power-ups.tsx @@ -5,8 +5,6 @@ import { text } from "../../assets"; import { BottomButtonWrapper } from "../../atoms"; import { ErrorView } from "../error-view"; import { ButtonReady } from "../button-ready"; -import { useEffectOnce } from "usehooks-ts"; -import { useStore } from "../../store"; import { MatchHeading } from "../match-heading"; import { Timer } from "../timer"; import { FadeTransition } from "../page-transition"; @@ -14,14 +12,8 @@ import { useClientTimer } from "../../hooks"; export const GetPowerUps: FC = () => { const localPlayer = useLocalPlayer(); - const setSpinnerVisibility = useStore((state) => state.setSpinnerVisibility); useClientTimer(); - // Add sound effect - - useEffectOnce(() => { - setSpinnerVisibility(true); - }); if (!localPlayer) return ; diff --git a/frontend/src/components/roll-dice/roll-dice.tsx b/frontend/src/components/roll-dice/roll-dice.tsx index 2f03df63..b3192812 100644 --- a/frontend/src/components/roll-dice/roll-dice.tsx +++ b/frontend/src/components/roll-dice/roll-dice.tsx @@ -59,7 +59,7 @@ export const RollDice: FC = () => { isAnimated /> - {dice && } + {!!dice && !!dice.length && } {button()} diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts index 19660f5a..9fc5a23e 100644 --- a/frontend/src/constants.ts +++ b/frontend/src/constants.ts @@ -96,8 +96,6 @@ export const SLIDER_MINIMUM = 0; export const SLIDER_MAXIMUM = 1; export const SLIDER_STEP = 0.1; -export const TIMEOUT_STAGE_TRANSITION_TIME = 5000; - // TODO: change the time export const DECISION_MAKING_TIME_IN_SECONDS = 100; diff --git a/frontend/src/hooks/use-timer.ts b/frontend/src/hooks/use-timer.ts index 621bdb3a..f2720685 100644 --- a/frontend/src/hooks/use-timer.ts +++ b/frontend/src/hooks/use-timer.ts @@ -1,7 +1,7 @@ import { useEffect } from "react"; import { useCountdown } from "usehooks-ts"; import { timerSound, text } from "../assets"; -import { MILLISECONDS, SOUND_TIMER_TRIGGERS, TIMEOUT_STAGE_TRANSITION_TIME } from "../constants"; +import { MILLISECONDS, SOUND_TIMER_TRIGGERS } from "../constants"; import { useLocalPlayer, useMatch } from "../service"; import { useStore } from "../store"; import { usePlaySound } from "./use-sound"; @@ -61,14 +61,14 @@ export const useClientTimer = (triggerCondition = true) => { const isPlayerReady = useStore((state) => state.isPlayerReady); const setSpinnerVisibility = useStore((state) => state.setSpinnerVisibility); const { count } = useTimer(); - const { delayBroadcastPlayerReady } = useMatch(); + const { broadcastPlayerReady } = useMatch(); useEffect(() => { if (count <= 0 && triggerCondition && !isPlayerReady) { setSpinnerVisibility(true); - delayBroadcastPlayerReady(TIMEOUT_STAGE_TRANSITION_TIME); + broadcastPlayerReady(); } - }, [count, delayBroadcastPlayerReady, triggerCondition, isPlayerReady, setSpinnerVisibility]); + }, [count, triggerCondition, isPlayerReady, setSpinnerVisibility, broadcastPlayerReady]); return { count }; }; diff --git a/frontend/src/pages/match/match.tsx b/frontend/src/pages/match/match.tsx index 1d6cc1db..5e68729e 100644 --- a/frontend/src/pages/match/match.tsx +++ b/frontend/src/pages/match/match.tsx @@ -178,8 +178,8 @@ export const Match: FC = ({ matchId }) => { if (!parsed.success) return; setTimerTimeInSeconds(parsed.data.remainingStageTime); - clearHistory(); setMatchState(parsed.data.matchState); + break; } case MatchOpCode.PLAYER_READY: { diff --git a/frontend/src/service/match.ts b/frontend/src/service/match.ts index 5444d992..e30a92e5 100644 --- a/frontend/src/service/match.ts +++ b/frontend/src/service/match.ts @@ -130,7 +130,6 @@ export const useMatch = () => { const setSpinnerVisibility = useStore((state) => state.setSpinnerVisibility); const setTurnActionStep = useStore((state) => state.setTurnActionStep); - const setPlayerReady = useStore((state) => state.setPlayerReady); const [isLoading, setIsLoading] = useState(false); @@ -165,17 +164,7 @@ export const useMatch = () => { [sendMatchState, setSpinnerVisibility] ); - const broadcastPlayerReady = () => sendMatchState(MatchOpCode.PLAYER_READY); - - const delayBroadcastPlayerReady = (delay: number) => { - setSpinnerVisibility(true); - - const timeout = setTimeout(() => { - setPlayerReady(true); - broadcastPlayerReady(); - }, delay); - return () => clearTimeout(timeout); - }; + const broadcastPlayerReady = useCallback(() => sendMatchState(MatchOpCode.PLAYER_READY), [sendMatchState]); const broadcastPlaceBid = async (bid: BidPayloadFrontend) => { await sendMatchStateAndShowSpinner(MatchOpCode.PLAYER_PLACE_BID, JSON.stringify(bid)); @@ -204,7 +193,6 @@ export const useMatch = () => { isLoading, sendMatchState, broadcastPlayerReady, - delayBroadcastPlayerReady, broadcastPlaceBid, broadcastCallExact, broadcastCallBoloney,