Optimisations + lisibilité

This commit is contained in:
Sébastien Rivière
2025-06-18 02:21:32 +02:00
parent c6066bc234
commit 4fd73a35c8
9 changed files with 153 additions and 187 deletions

3
.gitignore vendored
View File

@@ -127,3 +127,6 @@ dist
.yarn/build-state.yml .yarn/build-state.yml
.yarn/install-state.gz .yarn/install-state.gz
.pnp.* .pnp.*
# Other
.vscode/

View File

@@ -8,11 +8,10 @@ import game from "./game.js"
import zone from "./zone_manager.js" import zone from "./zone_manager.js"
import penaltyController from "./penalty_controller.js"; import penaltyController from "./penalty_controller.js";
import { playersBroadcast, sendUpdatedTeamInformations } from "./team_socket.js"; import { playersBroadcast, sendUpdatedTeamInformations } from "./team_socket.js";
import { sha256 } from "./util.js"; import { createHash } from "crypto";
import { config } from "dotenv"; import { config } from "dotenv";
config()
config();
const ADMIN_PASSWORD_HASH = process.env.ADMIN_PASSWORD_HASH; const ADMIN_PASSWORD_HASH = process.env.ADMIN_PASSWORD_HASH;
/** /**
@@ -26,18 +25,18 @@ export function secureAdminBroadcast(event, data) {
}); });
} }
//Array of logged in sockets // Array of logged in sockets
let loggedInSockets = []; let loggedInSockets = [];
export function initAdminSocketHandler() { export function initAdminSocketHandler() {
//Admin namespace // Admin namespace
io.of("admin").on("connection", (socket) => { io.of("admin").on("connection", (socket) => {
//Flag to check if the user is logged in, defined for each socket // Flag to check if the user is logged in, defined for each socket
console.log("Connection of an admin"); console.log("Connection of an admin");
let loggedIn = false; let loggedIn = false;
socket.on("disconnect", () => { socket.on("disconnect", () => {
console.log("Disconnection of an admin"); console.log("Disconnection of an admin");
//Remove the socket from the logged in sockets array // Remove the socket from the logged in sockets array
loggedInSockets = loggedInSockets.filter(s => s !== socket.id); loggedInSockets = loggedInSockets.filter(s => s !== socket.id);
}); });
@@ -45,17 +44,17 @@ export function initAdminSocketHandler() {
loggedInSockets = loggedInSockets.filter(s => s !== socket.id); loggedInSockets = loggedInSockets.filter(s => s !== socket.id);
}) })
//User is attempting to log in // User is attempting to log in
socket.on("login", (password) => { socket.on("login", (password) => {
const hash = sha256(password); const hash = createHash('sha256').update(password).digest('hex');
if (hash === ADMIN_PASSWORD_HASH && !loggedIn) { if (hash === ADMIN_PASSWORD_HASH && !loggedIn) {
//Attempt successful // Attempt successful
socket.emit("login_response", true); socket.emit("login_response", true);
loggedInSockets.push(socket.id); loggedInSockets.push(socket.id);
loggedIn = true; loggedIn = true;
//Send the current state // Send the current state
socket.emit("game_state", game.state) socket.emit("game_state", game.state)
//Other settings that need initialization // Other settings that need initialization
socket.emit("penalty_settings", penaltyController.settings) socket.emit("penalty_settings", penaltyController.settings)
socket.emit("game_settings", game.settings) socket.emit("game_settings", game.settings)
socket.emit("zone_settings", zone.zoneSettings) socket.emit("zone_settings", zone.zoneSettings)
@@ -64,9 +63,8 @@ export function initAdminSocketHandler() {
begin: zone.currentStartZone, begin: zone.currentStartZone,
end: zone.nextZone end: zone.nextZone
}) })
} else { } else {
//Attempt unsuccessful // Attempt unsuccessful
socket.emit("login_response", false); socket.emit("login_response", false);
} }
}); });
@@ -90,7 +88,7 @@ export function initAdminSocketHandler() {
} }
if (!game.setZoneSettings(settings)) { if (!game.setZoneSettings(settings)) {
socket.emit("error", "Error changing zone"); socket.emit("error", "Error changing zone");
socket.emit("zone_settings", zone.zoneSettings) //Still broadcast the old config to the client who submited an incorrect config to keep the client up to date socket.emit("zone_settings", zone.zoneSettings) // Still broadcast the old config to the client who submited an incorrect config to keep the client up to date
} else { } else {
secureAdminBroadcast("zone_settings", zone.zoneSettings) secureAdminBroadcast("zone_settings", zone.zoneSettings)
} }
@@ -111,7 +109,7 @@ export function initAdminSocketHandler() {
}) })
//User is attempting to add a new team // User is attempting to add a new team
socket.on("add_team", (teamName) => { socket.on("add_team", (teamName) => {
if (!loggedIn) { if (!loggedIn) {
socket.emit("error", "Not logged in"); socket.emit("error", "Not logged in");
@@ -124,7 +122,7 @@ export function initAdminSocketHandler() {
} }
}); });
//User is attempting to remove a team // User is attempting to remove a team
socket.on("remove_team", (teamId) => { socket.on("remove_team", (teamId) => {
if (!loggedIn) { if (!loggedIn) {
socket.emit("error", "Not logged in"); socket.emit("error", "Not logged in");
@@ -137,7 +135,7 @@ export function initAdminSocketHandler() {
} }
}); });
//User is attempting to change the game state // User is attempting to change the game state
socket.on("change_state", (state) => { socket.on("change_state", (state) => {
if (!loggedIn) { if (!loggedIn) {
socket.emit("error", "Not logged in"); socket.emit("error", "Not logged in");
@@ -151,9 +149,9 @@ export function initAdminSocketHandler() {
} }
}); });
//Use is sending a new list containing the new order of the teams // Use is sending a new list containing the new order of the teams
//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 // 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 // But the frontend should always send the same teams in a different order
socket.on("reorder_teams", (newOrder) => { socket.on("reorder_teams", (newOrder) => {
if (!loggedIn) { if (!loggedIn) {
socket.emit("error", "Not logged in"); socket.emit("error", "Not logged in");
@@ -179,8 +177,8 @@ export function initAdminSocketHandler() {
} }
}) })
//Request an update of the team list // Request an update of the team list
//We only reply to the sender to prevent spam // We only reply to the sender to prevent spam
socket.on("get_teams", () => { socket.on("get_teams", () => {
if (!loggedIn) { if (!loggedIn) {
socket.emit("error", "Not logged in"); socket.emit("error", "Not logged in");
@@ -188,8 +186,5 @@ export function initAdminSocketHandler() {
} }
socket.emit("teams", game.teams); socket.emit("teams", game.teams);
}); });
}); });
}
}

View File

@@ -2,14 +2,11 @@
This module manages the main game state, the teams, the settings and the game logic This module manages the main game state, the teams, the settings and the game logic
*/ */
import { secureAdminBroadcast } from "./admin_socket.js"; import { secureAdminBroadcast } from "./admin_socket.js";
import { isInCircle } from "./map_utils.js";
import { playersBroadcast, sendUpdatedTeamInformations } from "./team_socket.js"; import { playersBroadcast, sendUpdatedTeamInformations } from "./team_socket.js";
import { isInCircle } from "./map_utils.js";
import timeoutHandler from "./timeoutHandler.js"; import timeoutHandler from "./timeoutHandler.js";
import penaltyController from "./penalty_controller.js"; import penaltyController from "./penalty_controller.js";
import zoneManager from "./zone_manager.js"; import zoneManager from "./zone_manager.js";
import { getDistanceFromLatLon } from "./map_utils.js";
import { writePosition, writeCapture, writeSeePosition } from "./trajectory.js"; import { writePosition, writeCapture, writeSeePosition } from "./trajectory.js";
/** /**
@@ -32,7 +29,7 @@ export default {
loserEndGameMessage: "", loserEndGameMessage: "",
winnerEndGameMessage: "", winnerEndGameMessage: "",
capturedMessage: "", capturedMessage: "",
waitingMessage: "Jeu en préparation, veuillez patienter." waitingMessage: ""
}, },
/** /**
@@ -106,7 +103,7 @@ export default {
* @returns a random 4 digit number * @returns a random 4 digit number
*/ */
createCaptureCode() { createCaptureCode() {
return Math.floor(Math.random() * 10000) return Math.floor(Math.random() * 10000);
}, },
/** /**
@@ -115,9 +112,8 @@ export default {
* @returns true if the team has been added * @returns true if the team has been added
*/ */
addTeam(teamName) { addTeam(teamName) {
let id = this.getNewTeamId();
this.teams.push({ this.teams.push({
id: id, id: this.getNewTeamId(),
name: teamName, name: teamName,
chasing: null, chasing: null,
chased: null, chased: null,
@@ -160,7 +156,7 @@ export default {
updateTeamChasing() { updateTeamChasing() {
if (this.playingTeamCount() <= 2) { if (this.playingTeamCount() <= 2) {
if (this.state == GameState.PLAYING) { if (this.state == GameState.PLAYING) {
this.finishGame() this.finishGame();
} }
return false; return false;
} }
@@ -175,13 +171,13 @@ export default {
} else { } else {
firstTeam = this.teams[i].id; firstTeam = this.teams[i].id;
} }
previousTeam = this.teams[i].id previousTeam = this.teams[i].id;
} }
} }
this.getTeam(firstTeam).chased = previousTeam; this.getTeam(firstTeam).chased = previousTeam;
this.getTeam(previousTeam).chasing = firstTeam; this.getTeam(previousTeam).chasing = firstTeam;
this.getTeam(previousTeam).enemyName = this.getTeam(firstTeam).name; this.getTeam(previousTeam).enemyName = this.getTeam(firstTeam).name;
secureAdminBroadcast("teams", this.teams) secureAdminBroadcast("teams", this.teams);
return true; return true;
}, },
@@ -213,7 +209,7 @@ export default {
updateTeam(teamId, newTeam) { updateTeam(teamId, newTeam) {
this.teams = this.teams.map((t) => { this.teams = this.teams.map((t) => {
if (t.id == teamId) { if (t.id == teamId) {
return { ...t, ...newTeam } return { ...t, ...newTeam };
} else { } else {
return t; return t;
} }
@@ -230,22 +226,20 @@ export default {
* @returns true if the location has been updated * @returns true if the location has been updated
*/ */
updateLocation(teamId, location) { updateLocation(teamId, location) {
let team = this.getTeam(teamId); const team = this.getTeam(teamId);
//The ID does not match any team if (!team || !location) {
if (team == undefined) {
return false;
}
//The location sent by the team will be null if the browser call API dooes not succeed
//See issue #19
if (location == null) {
return false; return false;
} }
// Update of events of the game
writePosition(Date.now(), teamId, location[0], location[1]); writePosition(Date.now(), teamId, location[0], location[1]);
// Update of currentLocation
team.currentLocation = location; team.currentLocation = location;
//Update the team ready status if they are in their starting area // Update of ready (true if the team is in the starting area)
if (this.state == GameState.PLACEMENT && team.startingArea && team.startingArea && location) { if (this.state == GameState.PLACEMENT && team.startingArea && team.startingArea && location) {
team.ready = isInCircle({ lat: location[0], lng: location[1] }, team.startingArea.center, team.startingArea.radius) team.ready = isInCircle({ lat: location[0], lng: location[1] }, team.startingArea.center, team.startingArea.radius);
} }
// Sending new infos to the team
sendUpdatedTeamInformations(team.id);
return true; return true;
}, },
@@ -253,14 +247,14 @@ export default {
* Initialize the last sent location of the teams to their starting location * Initialize the last sent location of the teams to their starting location
*/ */
initLastSentLocations() { initLastSentLocations() {
for (let team of this.teams) { for (const team of this.teams) {
team.lastSentLocation = team.currentLocation; team.lastSentLocation = team.currentLocation;
team.locationSendDeadline = Date.now() + penaltyController.settings.allowedTimeBetweenPositionUpdate * 60 * 1000; team.locationSendDeadline = Date.now() + penaltyController.settings.allowedTimeBetweenPositionUpdate * 60 * 1000;
timeoutHandler.setSendPositionTimeout(team.id, team.locationSendDeadline); timeoutHandler.setSendPositionTimeout(team.id, team.locationSendDeadline);
this.getTeam(team.chasing).enemyLocation = team.lastSentLocation; this.getTeam(team.chasing).enemyLocation = team.lastSentLocation;
sendUpdatedTeamInformations(team.id); sendUpdatedTeamInformations(team.id);
} }
for (let team of this.teams) { for (const team of this.teams) {
team.enemyLocation = this.getTeam(team.chasing).lastSentLocation; team.enemyLocation = this.getTeam(team.chasing).lastSentLocation;
sendUpdatedTeamInformations(team.id); sendUpdatedTeamInformations(team.id);
} }
@@ -272,22 +266,24 @@ export default {
* @returns true if the location has been sent * @returns true if the location has been sent
*/ */
sendLocation(teamId) { sendLocation(teamId) {
let team = this.getTeam(teamId); const team = this.getTeam(teamId);
if (team == undefined) { if (!team || !team.currentLocation) {
return false; return false;
} }
if (team.currentLocation == null) { const dateNow = Date.now();
return false; // Update of events of the game
} writeSeePosition(dateNow, teamId, team.chasing);
writeSeePosition(Date.now(), teamId, team.chasing); // Update of locationSendDeadline
team.locationSendDeadline = Date.now() + penaltyController.settings.allowedTimeBetweenPositionUpdate * 60 * 1000; team.locationSendDeadline = dateNow + penaltyController.settings.allowedTimeBetweenPositionUpdate * 60 * 1000;
timeoutHandler.setSendPositionTimeout(team.id, team.locationSendDeadline); timeoutHandler.setSendPositionTimeout(team.id, team.locationSendDeadline);
// Update of lastSentLocation
team.lastSentLocation = team.currentLocation; team.lastSentLocation = team.currentLocation;
if (this.getTeam(team.chasing) != null) { // Update of enemyLocation
team.enemyLocation = this.getTeam(team.chasing).lastSentLocation; const teamChasing = this.getTeam(team.chasing);
} if (teamChasing) team.enemyLocation = teamChasing.lastSentLocation;
// Sending new infos to the team
sendUpdatedTeamInformations(team.id); sendUpdatedTeamInformations(team.id);
return team; return true;
}, },
/** /**
@@ -296,10 +292,9 @@ export default {
* @returns true if the team has been deleted * @returns true if the team has been deleted
*/ */
removeTeam(teamId) { removeTeam(teamId) {
if (this.getTeam(teamId) == undefined) { if (!this.getTeam(teamId)) {
return false; return false;
} }
//remove the team from the list
this.teams = this.teams.filter(t => t.id !== teamId); this.teams = this.teams.filter(t => t.id !== teamId);
this.updateTeamChasing(); this.updateTeamChasing();
timeoutHandler.endSendPositionTimeout(team.id); timeoutHandler.endSendPositionTimeout(team.id);
@@ -315,14 +310,19 @@ export default {
* @returns {Boolean} if the capture has been successfull or not * @returns {Boolean} if the capture has been successfull or not
*/ */
requestCapture(teamId, captureCode) { requestCapture(teamId, captureCode) {
let enemyTeam = this.getTeam(this.getTeam(teamId).chasing) const team = this.getTeam(teamId);
if (enemyTeam && enemyTeam.captureCode == captureCode) { const enemyTeam = this.getTeam(team.chasing);
writeCapture(Date.now(), teamId, enemyTeam.id); if (!enemyTeam || enemyTeam.captureCode != captureCode) {
this.capture(enemyTeam.id); return false;
this.updateTeamChasing();
return true;
} }
return false; // Update of events of the game
writeCapture(Date.now(), teamId, enemyTeam.id);
// Update of capture and chasing cycle
this.capture(enemyTeam.id);
// Sending new infos to the teams
sendUpdatedTeamInformations(team.id);
sendUpdatedTeamInformations(enemyTeam.id);
return true;
}, },
/** /**
@@ -330,7 +330,7 @@ export default {
* @param {Number} teamId the Id of the captured team * @param {Number} teamId the Id of the captured team
*/ */
capture(teamId) { capture(teamId) {
this.getTeam(teamId).captured = true this.getTeam(teamId).captured = true;
timeoutHandler.endSendPositionTimeout(teamId); timeoutHandler.endSendPositionTimeout(teamId);
this.updateTeamChasing(); this.updateTeamChasing();
}, },
@@ -349,11 +349,10 @@ export default {
var min = newSettings.min; var min = newSettings.min;
var max = newSettings.max; var max = newSettings.max;
// The end zone must be included in the start zone // The end zone must be included in the start zone
var dist = getDistanceFromLatLon(min.center, max.center); if (!isInCircle(min.center, max.center, max.radius-min.radius)) {
if (min.radius + dist >= max.radius) {
return false; return false;
} }
return zoneManager.udpateSettings(newSettings) return zoneManager.udpateSettings(newSettings);
}, },
/** /**
@@ -362,7 +361,7 @@ export default {
finishGame() { finishGame() {
this.setState(GameState.FINISHED); this.setState(GameState.FINISHED);
zoneManager.reset(); zoneManager.reset();
timeoutHandler.endAllSendPositionTimeout() timeoutHandler.endAllSendPositionTimeout();
playersBroadcast("game_state", this.state); playersBroadcast("game_state", this.state);
}, },
} }

View File

@@ -1,19 +1,17 @@
import { createServer } from "http"; import { createServer } from "http";
import express from "express"; import express from "express";
import { Server } from "socket.io"; import { Server } from "socket.io";
import { config } from "dotenv"; import { config } from "dotenv";
import { readFileSync } from "fs";
import { initAdminSocketHandler } from "./admin_socket.js"; import { initAdminSocketHandler } from "./admin_socket.js";
import { initTeamSocket } from "./team_socket.js"; import { initTeamSocket } from "./team_socket.js";
import { initPhotoUpload } from "./photo.js"; import { initPhotoUpload } from "./photo.js";
import { initTrajectories } from "./trajectory.js"; import { initTrajectories } from "./trajectory.js";
//extract admin password from .env file
config(); config();
const HOST = process.env.HOST; const HOST = process.env.HOST;
const PORT = process.env.PORT; const PORT = process.env.PORT;
export const app = express() export const app = express();
const httpServer = createServer({}, app); const httpServer = createServer({}, app);
@@ -21,9 +19,6 @@ httpServer.listen(PORT, HOST, () => {
console.log("Server running on http://" + HOST + ":" + PORT); console.log("Server running on http://" + HOST + ":" + PORT);
}); });
//set cors to allow all origins
export const io = new Server(httpServer, { export const io = new Server(httpServer, {
cors: { cors: {
origin: "*", origin: "*",

View File

@@ -1,3 +1,12 @@
/**
* Convert a angle from degree to radian
* @param {Number} deg angle in degree
* @returns angle in radian
*/
function degToRad(deg) {
return deg * (Math.PI / 180);
}
/** /**
* Compute the distance between two points givent their longitude and latitude * Compute the distance between two points givent their longitude and latitude
* @param {Object} pos1 The first position * @param {Object} pos1 The first position
@@ -5,13 +14,13 @@
* @returns the distance between the two positions in meters * @returns the distance between the two positions in meters
* @see https://gist.github.com/miguelmota/10076960 * @see https://gist.github.com/miguelmota/10076960
*/ */
export function getDistanceFromLatLon({ lat: lat1, lng: lon1 }, { lat: lat2, lng: lon2 }) { function getDistanceFromLatLon({ lat: lat1, lng: lon1 }, { lat: lat2, lng: lon2 }) {
var R = 6371; // Radius of the earth in km var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below var dLat = degToRad(lat2 - lat1);
var dLon = deg2rad(lon2 - lon1); var dLon = degToRad(lon2 - lon1);
var a = var a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(degToRad(lat1)) * Math.cos(degToRad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2) Math.sin(dLon / 2) * Math.sin(dLon / 2)
; ;
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
@@ -19,15 +28,6 @@ export function getDistanceFromLatLon({ lat: lat1, lng: lon1 }, { lat: lat2, lng
return d * 1000; return d * 1000;
} }
/**
* Convert a angle from degree to radian
* @param {Number} deg angle in degree
* @returns angle in radian
*/
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
/** /**
* Check if a GPS point is in a circle * Check if a GPS point is in a circle
* @param {Object} position The position to check, an object with lat and lng fields * @param {Object} position The position to check, an object with lat and lng fields
@@ -37,4 +37,4 @@ function deg2rad(deg) {
*/ */
export function isInCircle(position, center, radius) { export function isInCircle(position, center, radius) {
return getDistanceFromLatLon(position, center) < radius; return getDistanceFromLatLon(position, center) < radius;
} }

View File

@@ -13,7 +13,7 @@ const ALLOWED_MIME = [
"image/gif" "image/gif"
] ]
//Setup multer (the file upload middleware) // Setup multer (the file upload middleware)
const storage = multer.diskStorage({ const storage = multer.diskStorage({
// Save the file in the uploads directory // Save the file in the uploads directory
destination: function (req, file, callback) { destination: function (req, file, callback) {
@@ -27,7 +27,7 @@ const storage = multer.diskStorage({
const upload = multer({ const upload = multer({
storage, storage,
//Only upload the file if it is a valid mime type and the team POST parameter is a valid team // Only upload the file if it is a valid mime type and the team POST parameter is a valid team
fileFilter: function (req, file, callback) { fileFilter: function (req, file, callback) {
if (ALLOWED_MIME.indexOf(file.mimetype) == -1) { if (ALLOWED_MIME.indexOf(file.mimetype) == -1) {
callback(null, false); callback(null, false);
@@ -39,8 +39,7 @@ const upload = multer({
} }
}) })
// Clean the uploads directory
//Clean the uploads directory
function clean() { function clean() {
const files = fs.readdirSync(UPLOAD_DIR); const files = fs.readdirSync(UPLOAD_DIR);
for (const file of files) { for (const file of files) {
@@ -49,7 +48,6 @@ function clean() {
} }
} }
export function initPhotoUpload() { export function initPhotoUpload() {
clean(); clean();
//App handler for uploading a photo and saving it to a file //App handler for uploading a photo and saving it to a file

View File

@@ -15,8 +15,8 @@ import zone from "./zone_manager.js";
* @param {*} data The payload * @param {*} data The payload
*/ */
export function teamBroadcast(teamId, event, data) { export function teamBroadcast(teamId, event, data) {
for (let socketId of game.getTeam(teamId).sockets) { for (const socketId of game.getTeam(teamId).sockets) {
io.of("player").to(socketId).emit(event, data) io.of("player").to(socketId).emit(event, data);
} }
} }
@@ -26,25 +26,19 @@ export function teamBroadcast(teamId, event, data) {
* @param {String} data payload * @param {String} data payload
*/ */
export function playersBroadcast(event, data) { export function playersBroadcast(event, data) {
for (let team of game.teams) { for (const team of game.teams) {
teamBroadcast(team.id, event, data); teamBroadcast(team.id, event, data);
} }
} }
/** /**
* Remove a player from the list of logged in players * Send a socket message to all the players of a team
* @param {Number} id The id of the player to log out * @param {String} teamId The team that will receive the message
*/ */
function logoutPlayer(id) {
for (let team of game.teams) {
team.sockets = team.sockets.filter((sid) => sid != id);
}
}
export function sendUpdatedTeamInformations(teamId) { export function sendUpdatedTeamInformations(teamId) {
let team = game.getTeam(teamId) const team = game.getTeam(teamId);
if (!team) { if (!team) {
return false; return;
} }
team.sockets.forEach(socketId => { team.sockets.forEach(socketId => {
io.of("player").to(socketId).emit("update_team", { io.of("player").to(socketId).emit("update_team", {
@@ -61,6 +55,17 @@ export function sendUpdatedTeamInformations(teamId) {
penalties: team.penalties, penalties: team.penalties,
}) })
}) })
secureAdminBroadcast("teams", game.teams);
}
/**
* Remove a player from the list of logged in players
* @param {Number} id The id of the player to log out
*/
function logoutPlayer(id) {
for (const team of game.teams) {
team.sockets = team.sockets.filter((sid) => sid != id);
}
} }
export function initTeamSocket() { export function initTeamSocket() {
@@ -70,37 +75,33 @@ export function initTeamSocket() {
socket.on("disconnect", () => { socket.on("disconnect", () => {
console.log("Disconnection of a player"); console.log("Disconnection of a player");
logoutPlayer(socket.id) logoutPlayer(socket.id);
}); });
socket.on("login", (loginTeamId, callback) => { socket.on("login", (loginTeamId, callback) => {
let team = game.getTeam(loginTeamId); const team = game.getTeam(loginTeamId);
if (team === undefined) { if (!team) {
socket.emit("login_response", false); callback({ isLoggedIn: false, message: "Login denied" });
if (typeof callback === "function") { return;
callback({ isLoggedIn: false, message: "Login denied" });
}
} else {
logoutPlayer(socket.id)
team.sockets.push(socket.id);
teamId = loginTeamId;
sendUpdatedTeamInformations(loginTeamId);
socket.emit("login_response", true);
socket.emit("game_state", game.state)
socket.emit("game_settings", game.settings)
socket.emit("zone", zone.currentZone)
socket.emit("new_zone", {
begin: zone.currentStartZone,
end: zone.nextZone
})
if (typeof callback === "function") {
callback({ isLoggedIn : true, message: "Logged in"});
}
} }
logoutPlayer(socket.id);
team.sockets.push(socket.id);
teamId = loginTeamId;
sendUpdatedTeamInformations(loginTeamId);
socket.emit("login_response", true);
socket.emit("game_state", game.state);
socket.emit("game_settings", game.settings);
socket.emit("zone", zone.currentZone);
socket.emit("new_zone", {
begin: zone.currentStartZone,
end: zone.nextZone
})
callback({ isLoggedIn : true, message: "Logged in"});
}); });
socket.on("logout", () => { socket.on("logout", () => {
logoutPlayer(socket.id); logoutPlayer(socket.id);
teamId = null;
}) })
socket.on("update_position", (position) => { socket.on("update_position", (position) => {
@@ -108,48 +109,30 @@ export function initTeamSocket() {
// This is done to prevent multiple clients from sending slightly different prosition back and forth // This is done to prevent multiple clients from sending slightly different prosition back and forth
// Making the point jitter on the map // Making the point jitter on the map
if (!teamId) { if (!teamId) {
socket.emit("error", "not logged in yet");
return;
}
let team = game.getTeam(teamId)
if (team == undefined) {
logoutPlayer(socket.id);
return; return;
} }
const team = game.getTeam(teamId);
if (team.sockets.indexOf(socket.id) == 0) { if (team.sockets.indexOf(socket.id) == 0) {
game.updateLocation(teamId, position); game.updateLocation(teamId, position);
teamBroadcast(teamId, "update_team", { currentLocation: team.currentLocation, ready: team.ready });
secureAdminBroadcast("teams", game.teams);
} }
}); });
socket.on("send_position", () => { socket.on("send_position", () => {
game.sendLocation(teamId); if (!teamId) {
let team = game.getTeam(teamId);
if (team === undefined) {
socket.emit("error", "Team not found");
return; return;
} }
game.updateTeamChasing(); game.sendLocation(teamId);
teamBroadcast(teamId, "update_team", { enemyLocation: team.enemyLocation, locationSendDeadline: team.locationSendDeadline, lastSentLocation: team.lastSentLocation });
secureAdminBroadcast("teams", game.teams)
}); });
socket.on("capture", (captureCode, callback) => { socket.on("capture", (captureCode, callback) => {
let capturedTeam = game.getTeam(teamId)?.chasing; if (!teamId) {
if (capturedTeam !== undefined && game.requestCapture(teamId, captureCode)) { return;
sendUpdatedTeamInformations(teamId);
sendUpdatedTeamInformations(capturedTeam);
secureAdminBroadcast("teams", game.teams);
if (typeof callback === "function") {
callback({ hasCaptured : true, message: "Capture successful" });
}
} else {
socket.emit("error", "Incorrect code");
if (typeof callback === "function") {
callback({ hasCaptured : false, message: "Capture failed" });
}
} }
if (!game.requestCapture(teamId, captureCode)) {
callback({ hasCaptured : false, message: "Capture failed" });
return;
}
callback({ hasCaptured : true, message: "Capture successful" });
}) })
}); });
} }

View File

@@ -1,19 +0,0 @@
import { createHash } from "crypto";
/**
* Scale a value that is known to be in a range to a new range
* for instance map(50,0,100,1000,2000) will return 1500 as 50 is halfway between 0 and 100 and 1500 is halfway through 1000 and 2000
* @param {Number} value value to map
* @param {Number} oldMin minimum value of the number
* @param {Number} oldMax maximum value of the number
* @param {Number} newMin minimum value of the output
* @param {Number} newMax maximum value of the output
* @returns
*/
export function map(value, oldMin, oldMax, newMin, newMax) {
return ((value - oldMin) / (oldMax - oldMin)) * (newMax - newMin) + newMin;
}
export function sha256(password) {
return createHash('sha256').update(password).digest('hex');;
}

View File

@@ -1,13 +1,25 @@
/* /*
This module manages the play area during the game, shrinking it over time based of some settings. This module manages the play area during the game, shrinking it over time based of some settings.
*/ */
import { randomCirclePoint } from 'random-location' import { randomCirclePoint } from 'random-location'
import { isInCircle } from './map_utils.js'; import { isInCircle } from './map_utils.js';
import { map } from './util.js';
import { playersBroadcast } from './team_socket.js'; import { playersBroadcast } from './team_socket.js';
import { secureAdminBroadcast } from './admin_socket.js'; import { secureAdminBroadcast } from './admin_socket.js';
/**
* Scale a value that is known to be in a range to a new range
* for instance map(50,0,100,1000,2000) will return 1500 as 50 is halfway between 0 and 100 and 1500 is halfway through 1000 and 2000
* @param {Number} value value to map
* @param {Number} oldMin minimum value of the number
* @param {Number} oldMax maximum value of the number
* @param {Number} newMin minimum value of the output
* @param {Number} newMax maximum value of the output
* @returns
*/
function map(value, oldMin, oldMax, newMin, newMax) {
return ((value - oldMin) / (oldMax - oldMin)) * (newMax - newMin) + newMin;
}
export default { export default {
//Setings storing where the zone will start, end and how it should evolve //Setings storing where the zone will start, end and how it should evolve
//The zone will start by staying at its max value for reductionInterval minutes //The zone will start by staying at its max value for reductionInterval minutes