snakeia-server 1.1.5 → 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/.drone.yml CHANGED
@@ -15,4 +15,5 @@ steps:
15
15
  password:
16
16
  from_secret: REGISTRY_PASSWORD
17
17
  tags:
18
- - latest
18
+ - latest
19
+ - 1.2.0
@@ -23,20 +23,57 @@ const Position = snakeia.Position;
23
23
  const Grid = snakeia.Grid;
24
24
  const Snake = snakeia.Snake;
25
25
  const GameEngine = snakeia.GameEngine;
26
- const seedrandom = require("seedrandom");
27
26
 
28
27
  let game;
29
28
 
30
29
  function copySnakes(snakes) {
31
- var copy = JSON.parse(JSON.stringify(snakes));
30
+ const snakesCopy = [];
32
31
 
33
- if(copy) {
34
- for(var i = 0; i < copy.length; i++) {
35
- delete copy[i]["grid"];
36
- }
32
+ if(snakes) {
33
+ snakes.forEach(snake => {
34
+ if(snake) {
35
+ const snakeCopy = new Snake();
36
+
37
+ snakeCopy.color = snake.color;
38
+ snakeCopy.direction = snake.direction;
39
+ snakeCopy.errorInit = snake.errorInit;
40
+ snakeCopy.gameOver = snake.gameOver;
41
+ snakeCopy.autoRetry = snake.autoRetry;
42
+ snakeCopy.aiLevel = snake.aiLevel;
43
+
44
+ if(snake.lastTail) {
45
+ snakeCopy.lastTail = JSON.parse(JSON.stringify(snake.lastTail));
46
+ }
47
+
48
+ if(snake.lastHead) {
49
+ snakeCopy.lastHead = JSON.parse(JSON.stringify(snake.lastHead));
50
+ }
51
+
52
+ snakeCopy.lastTailMoved = snake.lastTailMoved;
53
+ snakeCopy.lastHeadMoved = snake.lastHeadMoved;
54
+ snakeCopy.name = snake.name;
55
+ snakeCopy.player = snake.player;
56
+
57
+ if(snake.queue) {
58
+ snakeCopy.queue = JSON.parse(JSON.stringify(snake.queue));
59
+ }
60
+
61
+ snakeCopy.score = snake.score;
62
+ snakeCopy.scoreMax = snake.scoreMax;
63
+ snakeCopy.ticksDead = snake.ticksDead;
64
+ snakeCopy.ticksWithoutAction = snake.ticksWithoutAction;
65
+ snakeCopy.grid = null;
66
+
67
+ if(snake.snakeAI && snake.snakeAI.aiLevelText) {
68
+ snakeCopy.snakeAI.aiLevelText = snake.snakeAI.aiLevelText;
69
+ }
70
+
71
+ snakesCopy.push(snakeCopy);
72
+ }
73
+ });
37
74
  }
38
75
 
39
- return copy;
76
+ return snakesCopy;
40
77
  }
41
78
 
42
79
  function copyGrid(grid) {
@@ -51,35 +88,22 @@ function copyGrid(grid) {
51
88
  }
52
89
 
53
90
  function parseSnakes(snakes, grid) {
54
- if(game) {
55
- var grid = grid != null ? grid : game.grid;
56
- }
57
-
58
- grid = Object.assign(new Grid(), grid);
91
+ let gridCopy = game ? (grid ?? game.grid) : grid;
92
+ gridCopy = Object.assign(new Grid(), gridCopy);
59
93
 
60
- if(!snakes && game) {
61
- snakes = game.snakes;
62
- }
63
-
64
- for(var i = 0; i < snakes.length; i++) {
65
- snakes[i].grid = grid;
66
- snakes[i] = Object.assign(new Snake(), snakes[i]);
67
-
68
- for(var j = 0; j < snakes[i].queue.length; j++) {
69
- snakes[i].queue[j] = Object.assign(new Position(), snakes[i].queue[j]);
70
- }
71
-
72
- snakes[i].initAI();
73
- }
94
+ snakes = snakes ?? game?.snakes;
95
+ const snakesCopy = (Array.isArray(snakes) ? snakes : [snakes]).map(snake => {
96
+ const newSnake = Object.assign(new Snake(), snake);
97
+ newSnake.grid = gridCopy;
98
+ newSnake.queue = newSnake.queue.map(pos => Object.assign(new Position(), pos));
99
+ return newSnake;
100
+ });
74
101
 
75
- return {
76
- grid: grid,
77
- snakes: snakes
78
- };
102
+ return { grid: gridCopy, snakes: snakesCopy };
79
103
  }
80
104
 
81
105
  if(!isMainThread) {
82
- parentPort.on("message", (data) => {
106
+ parentPort.on("message", async data => {
83
107
  const type = data.type;
84
108
  const keys = Object.keys(data);
85
109
 
@@ -89,8 +113,17 @@ if(!isMainThread) {
89
113
  const snakes = parsed["snakes"];
90
114
 
91
115
  if(!game) {
92
- game = new GameEngine(grid, snakes, data.speed, data.enablePause, data.enableRetry, data.progressiveSpeed);
93
- game.init();
116
+ try {
117
+ game = new GameEngine(grid, snakes, data.speed, data.enablePause, data.enableRetry, data.progressiveSpeed, data.aiStuckLimit, data.disableStuckAIDetection, data.aiUltraModelSettings);
118
+ await game.init();
119
+ } catch(e) {
120
+ console.error(e);
121
+
122
+ parentPort.postMessage({
123
+ type: "init",
124
+ errorOccurred: true
125
+ });
126
+ }
94
127
 
95
128
  parentPort.postMessage({
96
129
  type: "init",
@@ -100,7 +133,8 @@ if(!isMainThread) {
100
133
  "enableRetry": game.enableRetry,
101
134
  "progressiveSpeed": game.progressiveSpeed,
102
135
  "offsetFrame": game.speed * GameConstants.Setting.TIME_MULTIPLIER,
103
- "errorOccurred": game.errorOccurred
136
+ "errorOccurred": game.errorOccurred,
137
+ "engineLoading": game.engineLoading
104
138
  });
105
139
 
106
140
  game.onReset(() => {
@@ -127,7 +161,8 @@ if(!isMainThread) {
127
161
  "getInfosGame": false,
128
162
  "errorOccurred": game.errorOccurred,
129
163
  "aiStuck": game.aiStuck,
130
- "precAiStuck": false
164
+ "precAiStuck": false,
165
+ "engineLoading": game.engineLoading
131
166
  });
132
167
  });
133
168
 
@@ -144,7 +179,8 @@ if(!isMainThread) {
144
179
  "confirmExit": false,
145
180
  "getInfos": false,
146
181
  "getInfosGame": false,
147
- "errorOccurred": game.errorOccurred
182
+ "errorOccurred": game.errorOccurred,
183
+ "engineLoading": game.engineLoading
148
184
  });
149
185
  });
150
186
 
@@ -156,7 +192,8 @@ if(!isMainThread) {
156
192
  "confirmExit": false,
157
193
  "getInfos": false,
158
194
  "getInfosGame": false,
159
- "errorOccurred": game.errorOccurred
195
+ "errorOccurred": game.errorOccurred,
196
+ "engineLoading": game.engineLoading
160
197
  });
161
198
  });
162
199
 
@@ -167,7 +204,8 @@ if(!isMainThread) {
167
204
  "confirmExit": false,
168
205
  "getInfos": false,
169
206
  "getInfosGame": false,
170
- "errorOccurred": game.errorOccurred
207
+ "errorOccurred": game.errorOccurred,
208
+ "engineLoading": game.engineLoading
171
209
  });
172
210
  });
