Skip to content

Commit

Permalink
Merged PR 4312: Fixed dice rendering on timeout trigger
Browse files Browse the repository at this point in the history
Fixed dice rendering on timeout trigger.

QA: play a game without pressing "go for it" and "roll dice" and make sure dice are rendered correctly

Related work items: #19609
  • Loading branch information
silimarius committed Jun 5, 2023
1 parent a52cff7 commit 09bce4b
Show file tree
Hide file tree
Showing 12 changed files with 48 additions and 87 deletions.
4 changes: 2 additions & 2 deletions backend/src/game-modes/standard/logic-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
4 changes: 3 additions & 1 deletion backend/src/game-modes/standard/transition-handlers.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -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) => {
Expand All @@ -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);
4 changes: 2 additions & 2 deletions backend/src/services/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export const getFilteredPlayerIds = (players: Record<string, Player>, 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];

Expand All @@ -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;

Expand Down
39 changes: 14 additions & 25 deletions backend/src/services/timer.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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": {
Expand All @@ -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);
};
46 changes: 19 additions & 27 deletions backend/src/toolkit-api/dice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<number> => {
const requestRoll = (loopParams: MatchLoopParams, seed: number, playerAccount: AleoAccount): number => {
const { nk, ctx, logger } = loopParams;
const { address, privateKey, viewKey } = playerAccount;

Expand All @@ -20,7 +20,7 @@ const requestRoll = async (loopParams: MatchLoopParams, seed: number, playerAcco
return parsedBody.randomNumber;
};

const localRoll = async (): Promise<number> => {
const localRoll = (): number => {
const value = randomInt(6, 1);
return value;
};
Expand All @@ -29,39 +29,31 @@ const localRoll = async (): Promise<number> => {
*
* @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<Die[]> => {
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,
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/components/get-power-ups/get-power-ups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,15 @@ 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";
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 <ErrorView />;

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/roll-dice/roll-dice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const RollDice: FC = () => {
isAnimated
/>

{dice && <RollingDice dice={dice} dieColor={dieColor} />}
{!!dice && !!dice.length && <RollingDice dice={dice} dieColor={dieColor} />}

{button()}
</BottomButtonWrapper>
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
8 changes: 4 additions & 4 deletions frontend/src/hooks/use-timer.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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 };
};
2 changes: 1 addition & 1 deletion frontend/src/pages/match/match.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ export const Match: FC<MatchProps> = ({ matchId }) => {
if (!parsed.success) return;

setTimerTimeInSeconds(parsed.data.remainingStageTime);
clearHistory();
setMatchState(parsed.data.matchState);

break;
}
case MatchOpCode.PLAYER_READY: {
Expand Down
14 changes: 1 addition & 13 deletions frontend/src/service/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -204,7 +193,6 @@ export const useMatch = () => {
isLoading,
sendMatchState,
broadcastPlayerReady,
delayBroadcastPlayerReady,
broadcastPlaceBid,
broadcastCallExact,
broadcastCallBoloney,
Expand Down

0 comments on commit 09bce4b

Please sign in to comment.