snakeia-server 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/server.js CHANGED
@@ -40,12 +40,8 @@ const { doubleCsrf } = require("csrf-csrf");
40
40
  const bodyParser = require("body-parser");
41
41
  const node_config = require("config");
42
42
 
43
- const games = {}; // Contains all the games processed by the server
44
43
  process.env["ALLOW_CONFIG_MUTATIONS"] = true;
45
44
  let config = node_config.get("ServerConfig"); // Server configuration (see default config file config.json)
46
- const tokens = []; // User tokens
47
- const invalidatedUserTokens = []; // Invalidated user tokens
48
- const invalidatedAdminTokens = []; // Invalidated admin tokens
49
45
 
50
46
  // Load config file
51
47
  const configSources = node_config.util.getConfigSources();
@@ -96,114 +92,17 @@ i18n.configure({
96
92
 
97
93
  // Game modules
98
94
  const snakeia = require("snakeia");
95
+ const { randomUUID } = require("crypto");
99
96
  const Snake = snakeia.Snake;
100
97
  const Grid = snakeia.Grid;
101
98
  const GameConstants = snakeia.GameConstants;
102
99
  const GameEngine = config.enableMultithreading ? require("./GameEngineMultithreadingController")(logger) : snakeia.GameEngine;
100
+ const Player = require("./Player");
103
101
 
104
- class Player {
105
- constructor(token, id, snake, ready, version) {
106
- this.token = token;
107
- this.id = id;
108
- this.snake = snake;
109
- this.ready = ready;
110
- this.version = version;
111
- }
112
-
113
- get username() {
114
- return Player.getUsername(this);
115
- }
116
-
117
- static getPlayer(array, id) {
118
- for(let i = 0; i < array.length; i++) {
119
- if(array[i] != null && array[i].id == id) {
120
- return array[i];
121
- }
122
- }
123
-
124
- return null;
125
- }
126
-
127
- static getPlayerAllGames(id) {
128
- const keys = Object.keys(games);
129
-
130
- for(let i = 0; i < keys.length; i++) {
131
- const game = games[keys[i]];
132
-
133
- if(game) {
134
- const p = this.getPlayer(game.players, id);
135
- const p2 = this.getPlayer(game.spectators, id);
136
- if(p) return p;
137
- if(p2) return p2;
138
- }
139
- }
140
-
141
- return null;
142
- }
143
-
144
- static getPlayerToken(array, token) {
145
- if(!token) return null;
146
- for(let i = 0; i < array.length; i++) {
147
- if(array[i] != null && array[i].token == token) {
148
- return array[i];
149
- }
150
- }
151
-
152
- return null;
153
- }
154
-
155
- static getPlayerAllGamesToken(token) {
156
- if(!token) return null;
157
- const keys = Object.keys(games);
158
-
159
- for(let i = 0; i < keys.length; i++) {
160
- const game = games[keys[i]];
161
-
162
- if(game) {
163
- const p = this.getPlayerToken(game.players, token);
164
- const p2 = this.getPlayerToken(game.spectators, token);
165
- if(p) return p;
166
- if(p2) return p2;
167
- }
168
- }
169
-
170
- return null;
171
- }
172
-
173
- static containsId(array, id) {
174
- return Player.getPlayer(array, id) != null;
175
- }
176
-
177
- static containsToken(array, token) {
178
- return Player.getPlayerToken(array, token) != null;
179
- }
180
-
181
- static containsIdAllGames(id) {
182
- return Player.getPlayerAllGames(id) != null;
183
- }
184
-
185
- static containsTokenAllGames(token) {
186
- return Player.getPlayerAllGamesToken(token) != null;
187
- }
188
-
189
- static getUsername(player) {
190
- try {
191
- const decoded_token = jwt.verify(player.token, jsonWebTokenSecretKey);
192
- return decoded_token && decoded_token.username ? decoded_token.username : null;
193
- } catch(e) {
194
- return null;
195
- }
196
- }
197
-
198
- static getUsernameSocket(socket) {
199
- try {
200
- const decoded_token = jwt.verify(socket.handshake.auth.token || socket.handshake.query.token || socket.request.cookies.token, jsonWebTokenSecretKey);
201
- return decoded_token && decoded_token.username ? decoded_token.username : null;
202
- } catch(e) {
203
- return null;
204
- }
205
- }
206
- }
102
+ const games = {}; // Contains all the games processed by the server
103
+ const tokens = []; // User tokens
104
+ const invalidatedUserTokens = []; // Invalidated user tokens
105
+ const invalidatedAdminTokens = []; // Invalidated admin tokens
207
106
 
208
107
  function getRoomsData() {
209
108
  const rooms = [];
@@ -218,20 +117,20 @@ function getRoomsData() {
218
117
  rooms[i]["players"] = Object.keys(game["players"]).length + game.numberAIToAdd;
219
118
  rooms[i]["width"] = "???";
220
119
  rooms[i]["height"] = "???";
221
- rooms[i]["speed"] = game["game"].speed;
120
+ rooms[i]["speed"] = game["gameEngine"].speed;
222
121
  rooms[i]["code"] = keysRooms[i];
223
122
  rooms[i]["maxPlayers"] = getMaxPlayers(keysRooms[i]);
224
123
  rooms[i]["state"] = (game["started"] ? GameConstants.GameState.STARTED : game["timeoutPlay"] != null ? GameConstants.GameState.STARTING : game["searchingPlayers"] ? GameConstants.GameState.SEARCHING_PLAYERS : "");
225
124
 
226
- if(game["game"].grid != null) {
227
- rooms[i]["width"] = game["game"].grid.width;
228
- rooms[i]["height"] = game["game"].grid.height;
229
- rooms[i]["borderWalls"] = game["game"].grid.borderWalls;
230
- rooms[i]["generateWalls"] = game["game"].grid.generateWalls;
125
+ if(game["gameEngine"].grid != null) {
126
+ rooms[i]["width"] = game["gameEngine"].grid.width;
127
+ rooms[i]["height"] = game["gameEngine"].grid.height;
128
+ rooms[i]["borderWalls"] = game["gameEngine"].grid.borderWalls;
129
+ rooms[i]["generateWalls"] = game["gameEngine"].grid.generateWalls;
231
130
  }
232
131
 
233
- if(game["game"].snake != null) {
234
- rooms[i]["players"] = game["game"].snake.length;
132
+ if(game["gameEngine"].snake != null) {
133
+ rooms[i]["players"] = game["gameEngine"].snake.length;
235
134
  }
236
135
 
237
136
  if(game["spectators"] != null) {
@@ -263,7 +162,7 @@ function generateRandomJsonWebTokenSecretKey(precValue) {
263
162
  }
264
163
 
265
164
  function getMaxPlayers(code) {
266
- const game = games[code].game;
165
+ const game = games[code].gameEngine;
267
166
 
268
167
  const heightGrid = parseInt(game.grid.height);
269
168
  const widthGrid = parseInt(game.grid.width);
@@ -286,7 +185,7 @@ function getMaxPlayers(code) {
286
185
  }
287
186
 
288
187
  function createRoom(data, socket) {
289
- if(Object.keys(games).filter(key => games[key] != null).length < config.maxRooms && !Player.containsTokenAllGames(socket.handshake.auth.token || socket.handshake.query.token || socket.request.cookies.token) && !Player.containsIdAllGames(socket.id)) {
188
+ if(Object.keys(games).filter(key => games[key] != null).length < config.maxRooms && !Player.containsTokenAllGames(socket?.handshake?.auth?.token || socket?.handshake?.query?.token || socket?.request?.cookies?.token, games) && !Player.containsIdAllGames(socket.id, games)) {
290
189
  let heightGrid = 20;
291
190
  let widthGrid = 20;
292
191
  let borderWalls = false;
@@ -356,10 +255,14 @@ function createRoom(data, socket) {
356
255
  const grid = new Grid(widthGrid, heightGrid, generateWalls, borderWalls, false, null, false);
357
256
  grid.reset();
358
257
  grid.init();
359
- const game = new GameEngine(grid, [], speed);
258
+ const game = new GameEngine(grid, [], speed, null, null, null, null, null, {
259
+ modelListAPIURL: config.aiUltraAPIURL,
260
+ modelID: config.aiUltraCustomModelURL ? "custom" : config.aiUltraModelID,
261
+ customURL: config.aiUltraCustomModelURL
262
+ });
360
263
 
361
264
  games[code] = {
362
- game: game,
265
+ gameEngine: game,
363
266
  private: privateGame,
364
267
  players: [],
365
268
  spectators: [],
@@ -401,7 +304,7 @@ function createRoom(data, socket) {
401
304
  });
402
305
  }
403
306
  } else if(socket != null) {
404
- if(Player.containsTokenAllGames(socket.handshake.auth.token || socket.handshake.query.token || socket.request.cookies.token) || Player.containsIdAllGames(socket.id)) {
307
+ if(Player.containsTokenAllGames(socket?.handshake?.auth?.token || socket?.handshake?.query?.token || socket?.request?.cookies?.token, games) || Player.containsIdAllGames(socket.id, games)) {
405
308
  socket.emit("process", {
406
309
  success: false,
407
310
  code: null,
@@ -418,20 +321,57 @@ function createRoom(data, socket) {
418
321
  }
419
322
 
420
323
  function copySnakes(snakes) {
421
- const copy = JSON.parse(JSON.stringify(snakes));
324
+ const snakesCopy = [];
422
325
 
423
- if(copy) {
424
- copy.forEach(snake => {
425
- delete snake["grid"];
426
- if(snake.snakeAI && snake.snakeAI._aiLevelText) snake.snakeAI.aiLevelText = snake.snakeAI._aiLevelText;
326
+ if(snakes) {
327
+ snakes.forEach(snake => {
328
+ if(snake) {
329
+ const snakeCopy = new Snake();
330
+
331
+ snakeCopy.color = snake.color;
332
+ snakeCopy.direction = snake.direction;
333
+ snakeCopy.errorInit = snake.errorInit;
334
+ snakeCopy.gameOver = snake.gameOver;
335
+ snakeCopy.autoRetry = snake.autoRetry;
336
+ snakeCopy.aiLevel = snake.aiLevel;
337
+
338
+ if(snake.lastTail) {
339
+ snakeCopy.lastTail = JSON.parse(JSON.stringify(snake.lastTail));
340
+ }
341
+
342
+ if(snake.lastHead) {
343
+ snakeCopy.lastHead = JSON.parse(JSON.stringify(snake.lastHead));
344
+ }
345
+
346
+ snakeCopy.lastTailMoved = snake.lastTailMoved;
347
+ snakeCopy.lastHeadMoved = snake.lastHeadMoved;
348
+ snakeCopy.name = snake.name;
349
+ snakeCopy.player = snake.player;
350
+
351
+ if(snake.queue) {
352
+ snakeCopy.queue = JSON.parse(JSON.stringify(snake.queue));
353
+ }
354
+
355
+ snakeCopy.score = snake.score;
356
+ snakeCopy.scoreMax = snake.scoreMax;
357
+ snakeCopy.ticksDead = snake.ticksDead;
358
+ snakeCopy.ticksWithoutAction = snake.ticksWithoutAction;
359
+ snakeCopy.grid = null;
360
+
361
+ if(snake.snakeAI && snake.snakeAI.aiLevelText) {
362
+ snakeCopy.snakeAI.aiLevelText = snake.snakeAI.aiLevelText;
363
+ }
364
+
365
+ snakesCopy.push(snakeCopy);
366
+ }
427
367
  });
428
368
  }
429
369
 
430
- return copy;
370
+ return snakesCopy;
431
371
  }
432
372
 
433
373
  function setupRoom(code) {
434
- const game = games[code].game;
374
+ const game = games[code].gameEngine;
435
375
 
436
376
  game.onReset(() => {
437
377
  io.to("room-" + code).emit("reset", {
@@ -621,8 +561,8 @@ function cleanRooms() {
621
561
  if(nb <= 0) {
622
562
  toRemove.push(keys[i]);
623
563
 
624
- if(game.game && game.game.kill) {
625
- game.game.kill();
564
+ if(game.gameEngine && game.gameEngine.kill) {
565
+ game.gameEngine.kill();
626
566
  }
627
567
  }
628
568
  }
@@ -671,13 +611,14 @@ function gameMatchmaking(game, code) {
671
611
  "playerNumber": numberPlayers,
672
612
  "maxPlayers": getMaxPlayers(code),
673
613
  "spectatorMode": false,
674
- "errorOccurred": game.game.errorOccurred,
614
+ "errorOccurred": game.gameEngine.errorOccurred,
675
615
  "onlineMaster": false,
676
616
  "onlineMode": true,
677
617
  "enableRetryPauseMenu": false,
678
618
  "countBeforePlay": game.countBeforePlay,
679
- "initialSpeed": game.game.initialSpeed,
680
- "speed": game.game.speed,
619
+ "initialSpeed": game.gameEngine.initialSpeed,
620
+ "speed": game.gameEngine.speed,
621
+ "errorOccured": game.gameEngine.errorOccured
681
622
  });
682
623
 
683
624
  io.to(game.players[0].id).emit("init", {
@@ -689,7 +630,7 @@ function gameMatchmaking(game, code) {
689
630
  setupSpectators(code);
690
631
  }
691
632
 
692
- function startGame(code) {
633
+ async function startGame(code) {
693
634
  const game = games[code];
694
635
 
695
636
  if(game != null) {
@@ -700,15 +641,15 @@ function startGame(code) {
700
641
 
701
642
  game.searchingPlayers = false;
702
643
  game.started = true;
703
- game.game.snakes = [];
704
- game.game.grid.reset();
705
- game.game.grid.init();
644
+ game.gameEngine.snakes = [];
645
+ game.gameEngine.grid.reset();
646
+ game.gameEngine.grid.init();
706
647
 
707
648
  for(let i = 0; i < game.players.length; i++) {
708
649
  const username = game.players[i].username;
709
650
 
710
- game.players[i].snake = new Snake(null, null, game.game.grid, null, null, null, username);
711
- game.game.snakes.push(game.players[i].snake);
651
+ game.players[i].snake = new Snake(null, null, game.gameEngine.grid, null, null, null, username);
652
+ game.gameEngine.snakes.push(game.players[i].snake);
712
653
 
713
654
  io.to(game.players[i].id).emit("init", {
714
655
  "currentPlayer": (i + 1),
@@ -718,29 +659,38 @@ function startGame(code) {
718
659
 
719
660
  if(game.enableAI) {
720
661
  for(let i = 0; i < game.numberAIToAdd; i++) {
721
- const snakeAI = new Snake(null, null, game.game.grid, GameConstants.PlayerType.AI, game.levelAI);
722
- game.game.snakes.push(snakeAI);
662
+ const snakeAI = new Snake(null, null, game.gameEngine.grid, GameConstants.PlayerType.AI, game.levelAI);
663
+ game.gameEngine.snakes.push(snakeAI);
723
664
  }
724
665
  }
725
666
 
726
667
  if(config.enableMaxTimeGame) {
727
668
  clearTimeout(game.timeoutMaxTimePlay);
728
- game.game.timeStart = Date.now() + 5000;
669
+ game.gameEngine.timeStart = Date.now() + 5000;
729
670
  game.timeoutMaxTimePlay = setTimeout(() => {
730
- game.game.stop(true);
671
+ game.gameEngine.stop(true);
731
672
  }, config.maxTimeGame + 5000);
732
673
  }
674
+
675
+ io.to("room-" + code).emit("init", {
676
+ "engineLoading": true
677
+ });
733
678
 
734
679
  if(!game.alreadyInit) {
735
- game.game.init();
736
- game.game.start();
680
+ await game.gameEngine.init();
681
+ game.gameEngine.start();
737
682
  game.alreadyInit = true;
738
683
  } else {
739
- game.game.countBeforePlay = 3;
740
- game.game.init();
741
- game.game.reset();
684
+ game.gameEngine.countBeforePlay = 3;
685
+ await game.gameEngine.init();
686
+ game.gameEngine.reset();
742
687
  }
743
688
 
689
+ io.to("room-" + code).emit("init", {
690
+ "errorOccurred": game.gameEngine.errorOccurred,
691
+ "engineLoading": false
692
+ });
693
+
744
694
  setupSpectators(code);
745
695
  }
746
696
  }
@@ -753,7 +703,8 @@ function setupSpectators(code) {
753
703
  io.to(game.spectators[i].id).emit("init", {
754
704
  "spectatorMode": true,
755
705
  "onlineMode": true,
756
- "enableRetryPauseMenu": false
706
+ "enableRetryPauseMenu": false,
707
+ "engineLoading": false
757
708
  });
758
709
  }
759
710
  }
@@ -765,8 +716,8 @@ function sendStatus(code) {
765
716
 
766
717
  if(game != null) {
767
718
  for(let i = 0; i < game.players.length; i++) {
768
- game.game.key(game.players[i].snake.lastKey, i + 1);
769
- if(game.players[i].snake.gameOver) game.game.setGameOver(i + 1);
719
+ game.gameEngine.key(game.players[i].snake.lastKey, i + 1);
720
+ if(game.players[i].snake.gameOver) game.gameEngine.setGameOver(i + 1);
770
721
  }
771
722
  }
772
723
  }
@@ -908,14 +859,16 @@ app.use(i18n.init);
908
859
  // Rate limiter
909
860
  app.use("/authentication", rateLimit({
910
861
  windowMs: config.authentWindowMs,
911
- max: config.authentMaxRequest
862
+ max: config.authentMaxRequest,
863
+ validate: { trustProxy: false }
912
864
  }));
913
865
 
914
866
  // IP ban
915
867
  app.use(function(req, res, next) {
916
868
  ipBanned(req.ip).then(() => {
917
869
  res.render(__dirname + "/views/banned.html", {
918
- contact: config.contactBan
870
+ contact: config.contactBan,
871
+ theme: req.query.theme
919
872
  });
920
873
  res.end();
921
874
  }, () => {
@@ -926,7 +879,8 @@ app.use(function(req, res, next) {
926
879
  app.get("/", function(req, res) {
927
880
  res.render(__dirname + "/views/index.html", {
928
881
  version: config.version,
929
- engineVersion: GameConstants.Setting.APP_VERSION
882
+ engineVersion: GameConstants.Setting.APP_VERSION,
883
+ theme: req.query.theme
930
884
  });
931
885
  });
932
886
 
@@ -948,7 +902,8 @@ app.get("/authentication", function(req, res) {
948
902
  min: config.minCharactersUsername,
949
903
  max: config.maxCharactersUsername,
950
904
  enableMaxTimeGame: config.enableMaxTimeGame,
951
- maxTimeGame: config.maxTimeGame
905
+ maxTimeGame: config.maxTimeGame,
906
+ theme: req.query.theme
952
907
  });
953
908
  });
954
909
  } else {
@@ -985,7 +940,8 @@ app.post("/authentication", function(req, res) {
985
940
  min: config.minCharactersUsername,
986
941
  max: config.maxCharactersUsername,
987
942
  enableMaxTimeGame: config.enableMaxTimeGame,
988
- maxTimeGame: config.maxTimeGame
943
+ maxTimeGame: config.maxTimeGame,
944
+ theme: req.query.theme
989
945
  });
990
946
 
991
947
  logger.info("authentication - username: " + username + " - ip: " + req.ip);
@@ -1007,7 +963,8 @@ app.post("/authentication", function(req, res) {
1007
963
  min: config.minCharactersUsername,
1008
964
  max: config.maxCharactersUsername,
1009
965
  enableMaxTimeGame: config.enableMaxTimeGame,
1010
- maxTimeGame: config.maxTimeGame
966
+ maxTimeGame: config.maxTimeGame,
967
+ theme: req.query.theme
1011
968
  });
1012
969
  });
1013
970
  }
@@ -1030,9 +987,11 @@ app.get("/rooms", function(req, res) {
1030
987
 
1031
988
  // Admin panel
1032
989
  function kickUser(socketId, token) {
1033
- if(io.of("/").sockets.get(socketId)) {
1034
- logger.info("user kicked (socket: " + socketId + ") - ip: " + getIPSocketIO(io.of("/").sockets.get(socketId).handshake));
1035
- io.of("/").sockets.get(socketId).disconnect(true);
990
+ const sockets = io.of("/").sockets;
991
+
992
+ if(sockets.get(socketId)) {
993
+ logger.info("user kicked (socket: " + socketId + ") - ip: " + getIPSocketIO(sockets.get(socketId).handshake));
994
+ sockets.get(socketId).disconnect(true);
1036
995
  invalidateUserToken(token);
1037
996
  }
1038
997
  }
@@ -1058,8 +1017,10 @@ function invalidateUserToken(token) {
1058
1017
  }
1059
1018
 
1060
1019
  function banUserIP(socketId) {
1061
- if(io.of("/").sockets.get(socketId)) {
1062
- let ip = getIPSocketIO(io.of("/").sockets.get(socketId).handshake);
1020
+ const sockets = io.of("/").sockets;
1021
+
1022
+ if(sockets.get(socketId)) {
1023
+ let ip = getIPSocketIO(sockets.get(socketId).handshake);
1063
1024
 
1064
1025
  if(ip && ip.substr(0, 7) == "::ffff:") {
1065
1026
  ip = ip.substr(7, ip.length);
@@ -1168,8 +1129,16 @@ function verifyFormAuthenticationAdmin(body) {
1168
1129
  }
1169
1130
 
1170
1131
  const csrfSecret = generateRandomJsonWebTokenSecretKey(jsonWebTokenSecretKeyAdmin);
1171
- const { doubleCsrfProtection, generateToken } = doubleCsrf({
1132
+ const { doubleCsrfProtection, generateCsrfToken } = doubleCsrf({
1172
1133
  getSecret: () => csrfSecret,
1134
+ getSessionIdentifier: (req) => req.cookies.tokenAdmin || randomUUID(),
1135
+ getCsrfTokenFromRequest: (req) => {
1136
+ return (
1137
+ req.headers["x-csrf-token"] ||
1138
+ req.body?._csrf ||
1139
+ req.query?._csrf
1140
+ );
1141
+ },
1173
1142
  cookieName: productionMode ? "__Host-snakeia-server.x-csrf-token" : "snakeia-server.x-csrf-token",
1174
1143
  cookieOptions: {
1175
1144
  sameSite: productionMode ? "strict" : "lax",
@@ -1206,10 +1175,11 @@ app.get("/admin", doubleCsrfProtection, function(req, res) {
1206
1175
  games: games,
1207
1176
  io: io,
1208
1177
  config: config,
1209
- csrfToken: generateToken(req, res, true),
1178
+ csrfToken: generateCsrfToken(req, res, { overwrite: true, validateOnReuse: true }),
1210
1179
  serverLog: logFile,
1211
1180
  errorLog: errorLogFile,
1212
- getIPSocketIO: getIPSocketIO
1181
+ getIPSocketIO: getIPSocketIO,
1182
+ theme: req.query.theme
1213
1183
  });
1214
1184
  });
1215
1185
  });
@@ -1311,7 +1281,8 @@ app.use(function (err, req, res, next) {
1311
1281
 
1312
1282
  const adminRateLimiter = rateLimit({
1313
1283
  windowMs: config.authentWindowMs,
1314
- max: config.authentMaxRequest
1284
+ max: config.authentMaxRequest,
1285
+ validate: { trustProxy: false }
1315
1286
  });
1316
1287
 
1317
1288
  app.post("/admin", adminRateLimiter, function(req, res) {
@@ -1345,7 +1316,8 @@ app.post("/admin", adminRateLimiter, function(req, res) {
1345
1316
  csrfToken: null,
1346
1317
  serverLog: null,
1347
1318
  errorLog: null,
1348
- getIPSocketIO: getIPSocketIO
1319
+ getIPSocketIO: getIPSocketIO,
1320
+ theme: req.query.theme
1349
1321
  });
1350
1322
  });
1351
1323
  }
@@ -1395,22 +1367,24 @@ function checkAuthentication(token) {
1395
1367
  }
1396
1368
 
1397
1369
  function checkAuthenticationSocket(socket) {
1398
- return checkAuthentication(socket.handshake.auth.token || socket.handshake.query.token || socket.request.cookies.token);
1370
+ return checkAuthentication(socket?.handshake?.auth?.token || socket?.handshake?.query?.token || socket?.request?.cookies?.token);
1399
1371
  }
1400
1372
 
1401
1373
  function checkAuthenticationExpress(req) {
1402
1374
  return checkAuthentication(req.cookies.token);
1403
1375
  }
1404
1376
 
1405
- io.use(function(socket, next) {
1377
+ const checkBanned = function(socket, next) {
1406
1378
  ipBanned(getIPSocketIO(socket.handshake)).then(() => {
1407
1379
  next(new Error(GameConstants.Error.BANNED));
1408
1380
  }, () => {
1409
1381
  next();
1410
1382
  });
1411
- });
1383
+ };
1384
+
1385
+ io.use(checkBanned);
1412
1386
 
1413
- io.of("/rooms").on("connection", function(socket) {
1387
+ io.of("/rooms").use(ioCookieParser()).use(checkBanned).on("connection", function(socket) {
1414
1388
  checkAuthenticationSocket(socket).then(() => {
1415
1389
  socket.emit("rooms", {
1416
1390
  rooms: getRoomsData(),
@@ -1430,7 +1404,7 @@ io.of("/rooms").on("connection", function(socket) {
1430
1404
  });
1431
1405
  });
1432
1406
 
1433
- io.of("/createRoom").on("connection", function(socket) {
1407
+ io.of("/createRoom").use(ioCookieParser()).use(checkBanned).on("connection", function(socket) {
1434
1408
  socket.on("create", function(data) {
1435
1409
  checkAuthenticationSocket(socket).then(() => {
1436
1410
  createRoom(data, socket);
@@ -1450,7 +1424,7 @@ io.on("connection", function(socket) {
1450
1424
  const version = data.version;
1451
1425
  const game = games[code];
1452
1426
 
1453
- if(game != null && !Player.containsId(game.players, socket.id) && !Player.containsId(game.spectators, socket.id) && !Player.containsToken(game.players, token) && !Player.containsToken(game.spectators, token) && !Player.containsTokenAllGames(token) && !Player.containsIdAllGames(socket.id)) {
1427
+ if(game != null && !Player.containsId(game.players, socket.id) && !Player.containsId(game.spectators, socket.id) && !Player.containsToken(game.players, token) && !Player.containsToken(game.spectators, token) && !Player.containsTokenAllGames(token, games) && !Player.containsIdAllGames(socket.id, games)) {
1454
1428
  socket.join("room-" + code);
1455
1429
 
1456
1430
  if(game.players.length + game.numberAIToAdd >= getMaxPlayers(code) || game.started) {
@@ -1470,37 +1444,40 @@ io.on("connection", function(socket) {
1470
1444
 
1471
1445
  if(game.started) {
1472
1446
  socket.emit("init", {
1473
- "paused": game.game.paused,
1474
- "isReseted": game.game.isReseted,
1475
- "exited": game.game.exited,
1476
- "snakes": copySnakes(game.game.snakes),
1477
- "grid": game.game.grid,
1478
- "numFruit": game.game.numFruit,
1479
- "ticks": game.game.ticks,
1480
- "scoreMax": game.game.scoreMax,
1481
- "gameOver": game.game.gameOver,
1482
- "gameFinished": game.game.gameFinished,
1483
- "gameMazeWin": game.game.gameMazeWin,
1484
- "starting": game.game.starting,
1485
- "initialSpeed": game.game.initialSpeed,
1486
- "speed": game.game.speed,
1487
- "offsetFrame": game.game.speed * GameConstants.Setting.TIME_MULTIPLIER,
1447
+ "paused": game.gameEngine.paused,
1448
+ "isReseted": game.gameEngine.isReseted,
1449
+ "exited": game.gameEngine.exited,
1450
+ "snakes": copySnakes(game.gameEngine.snakes),
1451
+ "grid": game.gameEngine.grid,
1452
+ "numFruit": game.gameEngine.numFruit,
1453
+ "ticks": game.gameEngine.ticks,
1454
+ "scoreMax": game.gameEngine.scoreMax,
1455
+ "gameOver": game.gameEngine.gameOver,
1456
+ "gameFinished": game.gameEngine.gameFinished,
1457
+ "gameMazeWin": game.gameEngine.gameMazeWin,
1458
+ "starting": game.gameEngine.starting,
1459
+ "initialSpeed": game.gameEngine.initialSpeed,
1460
+ "speed": game.gameEngine.speed,
1461
+ "offsetFrame": game.gameEngine.speed * GameConstants.Setting.TIME_MULTIPLIER,
1488
1462
  "confirmReset": false,
1489
1463
  "confirmExit": false,
1490
1464
  "getInfos": false,
1491
1465
  "getInfosGame": false,
1492
- "errorOccurred": game.game.errorOccurred,
1466
+ "errorOccurred": game.gameEngine.errorOccurred,
1493
1467
  "timerToDisplay": config.enableMaxTimeGame ? (config.maxTimeGame - (Date.now() - game.timeStart)) / 1000 : -1,
1494
- "countBeforePlay": game.game.countBeforePlay,
1495
- "aiStuck": game.game.aiStuck,
1496
- "precAiStuck": false
1468
+ "countBeforePlay": game.gameEngine.countBeforePlay,
1469
+ "aiStuck": game.gameEngine.aiStuck,
1470
+ "precAiStuck": false,
1471
+ "enablePause": game.gameEngine.enablePause,
1472
+ "enableRetry": game.gameEngine.enableRetry,
1473
+ "progressiveSpeed": game.gameEngine.progressiveSpeed
1497
1474
  });
1498
1475
  } else {
1499
1476
  socket.emit("init", {
1500
- "enablePause": game.game.enablePause,
1501
- "enableRetry": game.game.enableRetry,
1502
- "progressiveSpeed": game.game.progressiveSpeed,
1503
- "offsetFrame": game.game.speed * GameConstants.Setting.TIME_MULTIPLIER
1477
+ "enablePause": game.gameEngine.enablePause,
1478
+ "enableRetry": game.gameEngine.enableRetry,
1479
+ "progressiveSpeed": game.gameEngine.progressiveSpeed,
1480
+ "offsetFrame": game.gameEngine.speed * GameConstants.Setting.TIME_MULTIPLIER
1504
1481
  });
1505
1482
  }
1506
1483
 
@@ -1573,7 +1550,7 @@ io.on("connection", function(socket) {
1573
1550
  success: false,
1574
1551
  errorCode: GameConstants.Error.ROOM_ALREADY_JOINED
1575
1552
  });
1576
- } else if(Player.containsTokenAllGames(token) || Player.containsIdAllGames(socket.id)) {
1553
+ } else if(Player.containsTokenAllGames(token, games) || Player.containsIdAllGames(socket.id, games)) {
1577
1554
  socket.emit("join-room", {
1578
1555
  success: false,
1579
1556
  errorCode: GameConstants.Error.ALREADY_CREATED_ROOM
@@ -1586,6 +1563,6 @@ io.on("connection", function(socket) {
1586
1563
  });
1587
1564
  });
1588
1565
 
1589
- http.listen(config.port, function(){
1566
+ http.listen(config.port, () => {
1590
1567
  console.log("listening on *:" + config.port);
1591
1568
  });
package/views/admin.html CHANGED
@@ -24,12 +24,19 @@
24
24
  <link href="/css/bootstrap.min.css" rel="stylesheet">
25
25
  <link href="/css/flat-ui.min.css" rel="stylesheet">
26
26
  <link href="/css/main.css" rel="stylesheet">
27
+ <% if(theme === "dark") { %>
28
+ <link href="/css/dark-theme.css" rel="stylesheet">
29
+ <% } %>
27
30
  <script src="/js/jquery.min.js"></script>
28
31
  <script src="/js/bootstrap.bundle.min.js"></script>
29
32
  <% if(enableRecaptcha && publicKey) { %><script src="https://www.google.com/recaptcha/api.js?hl=<%= locale %>" async defer></script><% } %>
30
33
  <title>SnakeIA Server</title>
31
34
  </head>
35
+ <% if(theme === "dark") { %>
36
+ <body class="text-center dark">
37
+ <% } else { %>
32
38
  <body class="text-center">
39
+ <% } %>
33
40
  <div class="container">
34
41
  <div class="row">
35
42
  <div class="col">