173
211
 
@@ -182,7 +220,8 @@ if(!isMainThread) {
182
220
  "confirmExit": false,
183
221
  "getInfos": false,
184
222
  "getInfosGame": false,
185
- "errorOccurred": game.errorOccurred
223
+ "errorOccurred": game.errorOccurred,
224
+ "engineLoading": game.engineLoading
186
225
  });
187
226
  });
188
227
 
@@ -197,7 +236,8 @@ if(!isMainThread) {
197
236
  "confirmExit": false,
198
237
  "getInfos": false,
199
238
  "getInfosGame": false,
200
- "errorOccurred": game.errorOccurred
239
+ "errorOccurred": game.errorOccurred,
240
+ "engineLoading": game.engineLoading
201
241
  });
202
242
  });
203
243
 
@@ -214,7 +254,8 @@ if(!isMainThread) {
214
254
  "confirmExit": false,
215
255
  "getInfos": false,
216
256
  "getInfosGame": false,
217
- "errorOccurred": game.errorOccurred
257
+ "errorOccurred": game.errorOccurred,
258
+ "engineLoading": game.engineLoading
218
259
  });
219
260
  });
220
261
 
@@ -243,7 +284,8 @@ if(!isMainThread) {
243
284
  "numFruit": game.numFruit,
244
285
  "offsetFrame": 0,
245
286
  "errorOccurred": game.errorOccurred,
246
- "aiStuck": game.aiStuck
287
+ "aiStuck": game.aiStuck,
288
+ "engineLoading": game.engineLoading
247
289
  });
