New feature added: Games automatically saved in database after game
ends in pgn format
This commit is contained in:
@@ -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
@@ -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();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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."));
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user