Skip to content

Commit

Permalink
Added Event Handler
Browse files Browse the repository at this point in the history
Handles different events and updates the game state accordingly

Also Integrated with GameProvider to handle these events
  • Loading branch information
Abhishek committed Jun 23, 2024
1 parent cc97d5e commit 11c597e
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 20 deletions.
123 changes: 123 additions & 0 deletions frontend/src/clientDispatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { GameEvent, GameEventTypes } from '../../backend/src/types';
import { GameState } from './contexts/GameContext';
import { triggerEvent } from './channel';

export const clientDispatch = (
gameState: GameState,
event: GameEvent
): GameState => {
let newGameState: GameState;

switch (event.type) {
case GameEventTypes.JOIN_GAME:
newGameState = handleJoinGame(gameState, event);
break;
case GameEventTypes.LEAVE_GAME:
newGameState = handleLeaveGame(gameState, event);
break;
case GameEventTypes.DRAW_CARD:
newGameState = handleDrawCard(gameState, event);
break;
case GameEventTypes.THROW_CARD:
newGameState = handleThrowCard(gameState, event);
break;
case GameEventTypes.STATE_SYNC:
newGameState = handleStateSync(gameState, event);
break;
default:
throw new Error(`Unhandled event type: ${event}`);
}

// Trigger the event to the server
triggerEvent(event);

return newGameState;
};

const handleJoinGame = (gameState: GameState, event: GameEvent): GameState => {
if (event.type !== GameEventTypes.JOIN_GAME) {
throw new Error(`Invalid event type for handleJoinGame: ${event.type}`);
}
const { playerId } = event;
return {
...gameState,
players: [...gameState.players, { id: playerId, cards: [] }],
};
};

const handleLeaveGame = (gameState: GameState, event: GameEvent): GameState => {
if (event.type !== GameEventTypes.LEAVE_GAME) {
throw new Error(
`Invalid event type for handleLeaveGame: ${event.type}`
);
}
const { playerId } = event;
return {
...gameState,
players: gameState.players.filter((player) => player.id !== playerId),
};
};

const handleDrawCard = (gameState: GameState, event: GameEvent): GameState => {
if (event.type !== GameEventTypes.DRAW_CARD) {
throw new Error(`Invalid event type for handleDrawCard: ${event.type}`);
}

const { playerId } = event;

// Find the player who drew the card
const updatedPlayers = gameState.players.map((player) => {
if (player.id === playerId) {
// Assume the last card in the player's deck is the drawn card
const drawnCardId = player.cards[player.cards.length - 1]; // Last drawn card
const updatedCards = [...player.cards, drawnCardId];
return { ...player, cards: updatedCards };
}
return player;
});

return {
...gameState,
players: updatedPlayers,
};
};

const handleThrowCard = (gameState: GameState, event: GameEvent): GameState => {
if (event.type !== GameEventTypes.THROW_CARD) {
throw new Error(
`Invalid event type for handleThrowCard: ${event.type}`
);
}
const { playerId, data } = event;
const { cardId } = data;
return {
...gameState,
players: gameState.players.map((player) =>
player.id === playerId
? { ...player, cards: player.cards.filter((c) => c !== cardId) }
: player
),
lastThrownCard: cardId,
};
};

const handleStateSync = (gameState: GameState, event: GameEvent): GameState => {
if (event.type !== GameEventTypes.STATE_SYNC) {
throw new Error(
`Invalid event type for handleStateSync: ${event.type}`
);
}
const { data } = event;
const mappedPlayers = data.players.map((player) => ({
id: player.id,
cards: player.cards.map((card) => card.id),
}));

return {
...gameState,
players: mappedPlayers,
cards: data.cards.map((card) => card.id),
currentTurn: data.currentTurn,
lastThrownCard: data.lastThrownCard,
};
};
37 changes: 17 additions & 20 deletions frontend/src/contexts/GameContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { useLocation, useNavigate } from 'react-router-dom';
import { useAuth } from './AuthContext';
import { useToast } from '../library/toast/toast-context';
import * as channel from '../channel';
import { clientDispatch } from '../clientDispatch';
import { GameEvent } from '../../../backend/src/types';

interface GameState {
export interface GameState {
players: { id: string; cards: string[] }[];
cards: string[];
currentTurn: number;
Expand Down Expand Up @@ -40,7 +42,11 @@ export const GameProvider = () => {
const toast = useToast();
const auth = useAuth();
const backendUrl = process.env.REACT_APP_BACKEND_URL;

const dispatchGameEvent = (event: GameEvent) => {
setGameState((prevState) =>
clientDispatch(prevState as GameState, event)
);
};
useEffect(() => {
if (!auth.isLoggedIn()) {
navigate('/');
Expand Down Expand Up @@ -109,25 +115,16 @@ export const GameProvider = () => {

// polling
useEffect(() => {
// add event listener to listen for the game state changes
channel.setGameEventsDispatcher((event) => {
// todo: this callback will be replaced by the event dispatcher
console.log('Handling event:', event);
if (event.type === 'STATE_SYNC') {
setGameState({
players: event.data.players.map((player) => {
return {
id: player.id,
cards: player.cards.map((card) => card.id),
};
}),
cards: event.data.cards.map((card) => card.id),
currentTurn: event.data.currentTurn,
lastThrownCard: event.data.lastThrownCard,
});
}
channel.setGameEventsDispatcher((event: GameEvent) => {
dispatchGameEvent(event);
});
}, [gameState]);

channel.startPolling();

return () => {
channel.stopPolling();
};
}, []);

return (
<GameContext.Provider value={{ gameState, setGameState }}>
Expand Down

0 comments on commit 11c597e

Please sign in to comment.