refactor of networking when first reaching game page

This commit is contained in:
AlecM33
2022-01-20 22:00:53 -05:00
parent d04a1d2b5e
commit fd3b05dd80
14 changed files with 308 additions and 307 deletions

View File

@@ -9,7 +9,6 @@ export const globals = {
ACCESS_CODE_CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789',
COMMANDS: {
FETCH_GAME_STATE: 'fetchGameState',
GET_ENVIRONMENT: 'getEnvironment',
START_GAME: 'startGame',
PAUSE_TIMER: 'pauseTimer',
RESUME_TIMER: 'resumeTimer',
@@ -18,8 +17,7 @@ export const globals = {
REVEAL_PLAYER: 'revealPlayer',
TRANSFER_MODERATOR: 'transferModerator',
CHANGE_NAME: 'changeName',
END_GAME: 'endGame',
FETCH_IN_PROGRESS_STATE: 'fetchInitialInProgressState'
END_GAME: 'endGame'
},
STATUS: {
LOBBY: 'lobby',

View File

@@ -105,6 +105,10 @@ export class GameCreationStepManager {
window.location = ('/game/' + res.content);
}
}).catch((e) => {
let button = document.getElementById("create-game");
button.innerText = "Create Game";
button.classList.remove('submitted');
button.addEventListener('click', this.steps["4"].forwardHandler);
if (e.status === 429) {
toast('You\'ve sent this request too many times.', 'error', true, true, 6);
}
@@ -395,6 +399,9 @@ function showButtons (back, forward, forwardHandler, backHandler, builtGame = nu
createButton.setAttribute('id', 'create-game');
createButton.classList.add('app-button');
createButton.addEventListener('click', () => {
createButton.removeEventListener('click', forwardHandler);
createButton.classList.add('submitted');
createButton.innerText = 'Creating...'
forwardHandler(
builtGame.deck.filter((card) => card.quantity > 0),
builtGame.hasTimer,

View File

@@ -254,7 +254,7 @@ function renderPotentialMods (gameState, group, transferModHandlers, socket) {
if ((member.out || member.userType === globals.USER_TYPES.SPECTATOR) && !(member.id === gameState.client.id)) {
const container = document.createElement('div');
container.classList.add('potential-moderator');
container.setAttribute("tabindex", "0");
container.setAttribute('tabindex', '0');
container.dataset.pointer = member.id;
container.innerText = member.name;
transferModHandlers[member.id] = (e) => {

View File

@@ -8,82 +8,105 @@ import { ModalManager } from '../modules/ModalManager.js';
import { stateBucket } from '../modules/StateBucket.js';
import { io } from 'socket.io-client';
import { injectNavbar } from '../modules/Navbar.js';
import { XHRUtility } from '../modules/XHRUtility.js';
const game = () => {
injectNavbar();
const timerWorker = new Worker(new URL('../modules/Timer.js', import.meta.url));
const socket = io('/in-game');
socket.on('disconnect', () => {
toast('Disconnected. Attempting reconnect...', 'error', true, false);
});
socket.on('connect', () => {
console.log('connect event fired');
socket.emit(globals.COMMANDS.GET_ENVIRONMENT, function (returnedEnvironment) {
prepareGamePage(returnedEnvironment, socket, timerWorker);
XHRUtility.xhr(
'/api/games/environment',
'GET',
null,
null
)
.then((res) => {
joinGame(res);
}).catch((res) => {
toast(res.content, 'error', true);
});
});
};
function prepareGamePage (environment, socket, timerWorker) {
let userId = UserUtility.validateAnonUserSignature(environment);
function joinGame (environmentResponse) {
let cookie = UserUtility.validateAnonUserSignature(environmentResponse.content);
const splitUrl = window.location.href.split('/game/');
const accessCode = splitUrl[1];
if (/^[a-zA-Z0-9]+$/.test(accessCode) && accessCode.length === globals.ACCESS_CODE_LENGTH) {
socket.emit(globals.COMMANDS.FETCH_GAME_STATE, accessCode, userId, function (gameState) {
stateBucket.currentGameState = gameState;
document.querySelector('.spinner-container')?.remove();
document.querySelector('.spinner-background')?.remove();
if (gameState === null) {
window.location = '/not-found?reason=' + encodeURIComponent('game-not-found');
} else {
document.getElementById('game-content').innerHTML = templates.INITIAL_GAME_DOM;
toast('You are connected.', 'success', true, true, 2);
userId = gameState.client.cookie;
UserUtility.setAnonymousUserId(userId, environment);
XHRUtility.xhr(
'/api/games/' + accessCode + '/players',
'PATCH',
null,
JSON.stringify({ cookie: cookie })
)
.then((res) => {
cookie = res.content;
UserUtility.setAnonymousUserId(res.content, environmentResponse.content);
const timerWorker = new Worker(new URL('../modules/Timer.js', import.meta.url));
const socket = io('/in-game');
const gameTimerManager = new GameTimerManager(stateBucket, socket);
const gameStateRenderer = new GameStateRenderer(stateBucket, socket);
let gameTimerManager;
if (stateBucket.currentGameState.timerParams) {
gameTimerManager = new GameTimerManager(stateBucket, socket);
socket.on('disconnect', () => {
toast('Disconnected. Attempting reconnect...', 'error', true, false);
});
socket.on('connect', () => {
prepareGamePage(
environmentResponse.content,
socket,
timerWorker,
cookie,
accessCode,
gameStateRenderer,
gameTimerManager
);
});
setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager);
}).catch((res) => {
if (res.status === 404) {
window.location = '/not-found?reason=' + encodeURIComponent('game-not-found');
} else if (res.status >= 500) {
toast(
'The server is experiencing problems. Please try again later',
'error',
true
);
}
initializeGame(stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager);
if (!gameState.client.hasEnteredName) {
document.getElementById('prompt').innerHTML = templates.NAME_CHANGE_MODAL;
document.getElementById('change-name-form').onsubmit = (e) => {
e.preventDefault();
const name = document.getElementById('player-new-name').value;
if (validateName(name)) {
socket.emit(globals.COMMANDS.CHANGE_NAME, gameState.accessCode, {
name: name,
personId: gameState.client.id
}, (result) => {
switch (result) {
case 'taken':
toast('This name is already taken.', 'error', true, true, 8);
break;
case 'changed':
ModalManager.dispelModal('change-name-modal', 'change-name-modal-background');
toast('Name set.', 'success', true, true, 5);
propagateNameChange(stateBucket.currentGameState, name, stateBucket.currentGameState.client.id);
processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker);
}
});
} else {
toast('Name must be between 1 and 30 characters.', 'error', true, true, 8);
}
};
}
}
});
} else {
window.location = '/not-found?reason=' + encodeURIComponent('invalid-access-code');
});
}
}
function initializeGame (stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager) {
setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager);
processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker);
function prepareGamePage (environment, socket, timerWorker, cookie, accessCode, gameStateRenderer, gameTimerManager) {
socket.emit(globals.COMMANDS.FETCH_GAME_STATE, accessCode, cookie, function (gameState) {
stateBucket.currentGameState = gameState;
document.querySelector('.spinner-container')?.remove();
document.querySelector('.spinner-background')?.remove();
document.getElementById('game-content').innerHTML = templates.INITIAL_GAME_DOM;
toast('You are connected.', 'success', true, true, 2);
processGameState(stateBucket.currentGameState, cookie, socket, gameStateRenderer, gameTimerManager, timerWorker);
if (!gameState.client.hasEnteredName) {
document.getElementById('prompt').innerHTML = templates.NAME_CHANGE_MODAL;
document.getElementById('change-name-form').onsubmit = (e) => {
e.preventDefault();
const name = document.getElementById('player-new-name').value;
if (validateName(name)) {
socket.emit(globals.COMMANDS.CHANGE_NAME, gameState.accessCode, {
name: name,
personId: gameState.client.id
}, (result) => {
switch (result) {
case 'taken':
toast('This name is already taken.', 'error', true, true, 8);
break;
case 'changed':
ModalManager.dispelModal('change-name-modal', 'change-name-modal-background');
toast('Name set.', 'success', true, true, 5);
propagateNameChange(stateBucket.currentGameState, name, stateBucket.currentGameState.client.id);
processGameState(stateBucket.currentGameState, cookie, socket, gameStateRenderer, gameTimerManager, timerWorker);
}
});
} else {
toast('Name must be between 1 and 30 characters.', 'error', true, true, 8);
}
};
}
});
}
function processGameState (currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker, refreshPrompt = true) {
@@ -163,79 +186,72 @@ function displayClientInfo (name, userType) {
}
function setClientSocketHandlers (stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager) {
if (!socket.hasListeners(globals.EVENTS.PLAYER_JOINED)) {
socket.on(globals.EVENTS.PLAYER_JOINED, (player, gameIsFull) => {
toast(player.name + ' joined!', 'success', false, true, 3);
stateBucket.currentGameState.people.push(player);
stateBucket.currentGameState.isFull = gameIsFull;
socket.on(globals.EVENTS.PLAYER_JOINED, (player, gameIsFull) => {
toast(player.name + ' joined!', 'success', false, true, 3);
stateBucket.currentGameState.people.push(player);
stateBucket.currentGameState.isFull = gameIsFull;
gameStateRenderer.renderLobbyPlayers();
if (
gameIsFull
&& (
stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|| stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
)
) {
displayStartGamePromptForModerators(stateBucket.currentGameState, gameStateRenderer);
}
});
socket.on(globals.EVENTS.PLAYER_LEFT, (player) => {
removeStartGameFunctionalityIfPresent(gameStateRenderer);
toast(player.name + ' has left!', 'error', false, true, 3);
const index = stateBucket.currentGameState.people.findIndex(person => person.id === player.id);
if (index >= 0) {
stateBucket.currentGameState.people.splice(
index,
1
);
gameStateRenderer.renderLobbyPlayers();
if (
gameIsFull
&& (
stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|| stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
)
) {
displayStartGamePromptForModerators(stateBucket.currentGameState, gameStateRenderer);
}
});
}
}
});
if (!socket.hasListeners(globals.EVENTS.PLAYER_LEFT)) {
socket.on(globals.EVENTS.PLAYER_LEFT, (player) => {
removeStartGameFunctionalityIfPresent(gameStateRenderer);
toast(player.name + ' has left!', 'error', false, true, 3);
const index = stateBucket.currentGameState.people.findIndex(person => person.id === player.id);
if (index >= 0) {
stateBucket.currentGameState.people.splice(
index,
1
socket.on(globals.EVENTS.START_GAME, () => {
socket.emit(
globals.COMMANDS.FETCH_GAME_STATE,
stateBucket.currentGameState.accessCode,
stateBucket.currentGameState.client.cookie,
function (gameState) {
stateBucket.currentGameState = gameState;
processGameState(
stateBucket.currentGameState,
gameState.client.cookie,
socket,
gameStateRenderer,
gameTimerManager,
timerWorker
);
gameStateRenderer.renderLobbyPlayers();
}
});
}
);
});
if (!socket.hasListeners(globals.EVENTS.START_GAME)) {
socket.on(globals.EVENTS.START_GAME, () => {
socket.emit(
globals.COMMANDS.FETCH_IN_PROGRESS_STATE,
stateBucket.currentGameState.accessCode,
stateBucket.currentGameState.client.cookie,
function (gameState) {
stateBucket.currentGameState = gameState;
processGameState(
stateBucket.currentGameState,
gameState.client.cookie,
socket,
gameStateRenderer,
gameTimerManager,
timerWorker
);
}
);
});
}
if (!socket.hasListeners(globals.EVENTS.SYNC_GAME_STATE)) {
socket.on(globals.EVENTS.SYNC_GAME_STATE, () => {
socket.emit(
globals.COMMANDS.FETCH_IN_PROGRESS_STATE,
stateBucket.currentGameState.accessCode,
stateBucket.currentGameState.client.cookie,
function (gameState) {
stateBucket.currentGameState = gameState;
processGameState(
stateBucket.currentGameState,
gameState.client.cookie,
socket,
gameStateRenderer,
gameTimerManager,
timerWorker
);
}
);
});
}
socket.on(globals.EVENTS.SYNC_GAME_STATE, () => {
socket.emit(
globals.COMMANDS.FETCH_GAME_STATE,
stateBucket.currentGameState.accessCode,
stateBucket.currentGameState.client.cookie,
function (gameState) {
stateBucket.currentGameState = gameState;
processGameState(
stateBucket.currentGameState,
gameState.client.cookie,
socket,
gameStateRenderer,
gameTimerManager,
timerWorker
);
}
);
});
if (timerWorker && gameTimerManager) {
gameTimerManager.attachTimerSocketListeners(socket, timerWorker, gameStateRenderer);

View File

@@ -21,7 +21,7 @@ function roomCodeIsValid (code) {
function attemptToJoinGame (code) {
XHRUtility.xhr(
'/api/games/availability/' + code.toLowerCase().trim(),
'/api/games/' + code.toLowerCase().trim() + 'availability',
'GET',
null,
null

View File

@@ -11,10 +11,6 @@ th, thead, tr, tt, u, ul, var {
border: 0;
background: transparent;
}
@font-face {
font-family: 'signika-negative';
src: url("../webfonts/Diavlo_LIGHT_II_37.woff2") format("woff2");
}
@font-face {
font-family: 'signika-negative';
@@ -164,6 +160,11 @@ button {
border: 2px solid #8a1c1c !important;
}
.submitted {
filter: opacity(0.5);
pointer-events: none;
}
.container {
padding: 5px;
border-radius: 3px;

View File

@@ -1,68 +1,68 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Create A Game</title>
<meta name="description" content="This resource was not found.">
<meta property="og:title" content="Not Found">
<meta property="og:type" content="website">
<meta property="og:url" content="https://playwerewolf.uk.r.appspot.com/not-found">
<meta property="og:description" content="The page you are looking for could not be found.">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="/styles/GLOBAL.css">
<link rel="stylesheet" href="/styles/create.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
</head>
<body>
<div id="mobile-menu-background-overlay"></div>
<div id="navbar"></div>
<span>
<h1>404</h1>
<h3>The game or other resource that you are looking for could not be found, or you don't have permission to access it.
If this error is unexpected, the application may have restarted.</h3>
</span>
<style>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Not Found</title>
<meta name="description" content="This resource was not found.">
<meta property="og:title" content="Not Found">
<meta property="og:type" content="website">
<meta property="og:url" content="https://playwerewolf.uk.r.appspot.com/not-found">
<meta property="og:description" content="The page you are looking for could not be found.">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="/styles/GLOBAL.css">
<link rel="stylesheet" href="/styles/create.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
<style>
h1 {
margin: 0 auto;
}
h1 {
margin: 0 auto;
}
h3 {
max-width: 40em;
font-size: 20px;
padding: 1em;
margin: 0 auto;
}
h3 {
max-width: 40em;
font-size: 20px;
padding: 1em;
margin: 0 auto;
}
html, body {
height: 100%;
}
html, body {
height: 100%;
}
span {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 0 auto;
}
#not-found-container {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 0 auto;
}
@media(min-width: 701px) {
h1 {
font-size: 75px;
}
}
@media(max-width: 700px) {
h1 {
font-size: 40px;
}
}
</style>
<script src="/dist/notFound-bundle.js"></script>
</body>
@media(min-width: 701px) {
h1 {
font-size: 75px;
}
}
@media(max-width: 700px) {
h1 {
font-size: 40px;
}
}
</style>
</head>
<body>
<div id="mobile-menu-background-overlay"></div>
<div id="navbar"></div>
<div id="not-found-container">
<h1>404</h1>
<h3>The game or other resource that you are looking for could not be found, or you don't have permission to access it.
If this error is unexpected, the application may have restarted.</h3>
</div>
<script src="/dist/notFound-bundle.js"></script>
</body>
</html>

View File

@@ -16,8 +16,7 @@
<link rel="stylesheet" href="/styles/game.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
<link rel="preload" as="font" href="/webfonts/SignikaNegative-Light.woff2" crossorigin/>
<link rel="preload" as="font" href="/webfonts/Diavlo_LIGHT_II_37.woff2" crossorigin/>
<link rel="preload" href="/webfonts/SignikaNegative-Light.woff2" as="font" type="font/woff2" crossorigin>
</head>
<body>
<div id="prompt"></div>

View File

@@ -6,6 +6,7 @@
"scripts": {
"bundle": "webpack --config client/webpack/webpack-prod.config.js",
"prestart": "npm run bundle",
"gcp-build": "webpack --config client/webpack/webpack-prod.config.js",
"build:dev": "webpack --watch --config client/webpack/webpack-dev.config.js --mode=development",
"start:dev": "NODE_ENV=development nodemon server/main.js",
"start:dev:no-hot-reload": "NODE_ENV=development && node server/main.js",

View File

@@ -35,9 +35,9 @@ router.post('/create', function (req, res) {
});
});
router.get('/availability/:code', function (req, res) {
const joinGamePromise = gameManager.joinGame(req.params.code);
joinGamePromise.then((result) => {
router.get('/:code/availability', function (req, res) {
const availabilityPromise = gameManager.checkAvailability(req.params.code);
availabilityPromise.then((result) => {
if (result === 404) {
res.status(404).send();
} else if (result instanceof Error) {
@@ -51,4 +51,26 @@ router.get('/availability/:code', function (req, res) {
});
});
router.patch('/:code/players', function (req, res) {
console.log(typeof req.body.cookie);
console.log(req.body.cookie);
if (
req.body === null
|| req.body.cookie === null
|| (typeof req.body.cookie !== 'string' && req.body.cookie !== false)
|| (req.body.cookie.length !== globals.USER_SIGNATURE_LENGTH && req.body.cookie !== false)
) {
res.status(400).send();
}
gameManager.joinGame(req.body.cookie, req.params.code).then((data) => {
res.status(200).send(data);
}).catch((code) => {
res.status(code).send();
});
});
router.get('/environment', function (req, res) {
res.status(200).send(gameManager.environment);
});
module.exports = router;

View File

@@ -5,7 +5,6 @@ const globals = {
STALE_GAME_HOURS: 12,
CLIENT_COMMANDS: {
FETCH_GAME_STATE: 'fetchGameState',
GET_ENVIRONMENT: 'getEnvironment',
START_GAME: 'startGame',
PAUSE_TIMER: 'pauseTimer',
RESUME_TIMER: 'resumeTimer',
@@ -14,8 +13,7 @@ const globals = {
REVEAL_PLAYER: 'revealPlayer',
TRANSFER_MODERATOR: 'transferModerator',
CHANGE_NAME: 'changeName',
END_GAME: 'endGame',
FETCH_IN_PROGRESS_STATE: 'fetchInitialInProgressState'
END_GAME: 'endGame'
},
MESSAGES: {
ENTER_NAME: 'Client must enter name.'

View File

@@ -24,14 +24,6 @@ app.set('port', args.port);
const inGameSocketServer = ServerBootstrapper.createSocketServer(main, app, args.port);
inGameSocketServer.on('connection', function (socket) {
socket.on('disconnecting', (reason) => {
logger.trace('client socket disconnecting because: ' + reason);
gameManager.removeClientFromLobbyIfApplicable(socket);
});
gameManager.addGameSocketHandlers(inGameSocketServer, socket);
});
let gameManager;
/* Instantiate the singleton game manager */
@@ -41,6 +33,16 @@ if (process.env.NODE_ENV.trim() === 'development') {
gameManager = new GameManager(logger, globals.ENVIRONMENT.PRODUCTION).getInstance();
}
gameManager.namespace = inGameSocketServer;
inGameSocketServer.on('connection', function (socket) {
socket.on('disconnecting', (reason) => {
logger.trace('client socket disconnecting because: ' + reason);
gameManager.removeClientFromLobbyIfApplicable(socket);
});
gameManager.addGameSocketHandlers(inGameSocketServer, socket);
});
/* api endpoints */
const games = require('./api/GamesAPI');
app.use('/api/games', games);

View File

@@ -14,7 +14,6 @@ class GameManager {
}
addGameSocketHandlers = (namespace, socket) => {
this.namespace = namespace;
socket.on(globals.CLIENT_COMMANDS.FETCH_GAME_STATE, (accessCode, personId, ackFn) => {
this.logger.trace('request for game state for accessCode: ' + accessCode + ' from socket: ' + socket.id + ' with cookie: ' + personId);
this.handleRequestForGameState(
@@ -28,27 +27,6 @@ class GameManager {
);
});
/* this event handler will call handleRequestForGameState() with the 'handleNoMatch' arg as false - only
connections that match a participant in the game at that time will have the game state sent to them.
*/
socket.on(globals.CLIENT_COMMANDS.FETCH_IN_PROGRESS_STATE, (accessCode, personId, ackFn) => {
this.logger.trace('request for game state for accessCode ' + accessCode + ', person ' + personId);
this.handleRequestForGameState(
this.namespace,
this.logger,
this.activeGameRunner,
accessCode,
personId,
ackFn,
socket,
false
);
});
socket.on(globals.CLIENT_COMMANDS.GET_ENVIRONMENT, (ackFn) => {
ackFn(this.environment);
});
socket.on(globals.CLIENT_COMMANDS.START_GAME, (accessCode) => {
const game = this.activeGameRunner.activeGames[accessCode];
if (game && game.isFull) {
@@ -152,7 +130,7 @@ class GameManager {
socket.on(globals.CLIENT_COMMANDS.CHANGE_NAME, (accessCode, data, ackFn) => {
const game = this.activeGameRunner.activeGames[accessCode];
if (game) {
const person = findPersonById(game, data.personId);
const person = findPersonByField(game, 'id', data.personId);
if (person) {
if (!isNameTaken(game, data.name)) {
ackFn('changed');
@@ -207,7 +185,7 @@ class GameManager {
}
};
joinGame = (code) => {
checkAvailability = (code) => {
const game = this.activeGameRunner.activeGames[code];
if (game) {
const unassignedPerson = game.people.find((person) => person.assigned === false);
@@ -275,16 +253,47 @@ class GameManager {
}
};
handleRequestForGameState = (namespace, logger, gameRunner, accessCode, personCookie, ackFn, socket, handleNoMatch = true) => {
joinGame = (cookie, accessCode) => {
const game = this.activeGameRunner.activeGames[accessCode];
if (game) {
const person = findPersonByField(game, 'cookie', cookie);
if (person) {
return Promise.resolve(person.cookie);
} else {
const unassignedPerson = game.moderator.assigned === false
? game.moderator
: game.people.find((person) => person.assigned === false);
if (unassignedPerson) {
this.logger.trace('request from client to join game. Assigning: ' + unassignedPerson.name);
unassignedPerson.assigned = true;
game.isFull = isGameFull(game);
this.namespace.in(game.accessCode).emit(
globals.EVENTS.PLAYER_JOINED,
GameStateCurator.mapPerson(unassignedPerson),
game.isFull
);
return Promise.resolve(unassignedPerson.cookie);
} else { // if the game is full, make them a spectator.
const spectator = new Person(
createRandomId(),
createRandomId(),
UsernameGenerator.generate(),
globals.USER_TYPES.SPECTATOR
);
this.logger.trace('new spectator: ' + spectator.name);
game.spectators.push(spectator);
return Promise.resolve(spectator.cookie);
}
}
} else {
return Promise.reject(404);
}
};
handleRequestForGameState = (namespace, logger, gameRunner, accessCode, personCookie, ackFn, socket) => {
const game = gameRunner.activeGames[accessCode];
if (game) {
let matchingPerson = game.people.find((person) => person.cookie === personCookie);
if (!matchingPerson) {
matchingPerson = game.spectators.find((spectator) => spectator.cookie === personCookie);
}
if (!matchingPerson && game.moderator.cookie === personCookie) {
matchingPerson = game.moderator;
}
const matchingPerson = findPersonByField(game, 'cookie', personCookie);
if (matchingPerson) {
if (matchingPerson.socketId === socket.id) {
logger.trace('matching person found with an established connection to the room: ' + matchingPerson.name);
@@ -295,8 +304,8 @@ class GameManager {
matchingPerson.socketId = socket.id;
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson, gameRunner, socket, logger));
}
} else if (handleNoMatch) {
this.handleRequestFromNonMatchingPerson(game, socket, gameRunner, ackFn, logger);
} else {
rejectClientRequestForGameState(ackFn);
}
} else {
rejectClientRequestForGameState(ackFn);
@@ -304,43 +313,6 @@ class GameManager {
}
};
handleRequestFromNonMatchingPerson = (game, socket, gameRunner, ackFn, logger) => {
const personWithMatchingSocketId = findPersonWithMatchingSocketId(game, socket.id);
if (personWithMatchingSocketId) {
logger.trace('matching person found whose cookie got cleared after establishing a connection to the room: ' + personWithMatchingSocketId.name);
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, personWithMatchingSocketId, gameRunner, socket, logger));
} else {
const unassignedPerson = game.moderator.assigned === false
? game.moderator
: game.people.find((person) => person.assigned === false);
if (unassignedPerson) {
logger.trace('completely new person with a first connection to the room: ' + unassignedPerson.name);
unassignedPerson.assigned = true;
unassignedPerson.socketId = socket.id;
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, unassignedPerson, gameRunner, socket, logger));
const isFull = isGameFull(game);
game.isFull = isFull;
socket.to(game.accessCode).emit(
globals.EVENTS.PLAYER_JOINED,
GameStateCurator.mapPerson(unassignedPerson),
isFull
);
} else { // if the game is full, make them a spectator.
const spectator = new Person(
createRandomId(),
createRandomId(),
UsernameGenerator.generate(),
globals.USER_TYPES.SPECTATOR
);
spectator.socketId = socket.id;
logger.trace('new spectator: ' + spectator.name);
game.spectators.push(spectator);
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, spectator, gameRunner, socket, logger));
}
socket.join(game.accessCode);
}
};
removeClientFromLobbyIfApplicable (socket) {
socket.rooms.forEach((room) => {
if (this.activeGameRunner.activeGames[room]) {
@@ -442,17 +414,6 @@ function rejectClientRequestForGameState (acknowledgementFunction) {
return acknowledgementFunction(null);
}
function findPersonWithMatchingSocketId (game, socketId) {
let person = game.people.find((person) => person.socketId === socketId);
if (!person) {
person = game.spectators.find((spectator) => spectator.socketId === socketId);
}
if (!person && game.moderator.socketId === socketId) {
person = game.moderator;
}
return person;
}
function findPlayerBySocketId (people, socketId) {
return people.find((person) => person.socketId === socketId && person.userType === globals.USER_TYPES.PLAYER);
}
@@ -461,16 +422,16 @@ function isGameFull (game) {
return game.moderator.assigned === true && !game.people.find((person) => person.assigned === false);
}
function findPersonById (game, id) {
function findPersonByField (game, fieldName, value) {
let person;
if (id === game.moderator.id) {
if (value === game.moderator[fieldName]) {
person = game.moderator;
}
if (!person) {
person = game.people.find((person) => person.id === id);
person = game.people.find((person) => person[fieldName] === value);
}
if (!person) {
person = game.spectators.find((spectator) => spectator.id === id);
person = game.spectators.find((spectator) => spectator[fieldName] === value);
}
return person;
}

View File

@@ -65,15 +65,11 @@ const ServerBootstrapper = {
let io;
if (process.env.NODE_ENV.trim() === 'development') {
io = require('socket.io')(main, {
cors: { origin: 'http://localhost:' + port },
pingTimeout: 5000,
pingInterval: 5000
cors: { origin: 'http://localhost:' + port }
});
} else {
io = require('socket.io')(main, {
cors: { origin: 'https://playwerewolf.uk.r.appspot.com' },
pingTimeout: 5000,
pingInterval: 5000
cors: { origin: 'https://playwerewolf.uk.r.appspot.com' }
});
}