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>