New feature added: Games automatically saved in database after game

ends in pgn format
This commit is contained in:
Moon Patel
2023-07-07 19:10:48 +05:30
parent 0abd8e0660
commit 8f39b29377
8 changed files with 89 additions and 24 deletions
+1
View File
@@ -8,6 +8,7 @@ const SOCKET_EVENTS = {
CHESS_OPPONENT_MOVE: "opponent-move",
USER_JOINED_ROOM: "user-joined-room",
USER_RESIGNED: "user-resigned",
GAME_END: "game-end",
};
module.exports = {
+52 -8
View File
@@ -1,5 +1,8 @@
const socket = require("socket.io");
const { SOCKET_EVENTS } = require("./constants");
const { Chess } = require("chess.js");
const { User } = require("./models/user");
const { Game } = require("./models/game");
const {
CHESS_MOVE,
CHESS_OPPONENT_MOVE,
@@ -10,8 +13,9 @@ const {
ROOM_FULL,
USER_JOINED_ROOM,
USER_RESIGNED,
GAME_END,
} = SOCKET_EVENTS;
// roomID => { timeLimit,gameHistory , players:[{username: {color}}] }
// roomID => { timeLimit,gameHistory , players:{'b': {username,userid}, 'w':{username,userid} } }
let activeRooms = new Map();
function createRoom(roomID, timeLimit) {
@@ -24,14 +28,18 @@ function getRoom(roomID) {
return activeRooms.get(roomID);
}
// structure of userDetails: {username,color}
function destoryRoom(roomID) {
activeRooms.delete(roomID);
}
// structure of userDetails: {username,userid,color}
function addUserToRoom(roomID, socket, userDetails) {
console.log(userDetails);
let { username, color } = userDetails;
let { username, color, userid } = userDetails;
let room = activeRooms.get(roomID);
if (room.players[username]) {
room.players[username] = { color, socket };
if (room.players[color]) {
room.players[color] = { username, userid, socket };
return JOIN_ROOM_SUCCESS;
}
if (Object.keys(room.players).length > 1) {
@@ -39,7 +47,7 @@ function addUserToRoom(roomID, socket, userDetails) {
console.log(activeRooms);
return ROOM_FULL;
} else {
room.players[username] = { color, socket };
room.players[color] = { username, userid, socket };
}
console.log(activeRooms);
@@ -69,7 +77,7 @@ function socketIOServerInit(server) {
let result = addUserToRoom(roomID, socket, data);
if (result === JOIN_ROOM_SUCCESS) {
socket.join(roomID);
io.to(roomID).emit("new user joined the room");
// io.to(roomID).emit("new user joined the room");
console.log(data, "joined");
let room = getRoom(roomID);
io.to(roomID).emit(USER_JOINED_ROOM, data.username);
@@ -89,9 +97,45 @@ function socketIOServerInit(server) {
socket.to(roomID).emit(CHESS_OPPONENT_MOVE, moveData);
});
socket.on(USER_RESIGNED, (roomID, username) => {
socket.on(USER_RESIGNED, async (roomID, username) => {
socket.to(roomID).emit(USER_RESIGNED, username);
});
socket.on(GAME_END, async (roomID) => {
console.log("Ending game...");
const room = getRoom(roomID);
const black = room.players["b"];
const white = room.players["w"];
io.socketsLeave(roomID);
black.socket.disconnect();
white.socket.disconnect();
// generating pgn
let moves = room.gameHistory;
let chess = new Chess();
for (let move of moves) {
let { from, to } = move;
chess.move({ from, to });
}
let pgn = chess.pgn();
const blackPlayerDoc = await User.findById(black.userid);
const whitePlayerDoc = await User.findById(white.userid);
let gameData = {
white: whitePlayerDoc.id,
black: blackPlayerDoc.id,
timeLimit: room.timeLimit,
roomID,
pgn,
};
const gameDoc = await Game.create(gameData);
blackPlayerDoc.games.push(gameDoc.id);
await blackPlayerDoc.save();
whitePlayerDoc.games.push(gameDoc.id);
await whitePlayerDoc.save();
});
});
}
-1
View File
@@ -25,7 +25,6 @@ function checkAuthMiddleware(req, res, next) {
if (req.method === "OPTIONS") {
return next();
}
console.log(req.headers)
if (!req.headers.authorization) {
console.log("NOT AUTH. AUTH HEADER MISSING.");
return next(new NotAuthError("Not authenticated."));
+10 -6
View File
@@ -46,8 +46,8 @@ const Challenges = () => {
}
}, [])
const acceptChallengeHandler = async ({ challenger, roomID, color, timeLimit }) => {
return async () => {
const acceptChallengeHandler = ({ challenger, roomID, color, timeLimit }) => {
async function handler() {
const res = await deleteChallenge(roomID, 'accept');
if (res?.success) {
localStorage.setItem('myColor', color === 'b' ? 'w' : 'b');
@@ -57,25 +57,29 @@ const Challenges = () => {
navigate(`/game/friend/${roomID}`);
}
}
return handler;
}
const declineChallengeHandler = async ({ challenger, roomID, color, timeLimit }) => {
return async () => {
const declineChallengeHandler = ({ challenger, roomID, color, timeLimit }) => {
async function handler() {
const res = await deleteChallenge(roomID, 'decline');
}
return handler;
}
const deleteChallenge = async (challengeID, response) => {
try {
let url = `${import.meta.env.VITE_BACKEND_HOST}/api/user/${userid}/challenges/${challengeID}?response=${response}`
let response = await fetch(url, {
console.log(url)
let res = await fetch(url, {
method: 'DELETE', headers: {
Authorization: `Bearer ${getAuthToken()}`,
}
})
const resData = await response.json();
const resData = await res.json();
return resData;
} catch (err) {
console.log(err)
setError(err)
}
}
+1
View File
@@ -10,6 +10,7 @@ export const SOCKET_EVENTS = {
CHESS_OPPONENT_MOVE: "opponent-move",
USER_JOINED_ROOM: "user-joined-room",
USER_RESIGNED: "user-resigned",
GAME_END: "game-end",
};
export const DISPATCH_EVENTS = {
+19 -4
View File
@@ -1,7 +1,9 @@
import React, { createContext, useReducer, useRef, useState } from 'react'
import { ChessModified, chessInit } from '../../utils/chess';
import { DISPATCH_EVENTS } from '../constants';
import { DISPATCH_EVENTS, SOCKET_EVENTS } from '../constants';
import { socket } from '../socket';
const { CAPTURE_PIECE, MOVE_PIECE, SELECT_PIECE, JUMP_TO, SET_GAME_HISTORY, END_GAME } = DISPATCH_EVENTS
const { GAME_END } = SOCKET_EVENTS;
export const ChessGameContext = createContext();
// myColor: null, chess: null, chessBoard: null, moveHints: null, selected: null, dispatch: null, handleOpponentMove: null, handleSquareClick: null, getSquareColor: null, isSquareMarked: null, selectPiece: null, handleDrop: null
@@ -23,8 +25,13 @@ const reducer = (state, action) => {
let { san, after } = newChessObj.move(action.val);
updatedGameHistory.push({ move: san, fen: after });
if (newChessObj.isCheckmate()) {
socket.emit(GAME_END, localStorage.getItem('roomID'));
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'CHECKMATE' };
} else {
} else if (newChessObj.isStalemate()) {
socket.emit(GAME_END, localStorage.getItem('roomID'));
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'STALEMATE' };
}
else {
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 };
}
}
@@ -36,8 +43,13 @@ const reducer = (state, action) => {
let { san, after } = newChessObj.move(action.val);
updatedGameHistory.push({ move: san, fen: after });
if (newChessObj.isCheckmate()) {
socket.emit(GAME_END, localStorage.getItem('roomID'));
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'CHECKMATE' };
} else {
} else if (newChessObj.isStalemate()) {
socket.emit(GAME_END, localStorage.getItem('roomID'));
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'STALEMATE' };
}
else {
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 };
}
}
@@ -83,6 +95,7 @@ function chessGameStateInit(myColor) {
// some functions to update game state.
const ChessGameContextProvider = ({ children }) => {
let myColor = localStorage.getItem('myColor');
let roomID = localStorage.getItem('roomID');
console.log('INSIDE CONTEXT PROVIDER');
const [{ chess, chessBoard, moveHints, selected, gameHistory, currentIndex, hasGameEnded, gameEndedReason }, dispatch] = useReducer(reducer, myColor, chessGameStateInit);
const [isTimerOn, setIsTimerOn] = useState(true);
@@ -182,6 +195,7 @@ const ChessGameContextProvider = ({ children }) => {
if (currentIndex === -1 || gameHistory.length === 0) {
return new ChessModified({ color: myColor }).getBoard(myColor);
} else {
// console.log(chess);
let currentChessBoard = new ChessModified({ prop: gameHistory[currentIndex].fen, color: myColor }).getBoard(myColor);
return currentChessBoard;
}
@@ -206,13 +220,14 @@ const ChessGameContextProvider = ({ children }) => {
function endGame(reason) {
dispatch({ type: END_GAME, val: reason })
socket.emit(GAME_END, roomID);
}
return (
<ChessGameContext.Provider value={{
myColor, chessBoard, moveHints, selected, handleOpponentMove, handleSquareClick, getSquareColor, isSquareMarked,
selectPiece, handleDrop, gameHistory, jumpTo, getChessBoard, currentIndex, goAhead, goBack, setGameHistory,
isTimerOn, hasGameEnded, gameEndedReason,endGame
isTimerOn, hasGameEnded, gameEndedReason, endGame
}}>
{children}
<audio src='/src/assets/move-self.mp3' ref={moveAudioRef} />
+3 -3
View File
@@ -34,12 +34,12 @@ const useStyles = createStyles((theme) => ({
const ChessBoard = () => {
const { classes } = useStyles();
const { getChessBoard, handleOpponentMove, handleDrop,hasGameEnded,gameEndedReason } = useContext(ChessGameContext)
const { getChessBoard, handleOpponentMove, handleDrop, hasGameEnded, gameEndedReason } = useContext(ChessGameContext)
let roomID = localStorage.getItem('roomID');
const chessBoard = getChessBoard();
if(hasGameEnded) {
console.log('Game ended due to',gameEndedReason)
if (hasGameEnded) {
console.log('Game ended due to', gameEndedReason)
} else {
console.log('Game not ended yet')
}
+3 -2
View File
@@ -17,6 +17,7 @@ const ChessGame = () => {
const user = getUserData();
let username = user.username;
let userid = user.id;
let color = localStorage.getItem('myColor');
const [hasJoinedRoom, setHasJoinedRoom] = useState(localStorage.getItem('socketid'));
const [isWaiting, setIsWaiting] = useState(true);
@@ -36,7 +37,7 @@ const ChessGame = () => {
}
const resign = () => {
socket.emit(USER_RESIGNED,roomID, username);
socket.emit(USER_RESIGNED, roomID, username);
endGame('RESIGN');
exitGame();
}
@@ -62,7 +63,7 @@ const ChessGame = () => {
})
console.log('JOINING ROOM')
socket.emit(JOIN_ROOM, roomID, { username, color })
socket.emit(JOIN_ROOM, roomID, { username, color, userid })
socket.on(DISCONNECT, (reason) => {
console.log('Socket disconnected due to', reason);