mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 07:47:50 +01:00
further redis effort
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
export const globals = {
|
export const globals = {
|
||||||
CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789',
|
CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789',
|
||||||
USER_SIGNATURE_LENGTH: 25,
|
USER_SIGNATURE_LENGTH: 75,
|
||||||
CLOCK_TICK_INTERVAL_MILLIS: 100,
|
CLOCK_TICK_INTERVAL_MILLIS: 100,
|
||||||
MAX_CUSTOM_ROLE_NAME_LENGTH: 50,
|
MAX_CUSTOM_ROLE_NAME_LENGTH: 50,
|
||||||
MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 1000,
|
MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 1000,
|
||||||
@@ -50,8 +50,10 @@ export const globals = {
|
|||||||
SYNC_GAME_STATE: 'syncGameState',
|
SYNC_GAME_STATE: 'syncGameState',
|
||||||
START_TIMER: 'startTimer',
|
START_TIMER: 'startTimer',
|
||||||
PLAYER_LEFT: 'playerLeft',
|
PLAYER_LEFT: 'playerLeft',
|
||||||
UPDATE_SPECTATORS: 'newSpectator',
|
ADD_SPECTATOR: 'addSpectator',
|
||||||
RESTART_GAME: 'restartGame'
|
UPDATE_SPECTATORS: 'updateSpectators',
|
||||||
|
RESTART_GAME: 'restartGame',
|
||||||
|
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod'
|
||||||
},
|
},
|
||||||
USER_TYPES: {
|
USER_TYPES: {
|
||||||
MODERATOR: 'moderator',
|
MODERATOR: 'moderator',
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ export class Ended {
|
|||||||
// sortPeopleByStatus(this.stateBucket.currentGameState.people);
|
// sortPeopleByStatus(this.stateBucket.currentGameState.people);
|
||||||
const modType = tempMod ? this.stateBucket.currentGameState.moderator.userType : null;
|
const modType = tempMod ? this.stateBucket.currentGameState.moderator.userType : null;
|
||||||
renderGroupOfPlayers(
|
renderGroupOfPlayers(
|
||||||
this.stateBucket.currentGameState.people,
|
this.stateBucket.currentGameState.people.filter(
|
||||||
|
p => p.userType === globals.USER_TYPES.PLAYER
|
||||||
|
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
|| p.killed
|
||||||
|
),
|
||||||
this.stateBucket.currentGameState.accessCode,
|
this.stateBucket.currentGameState.accessCode,
|
||||||
null,
|
null,
|
||||||
modType,
|
modType,
|
||||||
@@ -35,7 +39,7 @@ export class Ended {
|
|||||||
);
|
);
|
||||||
document.getElementById('players-alive-label').innerText =
|
document.getElementById('players-alive-label').innerText =
|
||||||
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
|
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
|
||||||
this.stateBucket.currentGameState.people.length + ' Alive';
|
this.stateBucket.currentGameState.gameSize + ' Alive';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ export class InProgress {
|
|||||||
|
|
||||||
if (spectatorCount) {
|
if (spectatorCount) {
|
||||||
spectatorCount?.addEventListener('click', () => {
|
spectatorCount?.addEventListener('click', () => {
|
||||||
Confirmation(SharedStateUtil.buildSpectatorList(this.stateBucket.currentGameState.spectators), null, true);
|
Confirmation(SharedStateUtil.buildSpectatorList(this.stateBucket.currentGameState.people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR)), null, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
SharedStateUtil.setNumberOfSpectators(
|
SharedStateUtil.setNumberOfSpectators(
|
||||||
this.stateBucket.currentGameState.spectators.length,
|
this.stateBucket.currentGameState.people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR).length,
|
||||||
spectatorCount
|
spectatorCount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -90,9 +90,16 @@ export class InProgress {
|
|||||||
/* TODO: UX issue - it's easier to parse visually when players are sorted this way,
|
/* TODO: UX issue - it's easier to parse visually when players are sorted this way,
|
||||||
but shifting players around when they are killed or revealed is bad UX for the moderator. */
|
but shifting players around when they are killed or revealed is bad UX for the moderator. */
|
||||||
// sortPeopleByStatus(this.stateBucket.currentGameState.people);
|
// sortPeopleByStatus(this.stateBucket.currentGameState.people);
|
||||||
const modType = tempMod ? this.stateBucket.currentGameState.moderator.userType : null;
|
const modType = tempMod
|
||||||
|
? this.stateBucket.currentGameState.people.find(person =>
|
||||||
|
person.id === this.stateBucket.currentGameState.currentModeratorId).userType
|
||||||
|
: null;
|
||||||
this.renderGroupOfPlayers(
|
this.renderGroupOfPlayers(
|
||||||
this.stateBucket.currentGameState.people,
|
this.stateBucket.currentGameState.people.filter(
|
||||||
|
p => p.userType === globals.USER_TYPES.PLAYER
|
||||||
|
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
|| p.killed
|
||||||
|
),
|
||||||
this.killPlayerHandlers,
|
this.killPlayerHandlers,
|
||||||
this.revealRoleHandlers,
|
this.revealRoleHandlers,
|
||||||
this.stateBucket.currentGameState.accessCode,
|
this.stateBucket.currentGameState.accessCode,
|
||||||
@@ -102,7 +109,7 @@ export class InProgress {
|
|||||||
);
|
);
|
||||||
document.getElementById('players-alive-label').innerText =
|
document.getElementById('players-alive-label').innerText =
|
||||||
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
|
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
|
||||||
this.stateBucket.currentGameState.people.length + ' Alive';
|
this.stateBucket.currentGameState.gameSize + ' Alive';
|
||||||
}
|
}
|
||||||
|
|
||||||
removePlayerListEventListeners (removeEl = true) {
|
removePlayerListEventListeners (removeEl = true) {
|
||||||
@@ -155,6 +162,7 @@ export class InProgress {
|
|||||||
const killedPerson = this.stateBucket.currentGameState.people.find((person) => person.id === id);
|
const killedPerson = this.stateBucket.currentGameState.people.find((person) => person.id === id);
|
||||||
if (killedPerson) {
|
if (killedPerson) {
|
||||||
killedPerson.out = true;
|
killedPerson.out = true;
|
||||||
|
killedPerson.killed = true;
|
||||||
killedPerson.userType = globals.USER_TYPES.KILLED_PLAYER;
|
killedPerson.userType = globals.USER_TYPES.KILLED_PLAYER;
|
||||||
if (this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR) {
|
if (this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR) {
|
||||||
toast(killedPerson.name + ' killed.', 'success', true, true, 'medium');
|
toast(killedPerson.name + ' killed.', 'success', true, true, 'medium');
|
||||||
@@ -203,14 +211,27 @@ export class InProgress {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.socket.hasListeners(globals.EVENT_IDS.UPDATE_SPECTATORS)) {
|
if (this.socket.hasListeners(globals.EVENT_IDS.ADD_SPECTATOR)) {
|
||||||
this.socket.removeAllListeners(globals.EVENT_IDS.UPDATE_SPECTATORS);
|
this.socket.removeAllListeners(globals.EVENT_IDS.ADD_SPECTATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.socket.on(globals.EVENT_IDS.UPDATE_SPECTATORS, (updatedSpectatorList) => {
|
this.socket.on(globals.EVENT_IDS.ADD_SPECTATOR, (spectator) => {
|
||||||
stateBucket.currentGameState.spectators = updatedSpectatorList;
|
stateBucket.currentGameState.people.push(spectator);
|
||||||
SharedStateUtil.setNumberOfSpectators(
|
SharedStateUtil.setNumberOfSpectators(
|
||||||
stateBucket.currentGameState.spectators.length,
|
stateBucket.currentGameState.people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR).length,
|
||||||
|
document.getElementById('spectator-count')
|
||||||
|
);
|
||||||
|
if (this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||||
|
|| this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||||
|
this.displayAvailableModerators();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on(globals.EVENT_IDS.UPDATE_SPECTATORS, (spectators) => {
|
||||||
|
stateBucket.currentGameState.people = stateBucket.currentGameState.people.filter(p => p.userType !== globals.USER_TYPES.SPECTATOR);
|
||||||
|
stateBucket.currentGameState.people = stateBucket.currentGameState.people.concat(spectators);
|
||||||
|
SharedStateUtil.setNumberOfSpectators(
|
||||||
|
stateBucket.currentGameState.people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR).length,
|
||||||
document.getElementById('spectator-count')
|
document.getElementById('spectator-count')
|
||||||
);
|
);
|
||||||
if (this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|
if (this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||||
@@ -231,15 +252,26 @@ export class InProgress {
|
|||||||
this.stateBucket.currentGameState.people.sort((a, b) => {
|
this.stateBucket.currentGameState.people.sort((a, b) => {
|
||||||
return a.name >= b.name ? 1 : -1;
|
return a.name >= b.name ? 1 : -1;
|
||||||
});
|
});
|
||||||
const teamGood = this.stateBucket.currentGameState.people.filter((person) => person.alignment === globals.ALIGNMENT.GOOD);
|
const teamGood = this.stateBucket.currentGameState.people.filter(
|
||||||
const teamEvil = this.stateBucket.currentGameState.people.filter((person) => person.alignment === globals.ALIGNMENT.EVIL);
|
(p) => p.alignment === globals.ALIGNMENT.GOOD
|
||||||
|
&& (p.userType === globals.USER_TYPES.PLAYER
|
||||||
|
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
|| p.killed)
|
||||||
|
|
||||||
|
);
|
||||||
|
const teamEvil = this.stateBucket.currentGameState.people.filter((p) => p.alignment === globals.ALIGNMENT.EVIL
|
||||||
|
&& (p.userType === globals.USER_TYPES.PLAYER
|
||||||
|
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
|| p.killed)
|
||||||
|
);
|
||||||
this.renderGroupOfPlayers(
|
this.renderGroupOfPlayers(
|
||||||
teamEvil,
|
teamEvil,
|
||||||
this.killPlayerHandlers,
|
this.killPlayerHandlers,
|
||||||
this.revealRoleHandlers,
|
this.revealRoleHandlers,
|
||||||
this.stateBucket.currentGameState.accessCode,
|
this.stateBucket.currentGameState.accessCode,
|
||||||
globals.ALIGNMENT.EVIL,
|
globals.ALIGNMENT.EVIL,
|
||||||
this.stateBucket.currentGameState.moderator.userType,
|
this.stateBucket.currentGameState.people.find(person =>
|
||||||
|
person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
|
||||||
this.socket
|
this.socket
|
||||||
);
|
);
|
||||||
this.renderGroupOfPlayers(
|
this.renderGroupOfPlayers(
|
||||||
@@ -248,12 +280,13 @@ export class InProgress {
|
|||||||
this.revealRoleHandlers,
|
this.revealRoleHandlers,
|
||||||
this.stateBucket.currentGameState.accessCode,
|
this.stateBucket.currentGameState.accessCode,
|
||||||
globals.ALIGNMENT.GOOD,
|
globals.ALIGNMENT.GOOD,
|
||||||
this.stateBucket.currentGameState.moderator.userType,
|
this.stateBucket.currentGameState.people.find(person =>
|
||||||
|
person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
|
||||||
this.socket
|
this.socket
|
||||||
);
|
);
|
||||||
document.getElementById('players-alive-label').innerText =
|
document.getElementById('players-alive-label').innerText =
|
||||||
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
|
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
|
||||||
this.stateBucket.currentGameState.people.length + ' Alive';
|
this.stateBucket.currentGameState.gameSize + ' Alive';
|
||||||
}
|
}
|
||||||
|
|
||||||
renderGroupOfPlayers (
|
renderGroupOfPlayers (
|
||||||
@@ -302,7 +335,11 @@ export class InProgress {
|
|||||||
} else if (!player.out && moderatorType) {
|
} else if (!player.out && moderatorType) {
|
||||||
killPlayerHandlers[player.id] = () => {
|
killPlayerHandlers[player.id] = () => {
|
||||||
Confirmation('Kill \'' + player.name + '\'?', () => {
|
Confirmation('Kill \'' + player.name + '\'?', () => {
|
||||||
socket.emit(globals.SOCKET_EVENTS.IN_GAME_MESSAGE, globals.EVENT_IDS.KILL_PLAYER, accessCode, { personId: player.id });
|
if (this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||||
|
socket.emit(globals.SOCKET_EVENTS.IN_GAME_MESSAGE, globals.EVENT_IDS.ASSIGN_DEDICATED_MOD, accessCode, { personId: player.id });
|
||||||
|
} else {
|
||||||
|
socket.emit(globals.SOCKET_EVENTS.IN_GAME_MESSAGE, globals.EVENT_IDS.KILL_PLAYER, accessCode, { personId: player.id });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
playerEl.querySelector('.kill-player-button').addEventListener('click', killPlayerHandlers[player.id]);
|
playerEl.querySelector('.kill-player-button').addEventListener('click', killPlayerHandlers[player.id]);
|
||||||
@@ -347,12 +384,6 @@ export class InProgress {
|
|||||||
this.transferModHandlers,
|
this.transferModHandlers,
|
||||||
this.socket
|
this.socket
|
||||||
);
|
);
|
||||||
renderPotentialMods( // spectators can also be made mods.
|
|
||||||
this.stateBucket.currentGameState,
|
|
||||||
this.stateBucket.currentGameState.spectators,
|
|
||||||
this.transferModHandlers,
|
|
||||||
this.socket
|
|
||||||
);
|
|
||||||
|
|
||||||
if (document.querySelectorAll('.potential-moderator').length === 0) {
|
if (document.querySelectorAll('.potential-moderator').length === 0) {
|
||||||
document.getElementById('transfer-mod-modal-content').innerText = 'There is nobody available to transfer to.';
|
document.getElementById('transfer-mod-modal-content').innerText = 'There is nobody available to transfer to.';
|
||||||
@@ -475,7 +506,7 @@ function insertPlaceholderButton (container, append, type) {
|
|||||||
function renderPotentialMods (gameState, group, transferModHandlers, socket) {
|
function renderPotentialMods (gameState, group, transferModHandlers, socket) {
|
||||||
const modalContent = document.getElementById('transfer-mod-modal-content');
|
const modalContent = document.getElementById('transfer-mod-modal-content');
|
||||||
for (const member of group) {
|
for (const member of group) {
|
||||||
if ((member.out || member.userType === globals.USER_TYPES.SPECTATOR) && !(member.id === gameState.client.id)) {
|
if ((member.userType === globals.USER_TYPES.KILLED_PLAYER || member.userType === globals.USER_TYPES.SPECTATOR) && !(member.id === gameState.client.id)) {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
container.classList.add('potential-moderator');
|
container.classList.add('potential-moderator');
|
||||||
container.setAttribute('tabindex', '0');
|
container.setAttribute('tabindex', '0');
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ export class Lobby {
|
|||||||
playerCount.innerText = this.stateBucket.currentGameState.gameSize + ' Players';
|
playerCount.innerText = this.stateBucket.currentGameState.gameSize + ' Players';
|
||||||
|
|
||||||
this.container.querySelector('#spectator-count').addEventListener('click', () => {
|
this.container.querySelector('#spectator-count').addEventListener('click', () => {
|
||||||
Confirmation(SharedStateUtil.buildSpectatorList(this.stateBucket.currentGameState.spectators), null, true);
|
Confirmation(SharedStateUtil.buildSpectatorList(this.stateBucket.currentGameState.people), null, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
SharedStateUtil.setNumberOfSpectators(
|
SharedStateUtil.setNumberOfSpectators(
|
||||||
this.stateBucket.currentGameState.spectators.length,
|
this.stateBucket.currentGameState.people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR).length,
|
||||||
this.container.querySelector('#spectator-count')
|
this.container.querySelector('#spectator-count')
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -68,18 +68,20 @@ export class Lobby {
|
|||||||
populatePlayers () {
|
populatePlayers () {
|
||||||
document.querySelectorAll('.lobby-player').forEach((el) => el.remove());
|
document.querySelectorAll('.lobby-player').forEach((el) => el.remove());
|
||||||
const lobbyPlayersContainer = this.container.querySelector('#lobby-players');
|
const lobbyPlayersContainer = this.container.querySelector('#lobby-players');
|
||||||
if (this.stateBucket.currentGameState.moderator.userType === globals.USER_TYPES.MODERATOR) {
|
const sorted = this.stateBucket.currentGameState.people.sort(
|
||||||
lobbyPlayersContainer.appendChild(
|
function (a, b) {
|
||||||
renderLobbyPerson(
|
if (a.userType === globals.USER_TYPES.MODERATOR) {
|
||||||
this.stateBucket.currentGameState.moderator.name,
|
return -1;
|
||||||
this.stateBucket.currentGameState.moderator.userType
|
}
|
||||||
)
|
return 1;
|
||||||
);
|
}
|
||||||
}
|
);
|
||||||
for (const person of this.stateBucket.currentGameState.people) {
|
for (const person of sorted.filter(p => p.userType !== globals.USER_TYPES.SPECTATOR)) {
|
||||||
lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name, person.userType));
|
lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name, person.userType));
|
||||||
}
|
}
|
||||||
const playerCount = this.stateBucket.currentGameState.people.length;
|
const playerCount = this.stateBucket.currentGameState.people.filter(
|
||||||
|
p => p.userType === globals.USER_TYPES.PLAYER || p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
).length;
|
||||||
document.querySelector("label[for='lobby-players']").innerText =
|
document.querySelector("label[for='lobby-players']").innerText =
|
||||||
'Participants (' + playerCount + '/' + this.stateBucket.currentGameState.gameSize + ' Players)';
|
'Participants (' + playerCount + '/' + this.stateBucket.currentGameState.gameSize + ' Players)';
|
||||||
}
|
}
|
||||||
@@ -99,10 +101,10 @@ export class Lobby {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on(globals.EVENT_IDS.UPDATE_SPECTATORS, (updatedSpectatorList) => {
|
this.socket.on(globals.EVENT_IDS.ADD_SPECTATOR, (spectator) => {
|
||||||
this.stateBucket.currentGameState.spectators = updatedSpectatorList;
|
this.stateBucket.currentGameState.people.push(spectator);
|
||||||
SharedStateUtil.setNumberOfSpectators(
|
SharedStateUtil.setNumberOfSpectators(
|
||||||
this.stateBucket.currentGameState.spectators.length,
|
this.stateBucket.currentGameState.people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR).length,
|
||||||
document.getElementById('spectator-count')
|
document.getElementById('spectator-count')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -193,6 +195,9 @@ function renderLobbyPerson (name, userType) {
|
|||||||
personNameEl.innerText = name;
|
personNameEl.innerText = name;
|
||||||
personTypeEl.innerText = userType + globals.USER_TYPE_ICONS[userType];
|
personTypeEl.innerText = userType + globals.USER_TYPE_ICONS[userType];
|
||||||
el.classList.add('lobby-player');
|
el.classList.add('lobby-player');
|
||||||
|
if (userType === globals.USER_TYPES.MODERATOR) {
|
||||||
|
el.classList.add('moderator');
|
||||||
|
}
|
||||||
|
|
||||||
el.appendChild(personNameEl);
|
el.appendChild(personNameEl);
|
||||||
el.appendChild(personTypeEl);
|
el.appendChild(personTypeEl);
|
||||||
|
|||||||
@@ -132,8 +132,9 @@ export const SharedStateUtil = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buildSpectatorList (spectators) {
|
buildSpectatorList (people) {
|
||||||
const list = document.createElement('div');
|
const list = document.createElement('div');
|
||||||
|
const spectators = people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR);
|
||||||
if (spectators.length === 0) {
|
if (spectators.length === 0) {
|
||||||
list.innerHTML = '<div>Nobody currently spectating.</div>';
|
list.innerHTML = '<div>Nobody currently spectating.</div>';
|
||||||
} else {
|
} else {
|
||||||
@@ -173,8 +174,18 @@ function processGameState (
|
|||||||
easing: 'ease-in-out',
|
easing: 'ease-in-out',
|
||||||
fill: 'both'
|
fill: 'both'
|
||||||
});
|
});
|
||||||
|
const clientAnimation = document.getElementById('client-container').animate([
|
||||||
|
{ opacity: '0' },
|
||||||
|
{ opacity: '1' }
|
||||||
|
], {
|
||||||
|
duration: 500,
|
||||||
|
easing: 'ease-out',
|
||||||
|
fill: 'both'
|
||||||
|
});
|
||||||
|
|
||||||
if (animateContainer) {
|
if (animateContainer) {
|
||||||
containerAnimation.play();
|
containerAnimation.play();
|
||||||
|
clientAnimation.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
displayClientInfo(currentGameState.client.name, currentGameState.client.userType);
|
displayClientInfo(currentGameState.client.name, currentGameState.client.userType);
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
margin: 0 auto 0.25em auto;
|
margin: 0 auto 0.25em auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.moderator {
|
||||||
|
border: 2px solid #c58f13;
|
||||||
|
}
|
||||||
|
|
||||||
.potential-moderator {
|
.potential-moderator {
|
||||||
margin: 0.5em auto;
|
margin: 0.5em auto;
|
||||||
}
|
}
|
||||||
@@ -952,3 +956,18 @@ canvas {
|
|||||||
transform: translateY(0px);
|
transform: translateY(0px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in-slide-down {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20px);
|
||||||
|
}
|
||||||
|
5% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const router = express.Router();
|
|||||||
const debugMode = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())).includes('debug');
|
const debugMode = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())).includes('debug');
|
||||||
const logger = require('../modules/Logger')(debugMode);
|
const logger = require('../modules/Logger')(debugMode);
|
||||||
const socketManager = (require('../modules/singletons/SocketManager.js')).instance;
|
const socketManager = (require('../modules/singletons/SocketManager.js')).instance;
|
||||||
const gameManager = (require('../modules/singletons/GameManager.js')).instance;
|
const activeGameRunner = (require('../modules/singletons/ActiveGameRunner.js')).instance;
|
||||||
const globals = require('../config/globals.js');
|
const globals = require('../config/globals.js');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
|
|
||||||
@@ -22,8 +22,8 @@ router.post('/sockets/broadcast', function (req, res) {
|
|||||||
|
|
||||||
router.get('/games/state', async (req, res) => {
|
router.get('/games/state', async (req, res) => {
|
||||||
const gamesArray = [];
|
const gamesArray = [];
|
||||||
await this.client.hGetAll('activeGames').then(async (r) => {
|
await activeGameRunner.client.keys('*').then(async (r) => {
|
||||||
Object.values(r).forEach((v) => gamesArray.push(v));
|
Object.values(r).forEach((v) => gamesArray.push(JSON.parse(v)));
|
||||||
});
|
});
|
||||||
res.status(200).send(gamesArray);
|
res.status(200).send(gamesArray);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ router.patch('/:code/players', async function (req, res) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.patch('/:code/restart', function (req, res) {
|
router.patch('/:code/restart', async function (req, res) {
|
||||||
if (
|
if (
|
||||||
req.body === null
|
req.body === null
|
||||||
|| !validateAccessCode(req.body.accessCode)
|
|| !validateAccessCode(req.body.accessCode)
|
||||||
@@ -101,7 +101,7 @@ router.patch('/:code/restart', function (req, res) {
|
|||||||
) {
|
) {
|
||||||
res.status(400).send();
|
res.status(400).send();
|
||||||
} else {
|
} else {
|
||||||
const game = gameManager.activeGameRunner.getActiveGame(req.body.accessCode);
|
const game = await gameManager.activeGameRunner.getActiveGame(req.body.accessCode);
|
||||||
if (game) {
|
if (game) {
|
||||||
gameManager.restartGame(game, gameManager.namespace).then((data) => {
|
gameManager.restartGame(game, gameManager.namespace).then((data) => {
|
||||||
res.status(200).send();
|
res.status(200).send();
|
||||||
@@ -123,11 +123,11 @@ function validateName (name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validateCookie (cookie) {
|
function validateCookie (cookie) {
|
||||||
return cookie === null || cookie === false || (typeof cookie === 'string' && cookie.length === globals.USER_SIGNATURE_LENGTH);
|
return cookie === null || cookie === false || (typeof cookie === 'string' && cookie.length === globals.INSTANCE_ID_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateAccessCode (accessCode) {
|
function validateAccessCode (accessCode) {
|
||||||
return /^[a-zA-Z0-9]+$/.test(accessCode) && accessCode.length === globals.ACCESS_CODE_LENGTH;
|
return /^[a-zA-Z0-9]+$/.test(accessCode) && accessCode?.length === globals.ACCESS_CODE_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateSpectatorFlag (spectatorFlag) {
|
function validateSpectatorFlag (spectatorFlag) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const globals = {
|
|||||||
EVIL: 'evil'
|
EVIL: 'evil'
|
||||||
},
|
},
|
||||||
REDIS_CHANNELS: {
|
REDIS_CHANNELS: {
|
||||||
ACTIVE_GAME_STREAM: 'active_game_stream'
|
ACTIVE_GAME_STREAM: 'active_game_stream'
|
||||||
},
|
},
|
||||||
CORS: process.env.NODE_ENV?.trim() === 'development'
|
CORS: process.env.NODE_ENV?.trim() === 'development'
|
||||||
? {
|
? {
|
||||||
@@ -30,7 +30,7 @@ const globals = {
|
|||||||
res.status(400).send('Request has invalid content type.');
|
res.status(400).send('Request has invalid content type.');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
STALE_GAME_HOURS: 24,
|
STALE_GAME_SECONDS: 86400,
|
||||||
SOCKET_EVENTS: {
|
SOCKET_EVENTS: {
|
||||||
IN_GAME_MESSAGE: 'inGameMessage'
|
IN_GAME_MESSAGE: 'inGameMessage'
|
||||||
},
|
},
|
||||||
@@ -49,8 +49,10 @@ const globals = {
|
|||||||
RESTART_GAME: 'restartGame',
|
RESTART_GAME: 'restartGame',
|
||||||
PLAYER_JOINED: 'playerJoined',
|
PLAYER_JOINED: 'playerJoined',
|
||||||
UPDATE_SPECTATORS: 'updateSpectators',
|
UPDATE_SPECTATORS: 'updateSpectators',
|
||||||
|
ADD_SPECTATOR: 'addSpectator',
|
||||||
SYNC_GAME_STATE: 'syncGameState',
|
SYNC_GAME_STATE: 'syncGameState',
|
||||||
UPDATE_SOCKET: 'updateSocket'
|
UPDATE_SOCKET: 'updateSocket',
|
||||||
|
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod'
|
||||||
},
|
},
|
||||||
SYNCABLE_EVENTS: function () {
|
SYNCABLE_EVENTS: function () {
|
||||||
return [
|
return [
|
||||||
@@ -65,10 +67,13 @@ const globals = {
|
|||||||
this.EVENT_IDS.END_GAME,
|
this.EVENT_IDS.END_GAME,
|
||||||
this.EVENT_IDS.RESTART_GAME,
|
this.EVENT_IDS.RESTART_GAME,
|
||||||
this.EVENT_IDS.PLAYER_JOINED,
|
this.EVENT_IDS.PLAYER_JOINED,
|
||||||
this.EVENT_IDS.UPDATE_SPECTATORS,
|
this.EVENT_IDS.ADD_SPECTATOR,
|
||||||
|
this.EVENT_IDS.REMOVE_SPECTATOR,
|
||||||
this.EVENT_IDS.SYNC_GAME_STATE,
|
this.EVENT_IDS.SYNC_GAME_STATE,
|
||||||
this.EVENT_IDS.UPDATE_SOCKET
|
this.EVENT_IDS.UPDATE_SOCKET,
|
||||||
]
|
this.EVENT_IDS.FETCH_GAME_STATE,
|
||||||
|
this.EVENT_IDS.ASSIGN_DEDICATED_MOD
|
||||||
|
];
|
||||||
},
|
},
|
||||||
MESSAGES: {
|
MESSAGES: {
|
||||||
ENTER_NAME: 'Client must enter name.'
|
ENTER_NAME: 'Client must enter name.'
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class Game {
|
|||||||
people,
|
people,
|
||||||
deck,
|
deck,
|
||||||
hasTimer,
|
hasTimer,
|
||||||
moderator,
|
currentModeratorId,
|
||||||
hasDedicatedModerator,
|
hasDedicatedModerator,
|
||||||
originalModeratorId,
|
originalModeratorId,
|
||||||
createTime,
|
createTime,
|
||||||
@@ -13,7 +13,7 @@ class Game {
|
|||||||
) {
|
) {
|
||||||
this.accessCode = accessCode;
|
this.accessCode = accessCode;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.moderator = moderator;
|
this.currentModeratorId = currentModeratorId;
|
||||||
this.people = people;
|
this.people = people;
|
||||||
this.deck = deck;
|
this.deck = deck;
|
||||||
this.gameSize = deck.reduce(
|
this.gameSize = deck.reduce(
|
||||||
@@ -23,11 +23,11 @@ class Game {
|
|||||||
this.hasTimer = hasTimer;
|
this.hasTimer = hasTimer;
|
||||||
this.hasDedicatedModerator = hasDedicatedModerator;
|
this.hasDedicatedModerator = hasDedicatedModerator;
|
||||||
this.originalModeratorId = originalModeratorId;
|
this.originalModeratorId = originalModeratorId;
|
||||||
|
this.previousModeratorId = null;
|
||||||
this.createTime = createTime;
|
this.createTime = createTime;
|
||||||
this.timerParams = timerParams;
|
this.timerParams = timerParams;
|
||||||
this.isFull = this.gameSize === 1 && !this.hasDedicatedModerator;
|
this.isFull = this.gameSize === 1 && !this.hasDedicatedModerator;
|
||||||
this.timeRemaining = null;
|
this.timeRemaining = null;
|
||||||
this.spectators = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// noinspection DuplicatedCode
|
// noinspection DuplicatedCode
|
||||||
|
const globals = require('../config/globals');
|
||||||
|
|
||||||
class Person {
|
class Person {
|
||||||
constructor (id, cookie, name, userType, gameRole = null, gameRoleDescription = null, alignment = null, assigned = false) {
|
constructor (id, cookie, name, userType, gameRole = null, gameRoleDescription = null, alignment = null, assigned = false) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@@ -10,7 +12,8 @@ class Person {
|
|||||||
this.gameRoleDescription = gameRoleDescription;
|
this.gameRoleDescription = gameRoleDescription;
|
||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
this.assigned = assigned;
|
this.assigned = assigned;
|
||||||
this.out = false;
|
this.out = userType === globals.USER_TYPES.MODERATOR || userType === globals.USER_TYPES.SPECTATOR;
|
||||||
|
this.killed = false;
|
||||||
this.revealed = false;
|
this.revealed = false;
|
||||||
this.hasEnteredName = false;
|
this.hasEnteredName = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,242 @@
|
|||||||
const globals = require('../config/globals');
|
const globals = require('../config/globals');
|
||||||
const GameStateCurator = require("./GameStateCurator");
|
const GameStateCurator = require('./GameStateCurator');
|
||||||
const EVENT_IDS = globals.EVENT_IDS;
|
const EVENT_IDS = globals.EVENT_IDS;
|
||||||
|
|
||||||
const Events = [
|
const Events = [
|
||||||
{
|
{
|
||||||
id: EVENT_IDS.PLAYER_JOINED,
|
id: EVENT_IDS.PLAYER_JOINED,
|
||||||
stateChange: (game, args, gameManager) => {
|
stateChange: (game, socketArgs, vars) => {
|
||||||
let toBeAssignedIndex = game.people.findIndex(
|
const toBeAssignedIndex = game.people.findIndex(
|
||||||
(person) => person.id === args.id && person.assigned === false
|
(person) => person.id === socketArgs.id && person.assigned === false
|
||||||
);
|
);
|
||||||
if (toBeAssignedIndex >= 0) {
|
if (toBeAssignedIndex >= 0) {
|
||||||
game.people[toBeAssignedIndex] = args;
|
game.people[toBeAssignedIndex] = socketArgs;
|
||||||
game.isFull = gameManager.isGameFull(game);
|
game.isFull = vars.gameManager.isGameFull(game);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
communicate: (game, args, gameManager) => {
|
communicate: (game, socketArgs, vars) => {
|
||||||
gameManager.namespace.in(game.accessCode).emit(
|
vars.gameManager.namespace.in(game.accessCode).emit(
|
||||||
globals.EVENTS.PLAYER_JOINED,
|
globals.EVENTS.PLAYER_JOINED,
|
||||||
GameStateCurator.mapPerson(args),
|
GameStateCurator.mapPerson(socketArgs),
|
||||||
game.isFull
|
game.isFull
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EVENT_IDS.UPDATE_SPECTATORS,
|
id: EVENT_IDS.ADD_SPECTATOR,
|
||||||
stateChange: (game, args, gameManager) => {
|
stateChange: (game, socketArgs, vars) => {
|
||||||
game.spectators = args;
|
game.people.push(socketArgs);
|
||||||
},
|
},
|
||||||
communicate: (game, args, gameManager) => {
|
communicate: (game, socketArgs, vars) => {
|
||||||
gameManager.namespace.in(game.accessCode).emit(
|
vars.gameManager.namespace.in(game.accessCode).emit(
|
||||||
globals.EVENTS.UPDATE_SPECTATORS,
|
globals.EVENT_IDS.ADD_SPECTATOR,
|
||||||
game.spectators.map((spectator) => { return GameStateCurator.mapPerson(spectator); })
|
GameStateCurator.mapPerson(socketArgs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.REMOVE_SPECTATOR,
|
||||||
|
stateChange: (game, socketArgs, vars) => {
|
||||||
|
const spectatorIndex = game.people.findIndex(person => person.userType === globals.USER_TYPES.SPECTATOR && person.id === socketArgs.personId);
|
||||||
|
if (spectatorIndex >= 0) {
|
||||||
|
game.people.splice(spectatorIndex, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
vars.gameManager.namespace.in(game.accessCode).emit(
|
||||||
|
globals.EVENT_IDS.REMOVE_SPECTATOR,
|
||||||
|
GameStateCurator.mapPerson(socketArgs)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: EVENT_IDS.FETCH_GAME_STATE,
|
id: EVENT_IDS.FETCH_GAME_STATE,
|
||||||
stateChange: (game, args, gameManager) => {
|
stateChange: (game, socketArgs, vars) => {
|
||||||
const matchingPerson = gameManager.findPersonByField(game, 'cookie', args.personId);
|
const matchingPerson = vars.gameManager.findPersonByField(game, 'cookie', socketArgs.personId);
|
||||||
if (matchingPerson) {
|
if (matchingPerson && matchingPerson.socketId !== vars.socketId) {
|
||||||
if (matchingPerson.socketId === socketId) {
|
matchingPerson.socketId = vars.socketId;
|
||||||
logger.debug('matching person found with an established connection to the room: ' + matchingPerson.name);
|
vars.gameManager.namespace.sockets.get(vars.socketId)?.join(game.accessCode);
|
||||||
if (ackFn) {
|
}
|
||||||
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson));
|
},
|
||||||
}
|
communicate: (game, socketArgs, vars) => {
|
||||||
} else {
|
if (!vars.ackFn) return;
|
||||||
logger.debug('matching person found with a new connection to the room: ' + matchingPerson.name);
|
const matchingPerson = vars.gameManager.findPersonByField(game, 'cookie', socketArgs.personId);
|
||||||
this.namespace.sockets.get(socketId).join(accessCode);
|
if (matchingPerson && vars.gameManager.namespace.sockets.get(matchingPerson.socketId)) {
|
||||||
matchingPerson.socketId = socketId;
|
vars.ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson));
|
||||||
await this.publisher.publish(
|
|
||||||
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
|
||||||
game.accessCode + ';' + globals.EVENT_IDS.UPDATE_SOCKET + ';' + JSON.stringify({ personId: matchingPerson.id, socketId: socketId }) + ';' + this.instanceId
|
|
||||||
);
|
|
||||||
if (ackFn) {
|
|
||||||
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (ackFn) {
|
vars.ackFn(null);
|
||||||
rejectClientRequestForGameState(ackFn);
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// id: EVENT_IDS.UPDATE_SOCKET,
|
||||||
|
// stateChange: (game, socketArgs, vars) => {
|
||||||
|
// const matchingPerson = vars.gameManager.findPersonByField(game, 'id', socketArgs.personId);
|
||||||
|
// if (matchingPerson) {
|
||||||
|
// matchingPerson.socketId = socketArgs.socketId;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.SYNC_GAME_STATE,
|
||||||
|
stateChange: (game, socketArgs, vars) => {},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
const matchingPerson = vars.gameManager.findPersonByField(game, 'id', socketArgs.personId);
|
||||||
|
if (matchingPerson && vars.gameManager.namespace.sockets.get(matchingPerson.socketId)) {
|
||||||
|
vars.gameManager.namespace.to(matchingPerson.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.START_GAME,
|
||||||
|
stateChange: (game, socketArgs, vars) => {
|
||||||
|
if (game.isFull) {
|
||||||
|
game.status = globals.STATUS.IN_PROGRESS;
|
||||||
|
if (game.hasTimer) {
|
||||||
|
game.timerParams.paused = true;
|
||||||
|
// this.activeGameRunner.runGame(game, namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
if (vars.ackFn) {
|
||||||
|
vars.ackFn();
|
||||||
|
}
|
||||||
|
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.START_GAME);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.KILL_PLAYER,
|
||||||
|
stateChange: (game, socketArgs, vars) => {
|
||||||
|
const person = game.people.find((person) => person.id === socketArgs.personId);
|
||||||
|
if (person && !person.out) {
|
||||||
|
person.userType = globals.USER_TYPES.KILLED_PLAYER;
|
||||||
|
person.out = true;
|
||||||
|
person.killed = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
const person = game.people.find((person) => person.id === socketArgs.personId);
|
||||||
|
if (person) {
|
||||||
|
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, person.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.REVEAL_PLAYER,
|
||||||
|
stateChange: (game, socketArgs, vars) => {
|
||||||
|
const person = game.people.find((person) => person.id === socketArgs.personId);
|
||||||
|
if (person && !person.revealed) {
|
||||||
|
person.revealed = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
const person = game.people.find((person) => person.id === socketArgs.personId);
|
||||||
|
if (person) {
|
||||||
|
vars.gameManager.namespace.in(game.accessCode).emit(
|
||||||
|
globals.EVENT_IDS.REVEAL_PLAYER,
|
||||||
|
{
|
||||||
|
id: person.id,
|
||||||
|
gameRole: person.gameRole,
|
||||||
|
alignment: person.alignment
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.END_GAME,
|
||||||
|
stateChange: (game, socketArgs, vars) => {
|
||||||
|
game.status = globals.STATUS.ENDED;
|
||||||
|
// if (this.activeGameRunner.timerThreads[game.accessCode]) {
|
||||||
|
// this.logger.trace('KILLING TIMER PROCESS FOR ENDED GAME ' + game.accessCode);
|
||||||
|
// this.activeGameRunner.timerThreads[game.accessCode].kill();
|
||||||
|
// }
|
||||||
|
for (const person of game.people) {
|
||||||
|
person.revealed = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
vars.gameManager.namespace.in(game.accessCode)
|
||||||
|
.emit(globals.EVENT_IDS.END_GAME, GameStateCurator.mapPeopleForModerator(game.people));
|
||||||
|
if (vars.ackFn) {
|
||||||
|
vars.ackFn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.TRANSFER_MODERATOR,
|
||||||
|
stateChange: (game, socketArgs, vars) => {
|
||||||
|
const currentModerator = vars.gameManager.findPersonByField(game, 'id', game.currentModeratorId);
|
||||||
|
const toTransferTo = vars.gameManager.findPersonByField(game, 'id', socketArgs.personId);
|
||||||
|
if (currentModerator) {
|
||||||
|
if (currentModerator.gameRole) {
|
||||||
|
currentModerator.userType = globals.USER_TYPES.KILLED_PLAYER;
|
||||||
|
} else {
|
||||||
|
currentModerator.userType = globals.USER_TYPES.SPECTATOR;
|
||||||
|
}
|
||||||
|
game.previousModeratorId = currentModerator.id;
|
||||||
|
}
|
||||||
|
if (toTransferTo) {
|
||||||
|
toTransferTo.userType = globals.USER_TYPES.MODERATOR;
|
||||||
|
game.currentModeratorId = toTransferTo.id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
const moderator = vars.gameManager.findPersonByField(game, 'id', game.currentModeratorId);
|
||||||
|
const previousModerator = vars.gameManager.findPersonByField(game, 'id', game.previousModeratorId);
|
||||||
|
if (moderator && vars.gameManager.namespace.sockets.get(moderator.socketId)) {
|
||||||
|
vars.gameManager.namespace.to(moderator.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
|
||||||
|
}
|
||||||
|
if (previousModerator && vars.gameManager.namespace.sockets.get(previousModerator.socketId)) {
|
||||||
|
vars.gameManager.namespace.to(previousModerator.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
|
||||||
|
}
|
||||||
|
vars.gameManager.namespace.to(game.accessCode).emit(globals.EVENT_IDS.UPDATE_SPECTATORS, game.people
|
||||||
|
.filter(p => p.userType === globals.USER_TYPES.SPECTATOR)
|
||||||
|
.map(spectator => GameStateCurator.mapPerson(spectator))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.ASSIGN_DEDICATED_MOD,
|
||||||
|
stateChange: (game, socketArgs, vars) => {
|
||||||
|
const currentModerator = vars.gameManager.findPersonByField(game, 'id', game.currentModeratorId);
|
||||||
|
const toTransferTo = vars.gameManager.findPersonByField(game, 'id', socketArgs.personId);
|
||||||
|
if (currentModerator && toTransferTo) {
|
||||||
|
if (currentModerator.id !== toTransferTo.id) {
|
||||||
|
currentModerator.userType = globals.USER_TYPES.PLAYER;
|
||||||
|
}
|
||||||
|
|
||||||
|
toTransferTo.userType = globals.USER_TYPES.MODERATOR;
|
||||||
|
toTransferTo.out = true;
|
||||||
|
toTransferTo.killed = true;
|
||||||
|
game.previousModeratorId = currentModerator.id;
|
||||||
|
game.currentModeratorId = toTransferTo.id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
const moderator = vars.gameManager.findPersonByField(game, 'id', game.currentModeratorId);
|
||||||
|
const moderatorSocket = vars.gameManager.namespace.sockets.get(moderator?.socketId);
|
||||||
|
if (moderator && moderatorSocket) {
|
||||||
|
vars.gameManager.namespace.to(moderator.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
|
||||||
|
moderatorSocket.to(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, game.previousModeratorId);
|
||||||
|
} else {
|
||||||
|
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, game.currentModeratorId);
|
||||||
|
}
|
||||||
|
const previousModerator = vars.gameManager.findPersonByField(game, 'id', game.previousModeratorId);
|
||||||
|
if (previousModerator && previousModerator.id !== moderator.id && vars.gameManager.namespace.sockets.get(previousModerator.socketId)) {
|
||||||
|
vars.gameManager.namespace.to(previousModerator.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: EVENT_IDS.RESTART_GAME,
|
||||||
|
stateChange: (game, socketArgs, vars) => {},
|
||||||
|
communicate: (game, socketArgs, vars) => {
|
||||||
|
if (vars.ackFn) {
|
||||||
|
vars.ackFn();
|
||||||
|
}
|
||||||
|
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.RESTART_GAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const GameStateCurator = {
|
|||||||
mapPeopleForModerator: (people) => {
|
mapPeopleForModerator: (people) => {
|
||||||
return people
|
return people
|
||||||
.filter((person) => {
|
.filter((person) => {
|
||||||
return person.assigned === true;
|
return person.assigned === true || (person.userType === globals.USER_TYPES.SPECTATOR || person.userType === globals.USER_TYPES.MODERATOR);
|
||||||
})
|
})
|
||||||
.map((person) => ({
|
.map((person) => ({
|
||||||
name: person.name,
|
name: person.name,
|
||||||
@@ -22,6 +22,7 @@ const GameStateCurator = {
|
|||||||
gameRoleDescription: person.gameRoleDescription,
|
gameRoleDescription: person.gameRoleDescription,
|
||||||
alignment: person.alignment,
|
alignment: person.alignment,
|
||||||
out: person.out,
|
out: person.out,
|
||||||
|
killed: person.killed,
|
||||||
revealed: person.revealed
|
revealed: person.revealed
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
@@ -32,12 +33,13 @@ const GameStateCurator = {
|
|||||||
id: person.id,
|
id: person.id,
|
||||||
userType: person.userType,
|
userType: person.userType,
|
||||||
out: person.out,
|
out: person.out,
|
||||||
|
killed: person.killed,
|
||||||
revealed: person.revealed,
|
revealed: person.revealed,
|
||||||
gameRole: person.gameRole,
|
gameRole: person.gameRole,
|
||||||
alignment: person.alignment
|
alignment: person.alignment
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return { name: person.name, id: person.id, userType: person.userType, out: person.out, revealed: person.revealed };
|
return { name: person.name, id: person.id, userType: person.userType, out: person.out, killed: person.killed, revealed: person.revealed };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -55,23 +57,21 @@ function getGameStateBasedOnPermissions (game, person) {
|
|||||||
gameRoleDescription: person.gameRoleDescription,
|
gameRoleDescription: person.gameRoleDescription,
|
||||||
customRole: person.customRole,
|
customRole: person.customRole,
|
||||||
alignment: person.alignment,
|
alignment: person.alignment,
|
||||||
out: person.out
|
out: person.out,
|
||||||
|
killed: person.killed
|
||||||
};
|
};
|
||||||
switch (person.userType) {
|
switch (person.userType) {
|
||||||
case globals.USER_TYPES.MODERATOR:
|
case globals.USER_TYPES.MODERATOR:
|
||||||
return {
|
return {
|
||||||
accessCode: game.accessCode,
|
accessCode: game.accessCode,
|
||||||
status: game.status,
|
status: game.status,
|
||||||
moderator: GameStateCurator.mapPerson(game.moderator),
|
currentModeratorId: game.currentModeratorId,
|
||||||
client: client,
|
client: client,
|
||||||
deck: game.deck,
|
deck: game.deck,
|
||||||
gameSize: game.gameSize,
|
gameSize: game.gameSize,
|
||||||
people: GameStateCurator.mapPeopleForModerator(game.people, client),
|
people: GameStateCurator.mapPeopleForModerator(game.people, client),
|
||||||
timerParams: game.timerParams,
|
timerParams: game.timerParams,
|
||||||
isFull: game.isFull,
|
isFull: game.isFull
|
||||||
spectators: game.spectators.map((filteredPerson) =>
|
|
||||||
GameStateCurator.mapPerson(filteredPerson)
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
case globals.USER_TYPES.TEMPORARY_MODERATOR:
|
case globals.USER_TYPES.TEMPORARY_MODERATOR:
|
||||||
case globals.USER_TYPES.SPECTATOR:
|
case globals.USER_TYPES.SPECTATOR:
|
||||||
@@ -80,20 +80,17 @@ function getGameStateBasedOnPermissions (game, person) {
|
|||||||
return {
|
return {
|
||||||
accessCode: game.accessCode,
|
accessCode: game.accessCode,
|
||||||
status: game.status,
|
status: game.status,
|
||||||
moderator: GameStateCurator.mapPerson(game.moderator),
|
currentModeratorId: game.currentModeratorId,
|
||||||
client: client,
|
client: client,
|
||||||
deck: game.deck,
|
deck: game.deck,
|
||||||
gameSize: game.gameSize,
|
gameSize: game.gameSize,
|
||||||
people: game.people
|
people: game.people
|
||||||
.filter((person) => {
|
.filter((person) => {
|
||||||
return person.assigned === true;
|
return person.assigned === true || person.userType === globals.USER_TYPES.SPECTATOR;
|
||||||
})
|
})
|
||||||
.map((filteredPerson) => GameStateCurator.mapPerson(filteredPerson)),
|
.map((filteredPerson) => GameStateCurator.mapPerson(filteredPerson)),
|
||||||
timerParams: game.timerParams,
|
timerParams: game.timerParams,
|
||||||
isFull: game.isFull,
|
isFull: game.isFull
|
||||||
spectators: game.spectators.map((filteredPerson) =>
|
|
||||||
GameStateCurator.mapPerson(filteredPerson)
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ class ActiveGameRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getActiveGame = async (accessCode) => {
|
getActiveGame = async (accessCode) => {
|
||||||
const r = await this.client.hGet('activeGames', accessCode);
|
const r = await this.client.get(accessCode);
|
||||||
return JSON.parse(r);
|
return r === null ? r : JSON.parse(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
createGameSyncSubscriber = async (gameManager, socketManager) => {
|
createGameSyncSubscriber = async (gameManager, socketManager) => {
|
||||||
@@ -28,7 +28,7 @@ class ActiveGameRunner {
|
|||||||
await this.subscriber.connect();
|
await this.subscriber.connect();
|
||||||
await this.subscriber.subscribe(globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM, async (message) => {
|
await this.subscriber.subscribe(globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM, async (message) => {
|
||||||
this.logger.info('MESSAGE: ' + message);
|
this.logger.info('MESSAGE: ' + message);
|
||||||
let messageComponents = message.split(';');
|
const messageComponents = message.split(';');
|
||||||
if (messageComponents[messageComponents.length - 1] === this.instanceId) {
|
if (messageComponents[messageComponents.length - 1] === this.instanceId) {
|
||||||
this.logger.trace('Disregarding self-authored message');
|
this.logger.trace('Disregarding self-authored message');
|
||||||
return;
|
return;
|
||||||
@@ -44,10 +44,10 @@ class ActiveGameRunner {
|
|||||||
game,
|
game,
|
||||||
null,
|
null,
|
||||||
game?.accessCode || messageComponents[0],
|
game?.accessCode || messageComponents[0],
|
||||||
args ? args : null,
|
args || null,
|
||||||
null,
|
null,
|
||||||
true
|
true
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.logger.info('ACTIVE GAME RUNNER - CREATED GAME SYNC SUBSCRIBER');
|
this.logger.info('ACTIVE GAME RUNNER - CREATED GAME SYNC SUBSCRIBER');
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const UsernameGenerator = require('../UsernameGenerator');
|
|||||||
const GameCreationRequest = require('../../model/GameCreationRequest');
|
const GameCreationRequest = require('../../model/GameCreationRequest');
|
||||||
const redis = require('redis');
|
const redis = require('redis');
|
||||||
|
|
||||||
|
|
||||||
class GameManager {
|
class GameManager {
|
||||||
constructor (logger, environment, instanceId) {
|
constructor (logger, environment, instanceId) {
|
||||||
if (GameManager.instance) {
|
if (GameManager.instance) {
|
||||||
@@ -34,8 +33,8 @@ class GameManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
refreshGame = async (game) => {
|
refreshGame = async (game) => {
|
||||||
this.logger.debug('PUSHING REFRESH OF ' + game.accessCode);
|
this.logger.debug('PUSHING REFRESH OF ' + game.accessCode);
|
||||||
await this.activeGameRunner.client.hSet('activeGames', game.accessCode, JSON.stringify(game));
|
await this.activeGameRunner.client.set(game.accessCode, JSON.stringify(game));
|
||||||
}
|
}
|
||||||
|
|
||||||
createGame = async (gameParams) => {
|
createGame = async (gameParams) => {
|
||||||
@@ -48,12 +47,12 @@ class GameManager {
|
|||||||
gameParams.moderatorName,
|
gameParams.moderatorName,
|
||||||
gameParams.hasDedicatedModerator
|
gameParams.hasDedicatedModerator
|
||||||
);
|
);
|
||||||
//await this.pruneStaleGames();
|
|
||||||
const newAccessCode = await this.generateAccessCode(globals.ACCESS_CODE_CHAR_POOL);
|
const newAccessCode = await this.generateAccessCode(globals.ACCESS_CODE_CHAR_POOL);
|
||||||
if (newAccessCode === null) {
|
if (newAccessCode === null) {
|
||||||
return Promise.reject(globals.ERROR_MESSAGE.NO_UNIQUE_ACCESS_CODE);
|
return Promise.reject(globals.ERROR_MESSAGE.NO_UNIQUE_ACCESS_CODE);
|
||||||
}
|
}
|
||||||
const moderator = initializeModerator(req.moderatorName, req.hasDedicatedModerator);
|
const moderator = initializeModerator(req.moderatorName, req.hasDedicatedModerator);
|
||||||
|
console.log(moderator);
|
||||||
moderator.assigned = true;
|
moderator.assigned = true;
|
||||||
if (req.timerParams !== null) {
|
if (req.timerParams !== null) {
|
||||||
req.timerParams.paused = false;
|
req.timerParams.paused = false;
|
||||||
@@ -64,13 +63,15 @@ class GameManager {
|
|||||||
initializePeopleForGame(req.deck, moderator, this.shuffle),
|
initializePeopleForGame(req.deck, moderator, this.shuffle),
|
||||||
req.deck,
|
req.deck,
|
||||||
req.hasTimer,
|
req.hasTimer,
|
||||||
moderator,
|
moderator.id,
|
||||||
req.hasDedicatedModerator,
|
req.hasDedicatedModerator,
|
||||||
moderator.id,
|
moderator.id,
|
||||||
new Date().toJSON(),
|
new Date().toJSON(),
|
||||||
req.timerParams
|
req.timerParams
|
||||||
);
|
);
|
||||||
await this.activeGameRunner.client.hSet('activeGames', newAccessCode, JSON.stringify(newGame));
|
await this.activeGameRunner.client.set(newAccessCode, JSON.stringify(newGame), {
|
||||||
|
EX: globals.STALE_GAME_SECONDS
|
||||||
|
});
|
||||||
return Promise.resolve({ accessCode: newAccessCode, cookie: moderator.cookie, environment: this.environment });
|
return Promise.resolve({ accessCode: newAccessCode, cookie: moderator.cookie, environment: this.environment });
|
||||||
}).catch((message) => {
|
}).catch((message) => {
|
||||||
console.log(message);
|
console.log(message);
|
||||||
@@ -79,17 +80,6 @@ class GameManager {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
startGame = async (game, namespace) => {
|
|
||||||
if (game.isFull) {
|
|
||||||
game.status = globals.STATUS.IN_PROGRESS;
|
|
||||||
if (game.hasTimer) {
|
|
||||||
game.timerParams.paused = true;
|
|
||||||
this.activeGameRunner.runGame(game, namespace);
|
|
||||||
}
|
|
||||||
namespace.in(game.accessCode).emit(globals.EVENT_IDS.START_GAME);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pauseTimer = async (game, logger) => {
|
pauseTimer = async (game, logger) => {
|
||||||
const thread = this.activeGameRunner.timerThreads[game.accessCode];
|
const thread = this.activeGameRunner.timerThreads[game.accessCode];
|
||||||
if (thread && !thread.killed) {
|
if (thread && !thread.killed) {
|
||||||
@@ -132,34 +122,6 @@ class GameManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
revealPlayer = async (game, personId) => {
|
|
||||||
const person = game.people.find((person) => person.id === personId);
|
|
||||||
if (person && !person.revealed) {
|
|
||||||
this.logger.debug('game ' + game.accessCode + ': revealing player ' + person.name);
|
|
||||||
person.revealed = true;
|
|
||||||
this.namespace.in(game.accessCode).emit(
|
|
||||||
globals.EVENT_IDS.REVEAL_PLAYER,
|
|
||||||
{
|
|
||||||
id: person.id,
|
|
||||||
gameRole: person.gameRole,
|
|
||||||
alignment: person.alignment
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
endGame = async (game) => {
|
|
||||||
game.status = globals.STATUS.ENDED;
|
|
||||||
if (this.activeGameRunner.timerThreads[game.accessCode]) {
|
|
||||||
this.logger.trace('KILLING TIMER PROCESS FOR ENDED GAME ' + game.accessCode);
|
|
||||||
this.activeGameRunner.timerThreads[game.accessCode].kill();
|
|
||||||
}
|
|
||||||
for (const person of game.people) {
|
|
||||||
person.revealed = true;
|
|
||||||
}
|
|
||||||
this.namespace.in(game.accessCode).emit(globals.EVENT_IDS.END_GAME, GameStateCurator.mapPeopleForModerator(game.people));
|
|
||||||
};
|
|
||||||
|
|
||||||
checkAvailability = async (code) => {
|
checkAvailability = async (code) => {
|
||||||
const game = await this.activeGameRunner.getActiveGame(code.toUpperCase().trim());
|
const game = await this.activeGameRunner.getActiveGame(code.toUpperCase().trim());
|
||||||
if (game) {
|
if (game) {
|
||||||
@@ -173,7 +135,7 @@ class GameManager {
|
|||||||
const charCount = charPool.length;
|
const charCount = charPool.length;
|
||||||
let codeDigits, accessCode;
|
let codeDigits, accessCode;
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
while (!accessCode || ((await this.activeGameRunner.client.hKeys('activeGames')).includes(accessCode)
|
while (!accessCode || ((await this.activeGameRunner.client.keys('*')).includes(accessCode)
|
||||||
&& attempts < globals.ACCESS_CODE_GENERATION_ATTEMPTS)) {
|
&& attempts < globals.ACCESS_CODE_GENERATION_ATTEMPTS)) {
|
||||||
codeDigits = [];
|
codeDigits = [];
|
||||||
let iterations = globals.ACCESS_CODE_LENGTH;
|
let iterations = globals.ACCESS_CODE_LENGTH;
|
||||||
@@ -184,76 +146,11 @@ class GameManager {
|
|||||||
accessCode = codeDigits.join('');
|
accessCode = codeDigits.join('');
|
||||||
attempts ++;
|
attempts ++;
|
||||||
}
|
}
|
||||||
return (await this.activeGameRunner.client.hKeys('activeGames')).includes(accessCode)
|
return (await this.activeGameRunner.client.keys('*')).includes(accessCode)
|
||||||
? null
|
? null
|
||||||
: accessCode;
|
: accessCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
transferModeratorPowers = async (socketId, game, person, namespace, logger) => {
|
|
||||||
if (person && (person.out || person.userType === globals.USER_TYPES.SPECTATOR)) {
|
|
||||||
let spectatorsUpdated = false;
|
|
||||||
if (game.spectators.includes(person)) {
|
|
||||||
game.spectators.splice(game.spectators.indexOf(person), 1);
|
|
||||||
spectatorsUpdated = true;
|
|
||||||
}
|
|
||||||
logger.debug('game ' + game.accessCode + ': transferring mod powers to ' + person.name);
|
|
||||||
if (game.moderator === person) {
|
|
||||||
person.userType = globals.USER_TYPES.MODERATOR;
|
|
||||||
const socket = this.namespace.sockets.get(socketId);
|
|
||||||
if (socket) {
|
|
||||||
this.namespace.to(socketId).emit(globals.EVENTS.SYNC_GAME_STATE); // they are guaranteed to be connected to this instance.
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const oldModerator = game.moderator;
|
|
||||||
if (game.moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
|
||||||
game.moderator.userType = globals.USER_TYPES.PLAYER;
|
|
||||||
} else if (game.moderator.gameRole) { // the current moderator was at one point a dealt-in player.
|
|
||||||
game.moderator.userType = globals.USER_TYPES.KILLED_PLAYER; // restore their state from before being made mod.
|
|
||||||
} else if (game.moderator.userType === globals.USER_TYPES.MODERATOR) {
|
|
||||||
game.moderator.userType = globals.USER_TYPES.SPECTATOR;
|
|
||||||
game.spectators.push(game.moderator);
|
|
||||||
spectatorsUpdated = true;
|
|
||||||
}
|
|
||||||
person.userType = globals.USER_TYPES.MODERATOR;
|
|
||||||
game.moderator = person;
|
|
||||||
if (spectatorsUpdated === true) {
|
|
||||||
namespace.in(game.accessCode).emit(
|
|
||||||
globals.EVENTS.UPDATE_SPECTATORS,
|
|
||||||
game.spectators.map((spectator) => GameStateCurator.mapPerson(spectator))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await notifyPlayerInvolvedInModTransfer(game, this.namespace, person);
|
|
||||||
await notifyPlayerInvolvedInModTransfer(game, this.namespace, oldModerator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
killPlayer = async (socketId, game, person, namespace, logger) => {
|
|
||||||
if (person && !person.out) {
|
|
||||||
logger.debug('game ' + game.accessCode + ': killing player ' + person.name);
|
|
||||||
if (person.userType !== globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
|
||||||
person.userType = globals.USER_TYPES.KILLED_PLAYER;
|
|
||||||
}
|
|
||||||
person.out = true;
|
|
||||||
const socket = namespace.sockets.get(socketId);
|
|
||||||
if (socket && game.moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
|
||||||
socket.to(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, person.id);
|
|
||||||
} else {
|
|
||||||
namespace.in(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, person.id);
|
|
||||||
}
|
|
||||||
// temporary moderators will transfer their powers automatically to the first person they kill.
|
|
||||||
if (game.moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
|
||||||
await this.socketManager.handleAndSyncEvent(
|
|
||||||
globals.EVENT_IDS.TRANSFER_MODERATOR,
|
|
||||||
game,
|
|
||||||
socket,
|
|
||||||
{ personId: person.id },
|
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
joinGame = async (game, name, cookie, joinAsSpectator) => {
|
joinGame = async (game, name, cookie, joinAsSpectator) => {
|
||||||
const matchingPerson = this.findPersonByField(game, 'cookie', cookie);
|
const matchingPerson = this.findPersonByField(game, 'cookie', cookie);
|
||||||
if (matchingPerson) {
|
if (matchingPerson) {
|
||||||
@@ -262,14 +159,16 @@ class GameManager {
|
|||||||
if (isNameTaken(game, name)) {
|
if (isNameTaken(game, name)) {
|
||||||
return Promise.reject({ status: 400, reason: 'This name is taken.' });
|
return Promise.reject({ status: 400, reason: 'This name is taken.' });
|
||||||
}
|
}
|
||||||
if (joinAsSpectator && game.spectators.length === globals.MAX_SPECTATORS) {
|
if (joinAsSpectator
|
||||||
|
&& game.people.filter(person => person.userType === globals.USER_TYPES.SPECTATOR).length === globals.MAX_SPECTATORS
|
||||||
|
) {
|
||||||
return Promise.reject({ status: 400, reason: 'There are too many people already spectating.' });
|
return Promise.reject({ status: 400, reason: 'There are too many people already spectating.' });
|
||||||
} else if (joinAsSpectator) {
|
} else if (joinAsSpectator) {
|
||||||
return await addSpectator(game, name, this.logger, this.namespace, this.publisher, this.instanceId, this.refreshGame);
|
return await addSpectator(game, name, this.logger, this.namespace, this.publisher, this.instanceId, this.refreshGame);
|
||||||
}
|
}
|
||||||
const unassignedPerson = game.moderator.assigned === false
|
const unassignedPerson = this.findPersonByField(game, 'id', game.currentModeratorId).assigned === false
|
||||||
? game.moderator
|
? this.findPersonByField(game, 'id', game.currentModeratorId)
|
||||||
: game.people.find((person) => person.assigned === false);
|
: game.people.find((person) => person.assigned === false && person.userType === globals.USER_TYPES.PLAYER);
|
||||||
if (unassignedPerson) {
|
if (unassignedPerson) {
|
||||||
this.logger.trace('request from client to join game. Assigning: ' + unassignedPerson.name);
|
this.logger.trace('request from client to join game. Assigning: ' + unassignedPerson.name);
|
||||||
unassignedPerson.assigned = true;
|
unassignedPerson.assigned = true;
|
||||||
@@ -287,7 +186,7 @@ class GameManager {
|
|||||||
);
|
);
|
||||||
return Promise.resolve(unassignedPerson.cookie);
|
return Promise.resolve(unassignedPerson.cookie);
|
||||||
} else {
|
} else {
|
||||||
if (game.spectators.length === globals.MAX_SPECTATORS) {
|
if (game.people.filter(person => person.userType === globals.USER_TYPES.SPECTATOR).length === globals.MAX_SPECTATORS) {
|
||||||
return Promise.reject({ status: 400, reason: 'This game has reached the maximum number of players and spectators.' });
|
return Promise.reject({ status: 400, reason: 'This game has reached the maximum number of players and spectators.' });
|
||||||
}
|
}
|
||||||
return await addSpectator(game, name, this.logger, this.namespace, this.publisher, this.instanceId, this.refreshGame);
|
return await addSpectator(game, name, this.logger, this.namespace, this.publisher, this.instanceId, this.refreshGame);
|
||||||
@@ -296,15 +195,15 @@ class GameManager {
|
|||||||
|
|
||||||
restartGame = async (game, namespace) => {
|
restartGame = async (game, namespace) => {
|
||||||
// kill any outstanding timer threads
|
// kill any outstanding timer threads
|
||||||
const subProcess = this.activeGameRunner.timerThreads[game.accessCode];
|
// const subProcess = this.activeGameRunner.timerThreads[game.accessCode];
|
||||||
if (subProcess) {
|
// if (subProcess) {
|
||||||
if (!subProcess.killed) {
|
// if (!subProcess.killed) {
|
||||||
this.logger.info('Killing timer process ' + subProcess.pid + ' for: ' + game.accessCode);
|
// this.logger.info('Killing timer process ' + subProcess.pid + ' for: ' + game.accessCode);
|
||||||
this.activeGameRunner.timerThreads[game.accessCode].kill();
|
// this.activeGameRunner.timerThreads[game.accessCode].kill();
|
||||||
}
|
// }
|
||||||
this.logger.debug('Deleting reference to subprocess ' + subProcess.pid);
|
// this.logger.debug('Deleting reference to subprocess ' + subProcess.pid);
|
||||||
delete this.activeGameRunner.timerThreads[game.accessCode];
|
// delete this.activeGameRunner.timerThreads[game.accessCode];
|
||||||
}
|
// }
|
||||||
|
|
||||||
// re-shuffle the deck
|
// re-shuffle the deck
|
||||||
const cards = [];
|
const cards = [];
|
||||||
@@ -318,23 +217,21 @@ class GameManager {
|
|||||||
|
|
||||||
// make sure no players are marked as out or revealed, and give them new cards.
|
// make sure no players are marked as out or revealed, and give them new cards.
|
||||||
for (let i = 0; i < game.people.length; i ++) {
|
for (let i = 0; i < game.people.length; i ++) {
|
||||||
if (game.people[i].out) {
|
|
||||||
game.people[i].out = false;
|
|
||||||
}
|
|
||||||
if (game.people[i].userType === globals.USER_TYPES.KILLED_PLAYER) {
|
if (game.people[i].userType === globals.USER_TYPES.KILLED_PLAYER) {
|
||||||
game.people[i].userType = globals.USER_TYPES.PLAYER;
|
game.people[i].userType = globals.USER_TYPES.PLAYER;
|
||||||
|
game.people[i].out = false;
|
||||||
}
|
}
|
||||||
game.people[i].revealed = false;
|
game.people[i].revealed = false;
|
||||||
game.people[i].gameRole = cards[i].role;
|
game.people[i].killed = false;
|
||||||
game.people[i].gameRoleDescription = cards[i].description;
|
if (game.people[i].gameRole) {
|
||||||
game.people[i].alignment = cards[i].team;
|
game.people[i].gameRole = cards[i].role;
|
||||||
}
|
game.people[i].gameRoleDescription = cards[i].description;
|
||||||
|
game.people[i].alignment = cards[i].team;
|
||||||
/* If there is currently a dedicated mod, and that person was once a player (i.e. they have a game role), make
|
if (game.people[i].id === game.currentModeratorId && game.people[i].userType === globals.USER_TYPES.MODERATOR) {
|
||||||
them a temporary mod for the restarted game.
|
game.people[i].userType = globals.USER_TYPES.TEMPORARY_MODERATOR;
|
||||||
*/
|
game.people[i].out = false;
|
||||||
if (game.moderator.gameRole && game.moderator.userType === globals.USER_TYPES.MODERATOR) {
|
}
|
||||||
game.moderator.userType = globals.USER_TYPES.TEMPORARY_MODERATOR;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the new game
|
// start the new game
|
||||||
@@ -345,36 +242,13 @@ class GameManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.refreshGame(game);
|
await this.refreshGame(game);
|
||||||
|
await this.publisher?.publish(
|
||||||
|
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
||||||
|
game.accessCode + ';' + globals.EVENT_IDS.RESTART_GAME + ';' + JSON.stringify({}) + ';' + this.instanceId
|
||||||
|
);
|
||||||
namespace.in(game.accessCode).emit(globals.EVENT_IDS.RESTART_GAME);
|
namespace.in(game.accessCode).emit(globals.EVENT_IDS.RESTART_GAME);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleRequestForGameState = async (game, namespace, logger, gameRunner, accessCode, personCookie, ackFn, socketId) => {
|
|
||||||
const matchingPerson = this.findPersonByField(game, 'cookie', personCookie);
|
|
||||||
if (matchingPerson) {
|
|
||||||
if (matchingPerson.socketId === socketId) {
|
|
||||||
logger.debug('matching person found with an established connection to the room: ' + matchingPerson.name);
|
|
||||||
if (ackFn) {
|
|
||||||
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.debug('matching person found with a new connection to the room: ' + matchingPerson.name);
|
|
||||||
this.namespace.sockets.get(socketId).join(accessCode);
|
|
||||||
matchingPerson.socketId = socketId;
|
|
||||||
await this.publisher.publish(
|
|
||||||
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
|
||||||
game.accessCode + ';' + globals.EVENT_IDS.UPDATE_SOCKET + ';' + JSON.stringify({ personId: matchingPerson.id, socketId: socketId }) + ';' + this.instanceId
|
|
||||||
);
|
|
||||||
if (ackFn) {
|
|
||||||
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ackFn) {
|
|
||||||
rejectClientRequestForGameState(ackFn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
-- To shuffle an array a of n elements (indices 0..n-1):
|
-- To shuffle an array a of n elements (indices 0..n-1):
|
||||||
for i from n−1 downto 1 do
|
for i from n−1 downto 1 do
|
||||||
@@ -392,39 +266,12 @@ class GameManager {
|
|||||||
return array;
|
return array;
|
||||||
};
|
};
|
||||||
|
|
||||||
// pruneStaleGames = async () => {
|
|
||||||
// this.activeGameRunner.activeGames.forEach((key, value) => {
|
|
||||||
// if (value.createTime) {
|
|
||||||
// const createDate = new Date(value.createTime);
|
|
||||||
// if (createDate.setHours(createDate.getHours() + globals.STALE_GAME_HOURS) < Date.now()) {
|
|
||||||
// this.logger.info('PRUNING STALE GAME ' + key);
|
|
||||||
// this.activeGameRunner.activeGames.delete(key);
|
|
||||||
// if (this.activeGameRunner.timerThreads[key]) {
|
|
||||||
// this.logger.info('KILLING STALE TIMER PROCESS FOR ' + key);
|
|
||||||
// this.activeGameRunner.timerThreads[key].kill();
|
|
||||||
// delete this.activeGameRunner.timerThreads[key];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
||||||
isGameFull = (game) => {
|
isGameFull = (game) => {
|
||||||
return game.moderator.assigned === true && !game.people.find((person) => person.assigned === false);
|
return !game.people.find((person) => person.userType === globals.USER_TYPES.PLAYER && person.assigned === false);
|
||||||
}
|
}
|
||||||
|
|
||||||
findPersonByField = (game, fieldName, value) => {
|
findPersonByField = (game, fieldName, value) => {
|
||||||
let person;
|
return game.people.find(person => person[fieldName] === value);
|
||||||
if (value === game.moderator[fieldName]) {
|
|
||||||
person = game.moderator;
|
|
||||||
}
|
|
||||||
if (!person) {
|
|
||||||
person = game.people.find((person) => person[fieldName] === value);
|
|
||||||
}
|
|
||||||
if (!person) {
|
|
||||||
person = game.spectators.find((spectator) => spectator[fieldName] === value);
|
|
||||||
}
|
|
||||||
return person;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,30 +286,23 @@ function initializeModerator (name, hasDedicatedModerator) {
|
|||||||
return new Person(createRandomId(), createRandomId(), name, userType);
|
return new Person(createRandomId(), createRandomId(), name, userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializePeopleForGame (uniqueCards, moderator, shuffle) {
|
function initializePeopleForGame (uniqueRoles, moderator, shuffle) {
|
||||||
const people = [];
|
const people = [];
|
||||||
|
|
||||||
const cards = [];
|
const cards = [];
|
||||||
let numberOfRoles = 0;
|
for (const role of uniqueRoles) {
|
||||||
for (const card of uniqueCards) {
|
for (let i = 0; i < role.quantity; i ++) {
|
||||||
for (let i = 0; i < card.quantity; i ++) {
|
cards.push(role);
|
||||||
cards.push(card);
|
|
||||||
numberOfRoles ++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shuffle(cards); // this shuffles in-place.
|
shuffle(cards); // this shuffles in-place.
|
||||||
|
|
||||||
let j = 0;
|
let j = 0;
|
||||||
if (moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) { // temporary moderators should be dealt in.
|
const number = moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
moderator.gameRole = cards[j].role;
|
? cards.length - 1
|
||||||
moderator.customRole = cards[j].custom;
|
: cards.length;
|
||||||
moderator.gameRoleDescription = cards[j].description;
|
while (j < number) {
|
||||||
moderator.alignment = cards[j].team;
|
|
||||||
people.push(moderator);
|
|
||||||
j ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (j < numberOfRoles) {
|
|
||||||
const person = new Person(
|
const person = new Person(
|
||||||
createRandomId(),
|
createRandomId(),
|
||||||
createRandomId(),
|
createRandomId(),
|
||||||
@@ -478,30 +318,29 @@ function initializePeopleForGame (uniqueCards, moderator, shuffle) {
|
|||||||
j ++;
|
j ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||||
|
moderator.gameRole = cards[cards.length - 1].role;
|
||||||
|
moderator.customRole = cards[cards.length - 1].custom;
|
||||||
|
moderator.gameRoleDescription = cards[cards.length - 1].description;
|
||||||
|
moderator.alignment = cards[cards.length - 1].team;
|
||||||
|
}
|
||||||
|
|
||||||
|
people.push(moderator);
|
||||||
|
|
||||||
return people;
|
return people;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRandomId () {
|
function createRandomId () {
|
||||||
let id = '';
|
let id = '';
|
||||||
for (let i = 0; i < globals.USER_SIGNATURE_LENGTH; i ++) {
|
for (let i = 0; i < globals.INSTANCE_ID_LENGTH; i ++) {
|
||||||
id += globals.ACCESS_CODE_CHAR_POOL[Math.floor(Math.random() * globals.ACCESS_CODE_CHAR_POOL.length)];
|
id += globals.INSTANCE_ID_CHAR_POOL[Math.floor(Math.random() * globals.INSTANCE_ID_CHAR_POOL.length)];
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rejectClientRequestForGameState (acknowledgementFunction) {
|
|
||||||
return acknowledgementFunction(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findPlayerBySocketId (people, socketId) {
|
|
||||||
return people.find((person) => person.socketId === socketId && person.userType === globals.USER_TYPES.PLAYER);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNameTaken (game, name) {
|
function isNameTaken (game, name) {
|
||||||
const processedName = name.toLowerCase().trim();
|
const processedName = name.toLowerCase().trim();
|
||||||
return (game.people.find((person) => person.name.toLowerCase().trim() === processedName))
|
return game.people.find((person) => person.name.toLowerCase().trim() === processedName);
|
||||||
|| (game.moderator.name.toLowerCase().trim() === processedName)
|
|
||||||
|| (game.spectators.find((spectator) => spectator.name.toLowerCase().trim() === processedName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGameSize (cards) {
|
function getGameSize (cards) {
|
||||||
@@ -513,12 +352,6 @@ function getGameSize (cards) {
|
|||||||
return quantity;
|
return quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function notifyPlayerInvolvedInModTransfer(game, namespace, person) {
|
|
||||||
if (namespace.sockets.get(person.socketId)) {
|
|
||||||
namespace.to(person.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addSpectator (game, name, logger, namespace, publisher, instanceId, refreshGame) {
|
async function addSpectator (game, name, logger, namespace, publisher, instanceId, refreshGame) {
|
||||||
const spectator = new Person(
|
const spectator = new Person(
|
||||||
createRandomId(),
|
createRandomId(),
|
||||||
@@ -527,15 +360,15 @@ async function addSpectator (game, name, logger, namespace, publisher, instanceI
|
|||||||
globals.USER_TYPES.SPECTATOR
|
globals.USER_TYPES.SPECTATOR
|
||||||
);
|
);
|
||||||
logger.trace('new spectator: ' + spectator.name);
|
logger.trace('new spectator: ' + spectator.name);
|
||||||
game.spectators.push(spectator);
|
game.people.push(spectator);
|
||||||
await refreshGame(game);
|
await refreshGame(game);
|
||||||
namespace.in(game.accessCode).emit(
|
namespace.in(game.accessCode).emit(
|
||||||
globals.EVENTS.UPDATE_SPECTATORS,
|
globals.EVENT_IDS.ADD_SPECTATOR,
|
||||||
game.spectators.map((spectator) => { return GameStateCurator.mapPerson(spectator); })
|
GameStateCurator.mapPerson(spectator)
|
||||||
);
|
);
|
||||||
await publisher.publish(
|
await publisher.publish(
|
||||||
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
||||||
game.accessCode + ';' + globals.EVENT_IDS.UPDATE_SPECTATORS + ';' + JSON.stringify(game.spectators) + ';' + instanceId
|
game.accessCode + ';' + globals.EVENT_IDS.ADD_SPECTATOR + ';' + JSON.stringify(GameStateCurator.mapPerson(spectator)) + ';' + instanceId
|
||||||
);
|
);
|
||||||
return Promise.resolve(spectator.cookie);
|
return Promise.resolve(spectator.cookie);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ const globals = require('../../config/globals');
|
|||||||
const EVENT_IDS = globals.EVENT_IDS;
|
const EVENT_IDS = globals.EVENT_IDS;
|
||||||
const { RateLimiterMemory } = require('rate-limiter-flexible');
|
const { RateLimiterMemory } = require('rate-limiter-flexible');
|
||||||
const redis = require('redis');
|
const redis = require('redis');
|
||||||
const GameStateCurator = require("../GameStateCurator");
|
const Events = require('../Events');
|
||||||
const Events = require("../Events");
|
|
||||||
|
|
||||||
class SocketManager {
|
class SocketManager {
|
||||||
constructor (logger, instanceId) {
|
constructor (logger, instanceId) {
|
||||||
@@ -73,58 +72,33 @@ class SocketManager {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleAndSyncEvent = async (eventId, game, socket, args, ackFn) => {
|
handleAndSyncEvent = async (eventId, game, socket, socketArgs, ackFn) => {
|
||||||
await this.handleEventById(eventId, game, socket?.id, game.accessCode, args, ackFn, false);
|
await this.handleEventById(eventId, game, socket?.id, game.accessCode, socketArgs, ackFn, false);
|
||||||
/* This server should publish events initiated by a connected socket to Redis for consumption by other instances. */
|
/* This server should publish events initiated by a connected socket to Redis for consumption by other instances. */
|
||||||
if (globals.SYNCABLE_EVENTS().includes(eventId)) {
|
if (globals.SYNCABLE_EVENTS().includes(eventId)) {
|
||||||
await this.gameManager.refreshGame(game);
|
await this.gameManager.refreshGame(game);
|
||||||
this.publisher?.publish(
|
await this.publisher?.publish(
|
||||||
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
||||||
game.accessCode + ';' + eventId + ';' + JSON.stringify(args) + ';' + this.instanceId
|
game.accessCode + ';' + eventId + ';' + JSON.stringify(socketArgs) + ';' + this.instanceId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEventById = async (eventId, game, socketId, accessCode, args, ackFn, syncOnly) => {
|
handleEventById = async (eventId, game, socketId, accessCode, socketArgs, ackFn, syncOnly) => {
|
||||||
this.logger.trace('ARGS TO HANDLER: ' + JSON.stringify(args));
|
this.logger.trace('ARGS TO HANDLER: ' + JSON.stringify(socketArgs));
|
||||||
const event = Events.find((event) => event.id === eventId);
|
const event = Events.find((event) => event.id === eventId);
|
||||||
|
const additionalVars = {
|
||||||
|
gameManager: this.gameManager,
|
||||||
|
socketId: socketId,
|
||||||
|
ackFn: ackFn
|
||||||
|
};
|
||||||
if (event) {
|
if (event) {
|
||||||
if (!syncOnly) {
|
if (!syncOnly) {
|
||||||
event.stateChange(game, args, this.gameManager);
|
event.stateChange(game, socketArgs, additionalVars);
|
||||||
}
|
}
|
||||||
event.communicate(game, args, this.gameManager);
|
event.communicate(game, socketArgs, additionalVars);
|
||||||
}
|
}
|
||||||
switch (eventId) {
|
switch (eventId) {
|
||||||
case EVENT_IDS.FETCH_GAME_STATE:
|
|
||||||
await this.gameManager.handleRequestForGameState(
|
|
||||||
game,
|
|
||||||
this.namespace,
|
|
||||||
this.logger,
|
|
||||||
this.activeGameRunner,
|
|
||||||
accessCode,
|
|
||||||
args.personId,
|
|
||||||
ackFn,
|
|
||||||
socketId
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case EVENT_IDS.UPDATE_SOCKET:
|
|
||||||
const matchingPerson = this.gameManager.findPersonByField(game, 'id', args.personId);
|
|
||||||
if (matchingPerson) {
|
|
||||||
matchingPerson.socketId = args.socketId;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_IDS.SYNC_GAME_STATE:
|
|
||||||
const personToSync = this.gameManager.findPersonByField(game, 'id', args.personId);
|
|
||||||
if (personToSync) {
|
|
||||||
this.gameManager.namespace.to(personToSync.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_IDS.START_GAME:
|
|
||||||
await this.gameManager.startGame(game, this.gameManager.namespace);
|
|
||||||
if (ackFn) {
|
|
||||||
ackFn();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_IDS.PAUSE_TIMER:
|
case EVENT_IDS.PAUSE_TIMER:
|
||||||
await this.gameManager.pauseTimer(game, this.logger);
|
await this.gameManager.pauseTimer(game, this.logger);
|
||||||
break;
|
break;
|
||||||
@@ -134,27 +108,6 @@ class SocketManager {
|
|||||||
case EVENT_IDS.GET_TIME_REMAINING:
|
case EVENT_IDS.GET_TIME_REMAINING:
|
||||||
await this.gameManager.getTimeRemaining(game, socketId);
|
await this.gameManager.getTimeRemaining(game, socketId);
|
||||||
break;
|
break;
|
||||||
case EVENT_IDS.KILL_PLAYER:
|
|
||||||
await this.gameManager.killPlayer(socketId, game, game.people.find((person) => person.id === args.personId), this.gameManager.namespace, this.logger);
|
|
||||||
break;
|
|
||||||
case EVENT_IDS.REVEAL_PLAYER:
|
|
||||||
await this.gameManager.revealPlayer(game, args.personId);
|
|
||||||
break;
|
|
||||||
case EVENT_IDS.TRANSFER_MODERATOR:
|
|
||||||
await this.gameManager.transferModeratorPowers(
|
|
||||||
socketId,
|
|
||||||
game,
|
|
||||||
this.gameManager?.findPersonByField(game, 'id', args.personId),
|
|
||||||
this.gameManager.namespace,
|
|
||||||
this.logger
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case EVENT_IDS.END_GAME:
|
|
||||||
await this.gameManager.endGame(game);
|
|
||||||
if (ackFn) {
|
|
||||||
ackFn();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user