From 4853e5edd9a2622ceb57aa1e1381571e739d12c8 Mon Sep 17 00:00:00 2001 From: Moon Patel Date: Mon, 3 Jul 2023 01:12:47 +0530 Subject: [PATCH] THIS IS A MAJOR MILESTONE Socket connection re-implemented. Everything is working fine now. All thats left to do is to make the app robust and handle some edge cases. TODO - The friends list is maybe hardcoded or whatever I dont know, but the problem is it shows the same username no matter who the signed in user is. I need to fix that. - Whenever the pawn reaches to tha last square for promotion an 'Invalid move' error is thrown by the Chess class. Need to fix that too. - Need to disable the chessboard (so user cannot make any moves) until the opponent has joined the game. - Set timers for the game. - Need to show the loading states in various places in the app. - Improve the backend such that a user cannot create more than one room at a time. - Remove hardcoded values from various places. - Make the app responsive. The UI is good on desktop but it is very bad on mobile. - Add a feature to search and add friends. - Destroying the rooms when the match ends and set timers for auto destruction after a certain time. - Need some logic to save games in the history. - Add some tests. --- backend/routes/room.js | 19 ++++-- backend/socket.js | 38 +++++++---- frontend/.gitignore | 3 +- frontend/src/components/Cell.jsx | 1 - frontend/src/components/Challenges.jsx | 15 ++-- frontend/src/pages/Chess/ChessGame.jsx | 76 +++++++++++++++------ frontend/src/pages/Play/ChallengeFriend.jsx | 15 ++-- frontend/src/pages/Play/ChessBoard.jsx | 7 +- 8 files changed, 113 insertions(+), 61 deletions(-) diff --git a/backend/routes/room.js b/backend/routes/room.js index 5f11172..ab5c611 100644 --- a/backend/routes/room.js +++ b/backend/routes/room.js @@ -10,24 +10,29 @@ const pendingChallenges = new Map(); // and vice versa is not true router.post("/create", checkAuth, async (req, res, next) => { console.log(req.body); - // challenger and challenged are username - const { challenger, challenged } = req.body; + // challenger and challenged are username, color is the color played by challenger, timeLimit is the timeLimit for one player + const { challenger, challenged, color, timeLimit } = req.body; - const challengedEmail = (await User.findOne({ username: challenged })).email; - console.log(challengedEmail); + // get email of the challenged person + // const challengedEmail = (await User.findOne({ username: challenged })).email; + // console.log(challengedEmail); const roomID = uuid.v4(); - createRoom(roomID, req.body.timeLimit); + createRoom(roomID, timeLimit); + // create a challenge and add it to pendingChallenges to notify the challenged user + // structure of challenge: {challenger,roomID,color,timeLimit} if (pendingChallenges.has(challenged)) { let challenges = pendingChallenges.get(challenged); - challenges.push(challenger); + challenges.push({ challenger, roomID, color, timeLimit }); } else { - pendingChallenges.set(challenged, [{ challenger, roomID }]); + // color is the choosed by the challenger + pendingChallenges.set(challenged, [{ challenger, roomID, color, timeLimit }]); } console.log("Pending challenges", pendingChallenges); + // STOP SENDING EMAILS FOR NOW // sendEmail( // challengedEmail, // `Challenge from ${challenger}`, diff --git a/backend/socket.js b/backend/socket.js index d97e96f..1a4f6d4 100644 --- a/backend/socket.js +++ b/backend/socket.js @@ -1,37 +1,43 @@ const socket = require("socket.io"); +// roomID => { timeLimit, players:[{username: {color}}] } let activeRooms = new Map(); function createRoom(roomID, timeLimit) { console.log(roomID, "created"); - activeRooms.set(roomID, { timeLimit, players: [] }); + activeRooms.set(roomID, { timeLimit, players: {} }); console.log("Currently active rooms", activeRooms.size); } // structure of userDetails: {username,color} function addUserToRoom(roomID, userDetails) { + console.log(userDetails); let { username, color } = userDetails; let room = activeRooms.get(roomID); - if (room.players) { - // room is full - if (Object.keys(room.players).length > 1) { - return "room-full"; - } else { - // only one user in room - room.players[username].color = color; - } - } else { - // add player in the room - room.players = {}; - room.players[username].color = color; + if (room.players[username]) { + room.players[username] = { color }; + return "join-room-success"; } + if (Object.keys(room.players).length > 1) { + // room is full + console.log(activeRooms); + return "room-full"; + } else { + room.players[username] = { color }; + } + console.log(activeRooms); + return "join-room-success"; } // initialize the socket server with the given http server instance function socketIOServerInit(server) { - const io = new socket.Server(server); + const io = new socket.Server(server, { + cors: { + origin: process.env.CORS_ALLOWED_HOST, + }, + }); io.on("connection", (socket) => { let id = socket.id; @@ -57,6 +63,10 @@ function socketIOServerInit(server) { socket.emit("join-room-error", "room does not exist"); } }); + + socket.on("move", (roomID, moveData) => { + socket.to(roomID).emit("opponent-move", moveData); + }); }); } diff --git a/frontend/.gitignore b/frontend/.gitignore index 3b0b403..86f19b9 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -23,4 +23,5 @@ dist-ssr *.sln *.sw? -.env \ No newline at end of file +.env +test.jsx \ No newline at end of file diff --git a/frontend/src/components/Cell.jsx b/frontend/src/components/Cell.jsx index aeb5a2f..0600d06 100644 --- a/frontend/src/components/Cell.jsx +++ b/frontend/src/components/Cell.jsx @@ -10,7 +10,6 @@ const Cell = ({ cell, chess, marked, dispatch }) => { const [isDropped, setIsDropped] = useState(false); let squareColor = chess.squareColor(square) === 'light' ? "w" : "b"; - console.log(chess.turn() !== localStorage.getItem('my_color')) const handleClick = () => { if (chess.turn() !== localStorage.getItem('my_color')) return; if (chess.myColor === color) { diff --git a/frontend/src/components/Challenges.jsx b/frontend/src/components/Challenges.jsx index 55ce461..558d634 100644 --- a/frontend/src/components/Challenges.jsx +++ b/frontend/src/components/Challenges.jsx @@ -5,10 +5,6 @@ import { getUserData } from '../../utils/auth' const Challenges = () => { const navigate = useNavigate(); - const dummyChallenges = [ - { challenger: 'moonpatel', roomID: 'sgnkjsdbnojsnvjsdnkl' }, - { challenger: 'user1', roomID: 'sgnkjsdbnojsnvjsdnkl' } - ] const [challenges, setChallenges] = useState([]); const { username } = getUserData() @@ -58,12 +54,19 @@ const Challenges = () => { Challenges { - challenges.map(({ challenger, roomID }) => { + challenges.map(({ challenger, roomID, color, timeLimit }) => { + console.log(challenger, roomID, color, timeLimit); return ( Challenge by {challenger} - + diff --git a/frontend/src/pages/Chess/ChessGame.jsx b/frontend/src/pages/Chess/ChessGame.jsx index e272986..f8d389f 100644 --- a/frontend/src/pages/Chess/ChessGame.jsx +++ b/frontend/src/pages/Chess/ChessGame.jsx @@ -8,41 +8,75 @@ import { getUserData } from '../../../utils/auth' const ChessGame = () => { const user = getUserData(); let username = user.username; + let color = localStorage.getItem('myColor') const [hasJoinedRoom, setHasJoinedRoom] = useState(localStorage.getItem('socketid')); const [isWaiting, setIsWaiting] = useState(true); - const roomID = useParams()['roomID']; + const roomID = localStorage.getItem('roomID') const navigate = useNavigate(); const exitGame = () => { localStorage.removeItem('socketid'); localStorage.removeItem('roomID'); localStorage.removeItem('opponent'); - localStorage.removeItem('my_color'); - localStorage.removeItem('time_limit'); + localStorage.removeItem('myColor'); + localStorage.removeItem('timeLimit'); socket.disconnect(); navigate('/play/friend'); } useEffect(() => { - if (hasJoinedRoom) { - } else { - console.log('Connecting'); - socket.connect(); - socket.on('connect', () => { - localStorage.setItem('socketid', socket.id); - console.log('Connected'); - }); - socket.emit('join-room', roomID, username, localStorage.getItem('opponent'), { color: localStorage.getItem('my_color'), timeLimit: localStorage.getItem('time_limit') }); - socket.on('joined-room', () => { - setHasJoinedRoom(true); - }); - socket.on('room-created', () => { - console.log('Room is created') - setIsWaiting(false); - }); - } + socket.connect(); + + socket.on('connect', () => { + console.log('Connected'); + }); + + socket.on('join-room-success', () => { + console.log('Room joined:', roomID); + setHasJoinedRoom(true); + }); + + socket.on('room-full', () => { + console.log('Room is full'); + }) + + socket.on("join-room-error", (err) => { + console.error("Error:", err); + }) + + console.log('JOINING ROOM') + socket.emit("join-room", roomID, { username, color }) + + socket.on('disconnect', (reason) => { + console.log('Socket disconnected due to', reason); + }) + + socket.on('opponent-move', (data) => { + console.log(data) + }) + }, []); + // useEffect(() => { + // if (hasJoinedRoom) { + // } else { + // console.log('Connecting'); + // socket.connect(); + // socket.on('connect', () => { + // localStorage.setItem('socketid', socket.id); + // console.log('Connected'); + // }); + // socket.emit('join-room', roomID, username, localStorage.getItem('opponent'), { color: localStorage.getItem('myColor'), timeLimit: localStorage.getItem('timeLimit') }); + // socket.on('joined-room', () => { + // setHasJoinedRoom(true); + // }); + // socket.on('room-created', () => { + // console.log('Room is created') + // setIsWaiting(false); + // }); + // } + // }, []); + if (!hasJoinedRoom) return ( ) @@ -56,7 +90,7 @@ const ChessGame = () => { icon={} description={"description"} /> - + { @@ -23,7 +21,7 @@ const ChallengeFriend = () => { {friend_username[0].toUpperCase()} {friend_username} -