diff --git a/src/components/ChatBox.tsx b/src/components/ChatBox.tsx index 1d9ac91..4df5ed2 100644 --- a/src/components/ChatBox.tsx +++ b/src/components/ChatBox.tsx @@ -10,7 +10,7 @@ import { IRootState } from "~/store/Store"; import { addChatMessage, populateChatFromPacket } from "~/store/ChatSlice"; import { ChatMessageType } from "~/types/ChatMessageType"; -import { ChatMessagesRequest, ChatMessagesSyncPacket, NewChatMessageSentPacket, SendNewChatMessagePacket } from "~/types/PacketType"; +import { ChatMessagesRequestPacket, ChatMessagesSyncPacket, NewChatMessageSentPacket, SendNewChatMessagePacket } from "~/types/PacketType"; type ChatBoxArgs = { @@ -41,7 +41,7 @@ export default function ChatBox({ visible }: ChatBoxArgs) { }); - const getChatMessagesPacket: ChatMessagesRequest = {packetType: "chatMessagesRequest"}; + const getChatMessagesPacket: ChatMessagesRequestPacket = {packetType: "chatMessagesRequest"}; serverConnection.send(getChatMessagesPacket); return () => { diff --git a/src/components/GameLog.tsx b/src/components/GameLog.tsx index a3218d9..5587dad 100644 --- a/src/components/GameLog.tsx +++ b/src/components/GameLog.tsx @@ -1,7 +1,14 @@ -import { useEffect, useRef, } from "react"; -import { useSelector } from "react-redux"; +import { useContext, useEffect, useRef } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +import WebSocketConnection, { WebSocketServerPacketSubscription } from "~/lib/WebSocketConnection"; +import { addGameLogMessage, populateGameLogFromPacket } from "~/store/GameData"; + +import { ServerConnectionContext } from "~/store/ServerConnectionContext"; import { IRootState } from "~/store/Store"; +import { GameLogMessagesRequestPacket, GameLogMessagesSyncPacket, NewGameLogMessageSentPacket } from "~/types/PacketType"; + type GameLogArgs = { visible: boolean @@ -9,22 +16,47 @@ type GameLogArgs = { export default function ChatBox({ visible }: GameLogArgs) { + const serverConnection = useContext(ServerConnectionContext) as WebSocketConnection; const gameLog = useSelector((state: IRootState) => (state.gameDataReducer.gameLog)); + const dispatch = useDispatch(); + const endOfMessages = useRef(null); + useEffect(() => { + // This should only be called once per client (on page load) in theory, but technically the server can send this whenever it wants + const gameLogMessagesSyncSubscription = serverConnection.subscribeToServerPacket("gameLogMessagesSync", (packet) => { + packet = packet as GameLogMessagesSyncPacket; + dispatch(populateGameLogFromPacket(packet)); + }); + + const gameLogMessageSubscription: WebSocketServerPacketSubscription = serverConnection.subscribeToServerPacket("newGameLogMessageSent", (packet) => { + packet = packet as NewGameLogMessageSentPacket; + dispatch(addGameLogMessage(packet)); + }); + + + const getGameLogMessagesPacket: GameLogMessagesRequestPacket = { packetType: "gameLogMessagesRequest" }; + serverConnection.send(getGameLogMessagesPacket); + + return () => { + serverConnection.unsubscribeFromServerPacket(gameLogMessageSubscription); + serverConnection.unsubscribeFromServerPacket(gameLogMessagesSyncSubscription); + }; + }, []); + // Always move to the bottom useEffect(() => { - endOfMessages.current?.scrollIntoView({behavior: "instant"}); + endOfMessages.current?.scrollIntoView({ behavior: "instant" }); }, [gameLog]); return ( visible ? <> -
+
{gameLog.map((message, index) =>

{message.message}

)}
-
-
+ +
: <> ); diff --git a/src/components/MainGameUI.tsx b/src/components/MainGameUI.tsx index a4a44c7..8059296 100644 --- a/src/components/MainGameUI.tsx +++ b/src/components/MainGameUI.tsx @@ -91,11 +91,6 @@ export default function MainGameUI() { alert(packet.reason); }); - const newGameLogMessageSentSubscription = serverConnection.subscribeToServerPacket("newGameLogMessageSent", (packet) => { - packet = packet as NewGameLogMessageSentPacket; - dispatch(addGameLogMessage(packet)); - }); - // Trigger the initial UI population *after* we've setup the callbacks const getGameInfoPacket: GameDataRequestPacket = { packetType: "gameDataRequest" }; diff --git a/src/store/GameData.ts b/src/store/GameData.ts index fcbd295..b7201e0 100644 --- a/src/store/GameData.ts +++ b/src/store/GameData.ts @@ -1,7 +1,7 @@ import { createSlice } from "@reduxjs/toolkit"; import { GameDataType } from "~/types/GameDataType"; -import { GameDataSyncPacket, NewGameLogMessageSentPacket, NewRoundStartedPacket, PlayerShotAtPacket, TurnStartedPacket } from "~/types/PacketType"; +import { GameDataSyncPacket, GameLogMessagesSyncPacket, NewGameLogMessageSentPacket, NewRoundStartedPacket, PlayerShotAtPacket, TurnStartedPacket } from "~/types/PacketType"; import { PlayerType } from "~/types/PlayerType"; @@ -37,6 +37,9 @@ export const gameDataSlice = createSlice({ setCurrentTurn: (state, action: {payload: TurnStartedPacket}) => { state.currentTurn = action.payload.username; }, + populateGameLogFromPacket: (state, action: {payload: GameLogMessagesSyncPacket}) => { + state.gameLog = action.payload.messages; + }, addGameLogMessage: (state, action: {payload: NewGameLogMessageSentPacket}) => { state.gameLog.push(action.payload.message); }, @@ -58,10 +61,9 @@ export const gameDataSlice = createSlice({ state.gameStarted = action.payload.gameData.gameStarted; state.currentTurn = action.payload.gameData.currentTurn; state.gameID = action.payload.gameData.gameID; - state.gameLog = action.payload.gameData.gameLog; } } }); -export const {addPlayer, setClientUsername, setCurrentHost, onGameStarted, setCurrentTurn, addGameLogMessage, newRoundStarted, playerShotAt, populateGameDataFromPacket} = gameDataSlice.actions; +export const {addPlayer, setClientUsername, setCurrentHost, onGameStarted, setCurrentTurn, populateGameLogFromPacket, addGameLogMessage, newRoundStarted, playerShotAt, populateGameDataFromPacket} = gameDataSlice.actions; export default gameDataSlice.reducer; diff --git a/src/types/PacketType.ts b/src/types/PacketType.ts index 2ea75b8..0d66bf2 100644 --- a/src/types/PacketType.ts +++ b/src/types/PacketType.ts @@ -110,6 +110,11 @@ export type ChatMessagesSyncPacket = { messages: ChatMessageType[] }; +export type GameLogMessagesSyncPacket = { + packetType: "gameLogMessagesSync", + messages: GameLogMessageType[] +}; + export type ShowAlertPacket = { packetType: "showAlert", content: string @@ -181,10 +186,14 @@ export type SendNewChatMessagePacket = { content: string }; -export type ChatMessagesRequest = { +export type ChatMessagesRequestPacket = { packetType: "chatMessagesRequest" }; +export type GameLogMessagesRequestPacket = { + packetType: "gameLogMessagesRequest" +}; + export type ServerPacket = ( | GameDataSyncPacket | PlayerJoinedPacket @@ -205,6 +214,7 @@ export type ServerPacket = ( | StealItemUsedPacket | NewChatMessageSentPacket | ChatMessagesSyncPacket + | GameLogMessagesSyncPacket | ShowAlertPacket | NewGameLogMessageSentPacket ); @@ -223,7 +233,8 @@ export type ClientPacket = ( | UseQuickshotItemPacket | UseStealItemPacket | SendNewChatMessagePacket - | ChatMessagesRequest + | ChatMessagesRequestPacket + | GameLogMessagesRequestPacket ); export type Packet = ServerPacket | ClientPacket;