diff --git a/traque-back/game.js b/traque-back/game.js index bfd6c59..f8e610f 100644 --- a/traque-back/game.js +++ b/traque-back/game.js @@ -1,3 +1,5 @@ +import { isInCircle } from "./map_utils.js"; + const GameState = { SETUP: "setup", PLACEMENT: "placement", @@ -15,6 +17,10 @@ export default class Game { if(Object.values(GameState).indexOf(newState) == -1) { return false; } + //The game has started + if(this.state == GameState.PLACEMENT && newState == GameState.PLAYING) { + this.initLastSentLocations(); + } this.state = newState; return true; } @@ -43,7 +49,8 @@ export default class Game { enemyLocation: null, captureCode: this.createCaptureCode(), sockets: [], - startingArea: null + startingArea: null, + ready: false, }); this.updateTeamChasing(); return true; @@ -80,27 +87,30 @@ export default class Game { return t; } }) - console.log(this.teams) return true; } - // renameTeam(teamId, newName) { - // let team = this.getTeam(teamId); - // if(team == undefined) { - // return false; - // } - // team.name = newName; - // return true; - // } - + updateLocation(teamId, location) { let team = this.getTeam(teamId); if(team == undefined) { return false; } team.currentLocation = location; + //Update the team ready status if they are in their starting area + if(this.state == GameState.PLACEMENT && team.startingArea && team.startingArea && location) { + team.ready = isInCircle(location, [team.startingArea.center.lat, team.startingArea.center.lng], team.startingArea.radius) + } return true; } + //Make it so that when a team requests the location of a team that has never sent their locaiton + //Their position at the begining of the game is sent + initLastSentLocations() { + for(let team of this.teams) { + team.lastSentLocation = team.currentLocation; + } + } + sendLocation(teamId) { let team = this.getTeam(teamId); if(team == undefined) { diff --git a/traque-back/index.js b/traque-back/index.js index ae73fba..c3165c4 100644 --- a/traque-back/index.js +++ b/traque-back/index.js @@ -40,14 +40,20 @@ function secureBroadcast(event, data) { } function teamBroadcast(teamId, event, data) { - for(let socketId of game.getTeam(teamId).sockets) { - io.of("player").to(socketId).emit(event,data) + for (let socketId of game.getTeam(teamId).sockets) { + io.of("player").to(socketId).emit(event, data) } } -function playersBroadcast(event,data) { - for(let team of game.teams) { - teamBroadcast(team.id,event,data); +function playersBroadcast(event, data) { + for (let team of game.teams) { + teamBroadcast(team.id, event, data); + } +} + +function logoutPlayer(id) { + for (let team of game.teams) { + team.sockets = team.sockets.filter((sid) => sid != id); } } @@ -70,6 +76,10 @@ io.of("admin").on("connection", (socket) => { loggedInSockets = loggedInSockets.filter(s => s !== socket.id); }); + socket.on("logout", () => { + loggedInSockets = loggedInSockets.filter(s => s !== socket.id); + }) + //User is attempting to log in socket.on("login", (password) => { if (password === ADMIN_PASSWORD && !loggedIn) { @@ -87,40 +97,40 @@ io.of("admin").on("connection", (socket) => { //User is attempting to add a new team socket.on("add_team", (teamName) => { - if(!loggedIn) { + if (!loggedIn) { socket.emit("error", "Not logged in"); return; } - if(game.addTeam(teamName)) { + if (game.addTeam(teamName)) { secureBroadcast("teams", game.teams); - }else { + } else { socket.emit("error", "Error adding team"); } }); //User is attempting to remove a team socket.on("remove_team", (teamId) => { - if(!loggedIn) { + if (!loggedIn) { socket.emit("error", "Not logged in"); return; } - if(game.removeTeam(teamId)) { + if (game.removeTeam(teamId)) { secureBroadcast("teams", game.teams); - }else { + } else { socket.emit("error", "Error removing team"); } }); //User is attempting to change the game state socket.on("change_state", (state) => { - if(!loggedIn) { + if (!loggedIn) { socket.emit("error", "Not logged in"); return; } - if(game.setState(state)) { + if (game.setState(state)) { secureBroadcast("game_state", game.state); playersBroadcast("game_state", game.state) - }else { + } else { socket.emit("error", "Error setting state"); } }); @@ -129,11 +139,11 @@ io.of("admin").on("connection", (socket) => { //Note that we never check if the new order contains the same teams as the old order, so it behaves more like a setTeams function //But the frontend should always send the same teams in a different order socket.on("reorder_teams", (newOrder) => { - if(!loggedIn) { + if (!loggedIn) { socket.emit("error", "Not logged in"); return; } - if(game.reorderTeams(newOrder)) { + if (game.reorderTeams(newOrder)) { secureBroadcast("teams", game.teams); } else { socket.emit("error", "Error reordering teams"); @@ -141,11 +151,11 @@ io.of("admin").on("connection", (socket) => { }); socket.on("update_team", (teamId, newTeam) => { - if(!loggedIn) { + if (!loggedIn) { socket.emit("error", "Not logged in"); return; } - if(game.updateTeam(teamId, newTeam)) { + if (game.updateTeam(teamId, newTeam)) { secureBroadcast("teams", game.teams); sendUpdatedTeamInformations(teamId) } @@ -154,11 +164,11 @@ io.of("admin").on("connection", (socket) => { //Request an update of the team list //We only reply to the sender to prevent spam socket.on("get_teams", () => { - if(!loggedIn) { + if (!loggedIn) { socket.emit("error", "Not logged in"); return; } - socket.emit("teams", game.teams); + socket.emit("teams", game.teams); }); }); @@ -173,7 +183,8 @@ function sendUpdatedTeamInformations(teamId) { currentLocation: team.currentLocation, lastSentLocation: team.lastSentLocation, captureCode: team.captureCode, - startingArea: team.startingArea + startingArea: team.startingArea, + ready: team.ready }) }) } @@ -184,46 +195,50 @@ io.of("player").on("connection", (socket) => { socket.on("disconnect", () => { console.log("user disconnected"); - if(teamId !== null && game.getTeam(teamId) !== undefined){ - game.getTeam(teamId).sockets = game.getTeam(teamId).sockets.filter(s => s !== socket.id); - } + logoutPlayer(socket.id) }); socket.on("login", (loginTeamId) => { - if(game.getTeam(loginTeamId) === undefined) { + if (game.getTeam(loginTeamId) === undefined) { socket.emit("login_response", false); return; } + logoutPlayer(socket.id) teamId = loginTeamId; let team = game.getTeam(loginTeamId); team.sockets.push(socket.id); - socket.emit("login_response", true); sendUpdatedTeamInformations(loginTeamId); + socket.emit("login_response", true); socket.emit("game_state", game.state) }); + socket.on("logout", () => { + logoutPlayer(socket.id); + }) + socket.on("update_position", (position) => { // Only the first player to connect to the team socket can update the current position // This is done to prevent multiple clients from sending slightly different prosition back and forth // Making the point jitter on the map - if(!teamId) { + if (!teamId) { socket.emit("error", "not logged in yet"); return; } - if(game.getTeam(teamId).sockets.indexOf(socket.id) == 0) { + let team = game.getTeam(teamId) + if (team.sockets.indexOf(socket.id) == 0) { game.updateLocation(teamId, position); - teamBroadcast(teamId, "update_team", {currentLocation: position}); + teamBroadcast(teamId, "update_team", { currentLocation: team.currentLocation, ready: team.ready }); } }); - + socket.on("send_position", () => { game.sendLocation(teamId); let team = game.getTeam(teamId); - if(team === undefined) { + if (team === undefined) { socket.emit("error", "Team not found"); return; } game.updateTeamChasing(); - teamBroadcast(teamId, "update_team", {enemyLocation: team.enemyLocation}); + teamBroadcast(teamId, "update_team", { enemyLocation: team.enemyLocation }); }); }); diff --git a/traque-back/map_utils.js b/traque-back/map_utils.js new file mode 100644 index 0000000..646cfb3 --- /dev/null +++ b/traque-back/map_utils.js @@ -0,0 +1,21 @@ +function getDistanceFromLatLon([lat1, lon1], [lat2, lon2]) { + var R = 6371; // Radius of the earth in km + var dLat = deg2rad(lat2-lat1); // deg2rad below + var dLon = deg2rad(lon2-lon1); + var a = + Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * + Math.sin(dLon/2) * Math.sin(dLon/2) + ; + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + var d = R * c; // Distance in km + return d * 1000; +} + +function deg2rad(deg) { + return deg * (Math.PI/180) +} + +export function isInCircle(position, center, radius) { + return getDistanceFromLatLon(position, center) < radius; +} \ No newline at end of file