248
290
  });
249
291
 
@@ -266,14 +308,25 @@ if(!isMainThread) {
266
308
  "speed": game.speed,
267
309
  "countBeforePlay": game.countBeforePlay,
268
310
  "numFruit": game.numFruit,
269
- "errorOccurred": game.errorOccurred
311
+ "errorOccurred": game.errorOccurred,
312
+ "engineLoading": game.engineLoading
270
313
  });
271
314
  });
272
315
  } else {
273
316
  game.snakes = snakes;
274
317
  game.grid = grid;
275
318
  game.countBeforePlay = 3;
276
- game.init();
319
+
320
+ try {
321
+ await game.init();
322
+ } catch(e) {
323
+ console.error(e);
324
+
325
+ parentPort.postMessage({
326
+ type: "init",
327
+ errorOccurred: true
328
+ });
329
+ }
277
330
  }
278
331
  } else if(game) {
279
332
  switch(type) {
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2020 Eliastik (eliastiksofts.com)
2
+ * Copyright (C) 2020-2025 Eliastik (eliastiksofts.com)
3
3
  *
4
4
  * This file is part of "SnakeIA Server".
5
5
  *
@@ -16,7 +16,7 @@
16
16
  * You should have received a copy of the GNU General Public License
17
17
  * along with "SnakeIA Server". If not, see <http://www.gnu.org/licenses/>.
18
18
  */
19
- const { Worker } = require('worker_threads');
19
+ const { Worker } = require("worker_threads");
20
20
  const snakeia = require("snakeia");
21
21
  const GameEngine = snakeia.GameEngine;
22
22
  const Grid = snakeia.Grid;
@@ -25,132 +25,145 @@ const Position = snakeia.Position;
25
25
  let logger;
26
26
 
27
27
  class GameEngineMultithreadingController extends GameEngine {
28
- constructor(grid, snakes, speed, enablePause, enableRetry, progressiveSpeed) {
29
- super(grid, snakes, speed, enablePause, enableRetry, progressiveSpeed);
28
+
29
+ constructor(grid, snakes, speed, enablePause, enableRetry, progressiveSpeed, aiStuckLimit, disableStuckAIDetection, aiUltraModelSettings) {
30
+ super(grid, snakes, speed, enablePause, enableRetry, progressiveSpeed, aiStuckLimit, disableStuckAIDetection, aiUltraModelSettings);
30
31
  this.worker = new Worker("./GameEngineMultithreading.js");
32
+ this.workerReady = false;
33
+ this.messageQueue = []; // Queue of message if the worker is still loading
31
34
  this.eventsInit = false;
32
35
  }
33
36
 
34
- init() {
35
- if(!this.eventsInit) {
36
- this.worker.on("message", (data) => {
37
- const type = data.type;
38
- const dataKeys = Object.keys(data);
37
+ async init() {
38
+ return new Promise(resolve => {
39
+ if(!this.eventsInit) {
40
+ this.worker.on("message", (data) => {
41
+ const type = data.type;
42
+ const dataKeys = Object.keys(data);
39
43
 
40
- if(dataKeys.length > 1) {
41
- let grid = this.grid;
42
- let snakes = this.snakes;
44
+ if(dataKeys.length > 1) {
45
+ let grid = this.grid;
46
+ let snakes = this.snakes;
43
47
 
44
- if(data.grid) {
45
- grid = Object.assign(new Grid(), data.grid);
46
- data.grid = grid;
47
- }
48
-
49
- if(data.snakes) {
50
- for(let i = 0; i < data.snakes.length; i++) {
51
- data.snakes[i].grid = grid;
52
- data.snakes[i] = Object.assign(new Snake(), data.snakes[i]);
53
-
54
- for(let j = 0; j < data.snakes[i].queue.length; j++) {
55
- data.snakes[i].queue[j] = Object.assign(new Position(), data.snakes[i].queue[j]);
56
- }
48
+ if(data.grid) {
49
+ grid = Object.assign(new Grid(), data.grid);
50
+ data.grid = grid;
57
51
  }
52
+
53
+ if(data.snakes) {
54
+ for(let i = 0; i < data.snakes.length; i++) {
55
+ data.snakes[i].grid = grid;
56
+ data.snakes[i] = Object.assign(new Snake(), data.snakes[i]);
57
+
58
+ for(let j = 0; j < data.snakes[i].queue.length; j++) {
59
+ data.snakes[i].queue[j] = Object.assign(new Position(), data.snakes[i].queue[j]);
60
+ }
61
+ }
58
62
 
59
- snakes = data.snakes;
60
- }
63
+ snakes = data.snakes;
64
+ }
61
65
 
62
- this.snakes = snakes;
63
- this.grid = grid;
66
+ this.snakes = snakes;
67
+ this.grid = grid;
64
68
 
65
- for(let i = 0; i < dataKeys.length; i++) {
66
- if(dataKeys[i] != "snakes" && dataKeys[i] != "grid") {
67
- this[dataKeys[i]] = data[dataKeys[i]];
69
+ for(let i = 0; i < dataKeys.length; i++) {
70
+ if(dataKeys[i] != "snakes" && dataKeys[i] != "grid") {
71
+ this[dataKeys[i]] = data[dataKeys[i]];
72
+ }
68
73
  }
69
74
  }
70
- }
71
-
72
- switch(type) {
73
- case "reset":
74
- this.reactor.dispatchEvent("onReset");
75
- break;
76
- case "start":
77
- this.reactor.dispatchEvent("onStart");
78
- break;
79
- case "pause":
80
- this.reactor.dispatchEvent("onPause");
81
- break;
82
- case "continue":
83
- this.reactor.dispatchEvent("onContinue");
84
- break;
85
- case "stop":
86
- this.reactor.dispatchEvent("onStop");
87
- break;
88
- case "exit":
89
- this.reactor.dispatchEvent("onExit");
90
- break;
91
- case "kill":
92
- this.reactor.dispatchEvent("onKill");
93
- break;
94
- case "scoreIncreased":
95
- this.reactor.dispatchEvent("onScoreIncreased");
96
- break;
97
- case "update":
98
- this.reactor.dispatchEvent("onUpdate");
99
- break;
100
- case "updateCounter":
101
- this.reactor.dispatchEvent("onUpdateCounter");
102
- break;
103
- }
104
- });
105
-
106
- this.worker.on("error", (error) => {
107
- if(logger) logger.error("Error in GameEngineMultithreading", error);
108
- this.errorOccurred = true;
109
- this.reactor.dispatchEvent("onStop");
110
- });
111
-
112
- this.worker.on("exit", () => {
113
- this.gameFinished = true;
114
- this.reactor.dispatchEvent("onStop");
115
- });
116
-
117
- this.eventsInit = true;
118
- }
119
75
 
120
- if(this.grid) {
121
- this.grid.rngGrid = null;
122
- this.grid.rngGame = null;
123
- }
124
-
125
- this.worker.postMessage({
126
- type: "init",
127
- grid: this.grid,
128
- snakes: this.snakes,
129
- speed: this.speed,
130
- enablePause: this.enablePause,
131
- enableRetry: this.enableRetry,
132
- progressiveSpeed: this.progressiveSpeed
76
+ switch(type) {
77
+ case "init":
78
+ this.workerReady = true;
79
+ this.passQueuedMessages();
80
+ resolve();
81
+ break;
82
+ case "reset":
83
+ this.reactor.dispatchEvent("onReset");
84
+ break;
85
+ case "start":
86
+ this.reactor.dispatchEvent("onStart");
87
+ break;
88
+ case "pause":
89
+ this.reactor.dispatchEvent("onPause");
90
+ break;
91
+ case "continue":
92
+ this.reactor.dispatchEvent("onContinue");
93
+ break;
94
+ case "stop":
95
+ this.reactor.dispatchEvent("onStop");
96
+ break;
97
+ case "exit":
98
+ this.reactor.dispatchEvent("onExit");
99
+ break;
100
+ case "kill":
101
+ this.reactor.dispatchEvent("onKill");
102
+ break;
103
+ case "scoreIncreased":
104
+ this.reactor.dispatchEvent("onScoreIncreased");
105
+ break;
106
+ case "update":
107
+ this.reactor.dispatchEvent("onUpdate");
108
+ break;
109
+ case "updateCounter":
110
+ this.reactor.dispatchEvent("onUpdateCounter");
111
+ break;
112
+ }
113
+ });
114
+
115
+ this.worker.on("error", (error) => {
116
+ if(logger) logger.error("Error in GameEngineMultithreading", error);
117
+ this.errorOccurred = true;
118
+ this.reactor.dispatchEvent("onStop");
119
+ });
120
+
121
+ this.worker.on("exit", () => {
122
+ this.gameFinished = true;
123
+ this.reactor.dispatchEvent("onStop");
124
+ });
125
+
126
+ this.eventsInit = true;
127
+ }
128
+
129
+ if(this.grid) {
130
+ this.grid.rngGrid = null;
131
+ this.grid.rngGame = null;
132
+ }
133
+
134
+ this.worker.postMessage({
135
+ type: "init",
136
+ grid: this.grid,
137
+ snakes: this.snakes,
138
+ speed: this.speed,
139
+ enablePause: this.enablePause,
140
+ enableRetry: this.enableRetry,
141
+ progressiveSpeed: this.progressiveSpeed,
142
+ aiStuckLimit: this.aiStuckLimit,
143
+ disableStuckAIDetection: this.disableStuckAIDetection,
144
+ aiUltraModelSettings: this.aiUltraModelSettings
145
+ });
133
146
  });
134
147
  }
135
148
 
136
149
  reset() {
137
- if(this.worker) this.worker.postMessage({ type: "reset" });
150
+ this.passMessage({ type: "reset" });
138
151
  }
139
152
 
140
153
  start() {
141
- if(this.worker) this.worker.postMessage({ type: "start" });
154
+ this.passMessage({ type: "start" });
142
155
  }
143
156
 
144
157
  stop(finish) {
145
- if(this.worker) this.worker.postMessage({ type: finish ? "finish" : "stop" });
158
+ this.passMessage({ type: finish ? "finish" : "stop" });
146
159
  }
147
160
 
148
161
  finish(finish) {
149
- if(this.worker) this.worker.postMessage({ type: finish ? "finish" : "stop" });
162
+ this.passMessage({ type: finish ? "finish" : "stop" });
150
163
  }
151
164
 
152
165
  pause() {
153
- if(this.worker) this.worker.postMessage({ type: "pause" });
166
+ this.passMessage({ type: "pause" });
154
167
  }
155
168
 
156
169
  kill() {
@@ -162,27 +175,27 @@ class GameEngineMultithreadingController extends GameEngine {
162
175
  }
163
176
 
164
177
  tick() {
165
- if(this.worker) this.worker.postMessage({ type: "tick" });
178
+ this.passMessage({ type: "tick" });
166
179
  }
167
180
 
168
181
  exit() {
169
- if(this.worker) this.worker.postMessage({ type: "exit" });
182
+ this.passMessage({ type: "exit" });
170
183
  }
171
184
 
172
185
  key(key, numSnake) {
173
- if(this.worker) this.worker.postMessage({ type: "key", key: key, numSnake: numSnake });
186
+ this.passMessage({ type: "key", key: key, numSnake: numSnake });
174
187
  }
175
188
 
176
189
  setGameOver(numSnake) {
177
- if(this.worker) this.worker.postMessage({ type: "setGameOver", numSnake: numSnake });
190
+ this.passMessage({ type: "setGameOver", numSnake: numSnake });
178
191
  }
179
192
 
180
193
  forceStart() {
181
- if(this.worker) this.worker.postMessage({ type: "forceStart" });
194
+ this.passMessage({ type: "forceStart" });
182
195
  }
183
196
 
184
197
  updateEngine(key, data) {
185
- if(this.worker) this.worker.postMessage({ type: "update", key: key, data: data });
198
+ this.passMessage({ type: "update", key: key, data: data });
186
199
  }
187
200
 
188
201
  onReset(callback) {
@@ -224,6 +237,24 @@ class GameEngineMultithreadingController extends GameEngine {
224
237
  onUpdateCounter(callback) {
225
238
  this.reactor.addEventListener("onUpdateCounter", callback);
226
239
  }
240
+
241
+ passMessage(message) {
242
+ if(this.workerReady && this.worker) {
243
+ this.worker.postMessage(message);
244
+ } else {
245
+ this.messageQueue.push(message);
246
+ }
247
+ }
248
+
249
+ passQueuedMessages() {
250
+ if(this.workerReady && this.worker) {
251
+ this.messageQueue.forEach(message => {
252
+ this.worker.postMessage(message);
253
+ });
254
+
255
+ this.messageQueue = [];
256
+ }
257
+ }
227
258
  }
228
259
 
229
260
  module.exports = function(l) {
package/Player.js ADDED
@@ -0,0 +1,132 @@
1
+ /*
2
+ * Copyright (C) 2020-2025 Eliastik (eliastiksofts.com)
3
+ *
4
+ * This file is part of "SnakeIA Server".
5
+ *
6
+ * "SnakeIA Server" is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * "SnakeIA Server" is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with "SnakeIA Server". If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+ class Player {
20
+ constructor(token, id, snake, ready, version) {
21
+ this.token = token;
22
+ this.id = id;
23
+ this.snake = snake;
24
+ this.ready = ready;
25
+ this.version = version;
26
+ }
27
+
28
+ get username() {
29
+ return Player.getUsername(this);
30
+ }
31
+
32
+ static getPlayer(array, id) {
33
+ for (let i = 0; i < array.length; i++) {
34
+ if (array[i] != null && array[i].id == id) {
35
+ return array[i];
36
+ }
37
+ }
38
+
39
+ return null;
40
+ }
41
+
42
+ static getPlayerAllGames(id, games) {
43
+ const keys = Object.keys(games);
44
+
45
+ for (let i = 0; i < keys.length; i++) {
46
+ const game = games[keys[i]];
47
+
48
+ if (game) {
49
+ const p = this.getPlayer(game.players, id);
50
+ const p2 = this.getPlayer(game.spectators, id);
51
+ if (p) return p;
52
+ if (p2) return p2;
53
+ }
54
+ }
55
+
56
+ return null;
57
+ }
58
+
59
+ static getPlayerToken(array, token) {
60
+ if (!token) return null;
61
+ for (let i = 0; i < array.length; i++) {
62
+ if (array[i] != null && array[i].token == token) {
63
+ return array[i];
64
+ }
65
+ }
66
+
67
+ return null;
68
+ }
69
+
70
+ static getPlayerAllGamesToken(token, games) {
71
+ if (!token) return null;
72
+ const keys = Object.keys(games);
73
+
74
+ for (let i = 0; i < keys.length; i++) {
75
+ const game = games[keys[i]];
76
+
77
+ if (game) {
78
+ const p = this.getPlayerToken(game.players, token);
79
+ const p2 = this.getPlayerToken(game.spectators, token);
80
+ if (p) return p;
81
+ if (p2) return p2;
82
+ }
83
+ }
84
+
85
+ return null;
86
+ }
87
+
88
+ static containsId(array, id) {
89
+ return Player.getPlayer(array, id) != null;
90
+ }
91
+
92
+ static containsToken(array, token) {
93
+ return Player.getPlayerToken(array, token) != null;
94
+ }
95
+
96
+ static containsIdAllGames(id, games) {
97
+ return Player.getPlayerAllGames(id, games) != null;
98
+ }
99
+
100
+ static containsTokenAllGames(token, games) {
101
+ return Player.getPlayerAllGamesToken(token, games) != null;
102
+ }
103
+
104
+ static getUsername(player) {
105
+ try {
106
+ const decoded_token = jwt.verify(player.token, jsonWebTokenSecretKey);
107
+ return decoded_token && decoded_token.username
108
+ ? decoded_token.username
109
+ : null;
110
+ } catch (e) {
111
+ return null;
112
+ }
113
+ }
114
+
115
+ static getUsernameSocket(socket) {
116
+ try {
117
+ const decoded_token = jwt.verify(
118
+ socket.handshake.auth.token ||
119
+ socket.handshake.query.token ||
120
+ socket.request.cookies.token,
121
+ jsonWebTokenSecretKey
122
+ );
123
+ return decoded_token && decoded_token.username
124
+ ? decoded_token.username
125
+ : null;
126
+ } catch (e) {
127
+ return null;
128
+ }
129
+ }
130
+ }
131
+
132
+ module.exports = Player;