mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 07:47:50 +01:00
playing and pausing the timer
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
.idea
|
.idea
|
||||||
node_modules/*
|
node_modules/*
|
||||||
./client/certs/
|
client/certs/
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ export const globals = {
|
|||||||
COMMANDS: {
|
COMMANDS: {
|
||||||
FETCH_GAME_STATE: 'fetchGameState',
|
FETCH_GAME_STATE: 'fetchGameState',
|
||||||
GET_ENVIRONMENT: 'getEnvironment',
|
GET_ENVIRONMENT: 'getEnvironment',
|
||||||
START_GAME: 'startGame'
|
START_GAME: 'startGame',
|
||||||
|
PAUSE_TIMER: 'pauseTimer',
|
||||||
|
RESUME_TIMER: 'resumeTimer'
|
||||||
},
|
},
|
||||||
STATUS: {
|
STATUS: {
|
||||||
LOBBY: "lobby",
|
LOBBY: "lobby",
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ export class GameStateRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderGameHeader() {
|
renderGameHeader() {
|
||||||
let title = document.createElement("h1");
|
// let title = document.createElement("h1");
|
||||||
title.innerText = "Game";
|
// title.innerText = "Game";
|
||||||
document.querySelector('#game-title h1')?.remove();
|
// document.querySelector('#game-title h1')?.remove();
|
||||||
document.getElementById("game-title").appendChild(title);
|
// document.getElementById("game-title").appendChild(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPlayerRole() {
|
renderPlayerRole() {
|
||||||
@@ -99,6 +99,10 @@ export class GameStateRenderer {
|
|||||||
document.getElementById("game-role").style.display = 'none';
|
document.getElementById("game-role").style.display = 'none';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderModeratorView() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderClient(client, container) {
|
function renderClient(client, container) {
|
||||||
|
|||||||
@@ -45,5 +45,24 @@ export const templates = {
|
|||||||
"<div id='game-role-back'>" +
|
"<div id='game-role-back'>" +
|
||||||
"<h4>Click to reveal your role</h4>" +
|
"<h4>Click to reveal your role</h4>" +
|
||||||
"<p>(click again to hide)</p>" +
|
"<p>(click again to hide)</p>" +
|
||||||
"</div>"
|
"</div>",
|
||||||
|
MODERATOR_GAME_VIEW:
|
||||||
|
"<div id='person-name'></div>" +
|
||||||
|
"<h2 class='user-type user-type-moderator'>Moderator</h2>" +
|
||||||
|
"<div id='game-header'>" +
|
||||||
|
"<div class='timer-container-moderator'>" +
|
||||||
|
"<label for='game-timer'>Time Remaining</label>" +
|
||||||
|
"<div id='game-timer'></div>" +
|
||||||
|
"</div>" +
|
||||||
|
"<div id='play-pause'>" +
|
||||||
|
"<button id='pause-button'>Pause</button>" +
|
||||||
|
"<button id='play-button'>Play</button>" +
|
||||||
|
"</div>" +
|
||||||
|
"<div>" +
|
||||||
|
"<label for='alive-count'>Players Left</label>" +
|
||||||
|
"<div id='alive-count'></div>" +
|
||||||
|
"</div>" +
|
||||||
|
"</div>" +
|
||||||
|
"<div id='player-list-moderator'></div>" +
|
||||||
|
"<button id='end-game-button'>End Game</button>"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,13 +27,12 @@ function prepareGamePage(environment, socket, reconnect=false) {
|
|||||||
} else {
|
} else {
|
||||||
toast('You are connected.', 'success', true);
|
toast('You are connected.', 'success', true);
|
||||||
console.log(gameState);
|
console.log(gameState);
|
||||||
gameState.accessCode = accessCode;
|
|
||||||
userId = gameState.client.id;
|
userId = gameState.client.id;
|
||||||
UserUtility.setAnonymousUserId(userId, environment);
|
UserUtility.setAnonymousUserId(userId, environment);
|
||||||
let gameStateRenderer = new GameStateRenderer(gameState);
|
let gameStateRenderer = new GameStateRenderer(gameState);
|
||||||
const timerWorker = new Worker('../modules/Timer.js');
|
const timerWorker = new Worker('../modules/Timer.js');
|
||||||
setClientSocketHandlers(gameStateRenderer, socket, timerWorker);
|
setClientSocketHandlers(gameStateRenderer, socket, timerWorker);
|
||||||
processGameState(gameState, userId, socket, gameStateRenderer, timerWorker, reconnect); // this socket is initialized via a script tag in the game page HTML.
|
processGameState(gameState, userId, socket, gameStateRenderer, timerWorker);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -54,15 +53,28 @@ function processGameState (gameState, userId, socket, gameStateRenderer, timerWo
|
|||||||
|| gameState.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
|| gameState.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
displayStartGamePromptForModerators(gameStateRenderer);
|
displayStartGamePromptForModerators(gameStateRenderer, socket);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case globals.STATUS.IN_PROGRESS:
|
case globals.STATUS.IN_PROGRESS:
|
||||||
document.querySelector("#start-game-prompt")?.remove();
|
document.querySelector("#start-game-prompt")?.remove();
|
||||||
gameStateRenderer.gameState = gameState;
|
gameStateRenderer.gameState = gameState;
|
||||||
document.getElementById("game-state-container").innerHTML = templates.GAME;
|
|
||||||
gameStateRenderer.renderGameHeader();
|
gameStateRenderer.renderGameHeader();
|
||||||
gameStateRenderer.renderPlayerRole();
|
if (gameState.userType === globals.USER_TYPES.PLAYER || gameState.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||||
|
document.getElementById("game-state-container").innerHTML = templates.GAME;
|
||||||
|
gameStateRenderer.renderPlayerRole();
|
||||||
|
} else if (gameState.userType === globals.USER_TYPES.MODERATOR) {
|
||||||
|
document.getElementById("game-state-container").innerHTML = templates.MODERATOR_GAME_VIEW;
|
||||||
|
gameStateRenderer.renderModeratorView();
|
||||||
|
console.log(gameState);
|
||||||
|
console.log(gameState.accessCode);
|
||||||
|
document.getElementById("pause-button").addEventListener('click', () => {
|
||||||
|
socket.emit(globals.COMMANDS.PAUSE_TIMER, gameState.accessCode);
|
||||||
|
});
|
||||||
|
document.getElementById("play-button").addEventListener('click', () => {
|
||||||
|
socket.emit(globals.COMMANDS.RESUME_TIMER, gameState.accessCode);
|
||||||
|
})
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -110,6 +122,18 @@ function setClientSocketHandlers(gameStateRenderer, socket, timerWorker) {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!socket.hasListeners(globals.COMMANDS.PAUSE_TIMER)) {
|
||||||
|
socket.on(globals.COMMANDS.PAUSE_TIMER, (timeRemaining) => {
|
||||||
|
console.log(timeRemaining);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!socket.hasListeners(globals.COMMANDS.RESUME_TIMER)) {
|
||||||
|
socket.on(globals.COMMANDS.RESUME_TIMER, (timeRemaining) => {
|
||||||
|
console.log(timeRemaining);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayStartGamePromptForModerators(gameStateRenderer, socket) {
|
function displayStartGamePromptForModerators(gameStateRenderer, socket) {
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ const globals = {
|
|||||||
CLIENT_COMMANDS: {
|
CLIENT_COMMANDS: {
|
||||||
FETCH_GAME_STATE: 'fetchGameState',
|
FETCH_GAME_STATE: 'fetchGameState',
|
||||||
GET_ENVIRONMENT: 'getEnvironment',
|
GET_ENVIRONMENT: 'getEnvironment',
|
||||||
START_GAME: 'startGame'
|
START_GAME: 'startGame',
|
||||||
|
PAUSE_TIMER: 'pauseTimer',
|
||||||
|
RESUME_TIMER: 'resumeTimer'
|
||||||
},
|
},
|
||||||
STATUS: {
|
STATUS: {
|
||||||
LOBBY: "lobby",
|
LOBBY: "lobby",
|
||||||
@@ -39,7 +41,9 @@ const globals = {
|
|||||||
GAME_PROCESS_COMMANDS: {
|
GAME_PROCESS_COMMANDS: {
|
||||||
END_GAME: "endGame",
|
END_GAME: "endGame",
|
||||||
START_GAME: "startGame",
|
START_GAME: "startGame",
|
||||||
START_TIMER: "startTimer"
|
START_TIMER: "startTimer",
|
||||||
|
PAUSE_TIMER: "pauseTimer",
|
||||||
|
RESUME_TIMER: "resumeTimer"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
class Game {
|
class Game {
|
||||||
constructor(accessCode, status, people, deck, hasTimer, moderator, timerParams=null) {
|
constructor(accessCode, status, people, deck, hasTimer, moderator, timerParams=null) {
|
||||||
this.accessCode = accessCode
|
this.accessCode = accessCode;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.moderator = moderator;
|
this.moderator = moderator;
|
||||||
this.people = people;
|
this.people = people;
|
||||||
@@ -8,6 +8,7 @@ class Game {
|
|||||||
this.hasTimer = hasTimer;
|
this.hasTimer = hasTimer;
|
||||||
this.timerParams = timerParams;
|
this.timerParams = timerParams;
|
||||||
this.isFull = false;
|
this.isFull = false;
|
||||||
|
this.timeRemaining = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const globals = require('../config/globals');
|
|||||||
class ActiveGameRunner {
|
class ActiveGameRunner {
|
||||||
constructor (logger) {
|
constructor (logger) {
|
||||||
this.activeGames = {};
|
this.activeGames = {};
|
||||||
|
this.timerThreads = {};
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ class ActiveGameRunner {
|
|||||||
runGame = (game, namespace) => {
|
runGame = (game, namespace) => {
|
||||||
this.logger.debug('running game ' + game.accessCode);
|
this.logger.debug('running game ' + game.accessCode);
|
||||||
const gameProcess = fork(path.join(__dirname, '/GameProcess.js'));
|
const gameProcess = fork(path.join(__dirname, '/GameProcess.js'));
|
||||||
|
this.timerThreads[game.accessCode] = gameProcess;
|
||||||
gameProcess.on('message', (msg) => {
|
gameProcess.on('message', (msg) => {
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case globals.GAME_PROCESS_COMMANDS.END_GAME:
|
case globals.GAME_PROCESS_COMMANDS.END_GAME:
|
||||||
@@ -21,11 +23,26 @@ class ActiveGameRunner {
|
|||||||
this.logger.debug('PARENT: END GAME');
|
this.logger.debug('PARENT: END GAME');
|
||||||
namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.END_GAME, game.accessCode);
|
namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.END_GAME, game.accessCode);
|
||||||
break;
|
break;
|
||||||
|
case globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER:
|
||||||
|
game.timerParams.paused = true;
|
||||||
|
this.logger.trace(msg);
|
||||||
|
game.timeRemaining = msg.timeRemaining;
|
||||||
|
this.logger.debug('PARENT: PAUSE TIMER');
|
||||||
|
namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER, game.timeRemaining);
|
||||||
|
break;
|
||||||
|
case globals.GAME_PROCESS_COMMANDS.RESUME_TIMER:
|
||||||
|
game.timerParams.paused = false;
|
||||||
|
this.logger.trace(msg);
|
||||||
|
game.timeRemaining = msg.timeRemaining;
|
||||||
|
this.logger.debug('PARENT: RESUME TIMER');
|
||||||
|
namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.RESUME_TIMER, game.timeRemaining);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
gameProcess.on('exit', () => {
|
gameProcess.on('exit', () => {
|
||||||
this.logger.debug('Game ' + game.accessCode + ' has ended. Elapsed: ' + (new Date() - game.startTime) + 'ms');
|
this.logger.debug('Game ' + game.accessCode + ' has ended.');
|
||||||
|
delete this.timerThreads[game.accessCode];
|
||||||
});
|
});
|
||||||
gameProcess.send({
|
gameProcess.send({
|
||||||
command: globals.GAME_PROCESS_COMMANDS.START_TIMER,
|
command: globals.GAME_PROCESS_COMMANDS.START_TIMER,
|
||||||
|
|||||||
@@ -43,6 +43,38 @@ class GameManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on(globals.CLIENT_COMMANDS.PAUSE_TIMER, (accessCode) => {
|
||||||
|
this.logger.trace(accessCode);
|
||||||
|
let game = this.activeGameRunner.activeGames[accessCode];
|
||||||
|
if (game) {
|
||||||
|
let thread = this.activeGameRunner.timerThreads[accessCode];
|
||||||
|
if (thread) {
|
||||||
|
this.logger.debug('Timer thread found for game ' + accessCode);
|
||||||
|
thread.send({
|
||||||
|
command: globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER,
|
||||||
|
accessCode: game.accessCode,
|
||||||
|
logLevel: this.logger.logLevel
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on(globals.CLIENT_COMMANDS.RESUME_TIMER, (accessCode) => {
|
||||||
|
this.logger.trace(accessCode);
|
||||||
|
let game = this.activeGameRunner.activeGames[accessCode];
|
||||||
|
if (game) {
|
||||||
|
let thread = this.activeGameRunner.timerThreads[accessCode];
|
||||||
|
if (thread) {
|
||||||
|
this.logger.debug('Timer thread found for game ' + accessCode);
|
||||||
|
thread.send({
|
||||||
|
command: globals.GAME_PROCESS_COMMANDS.RESUME_TIMER,
|
||||||
|
accessCode: game.accessCode,
|
||||||
|
logLevel: this.logger.logLevel
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -54,6 +86,9 @@ class GameManager {
|
|||||||
} else {
|
} else {
|
||||||
const newAccessCode = this.generateAccessCode();
|
const newAccessCode = this.generateAccessCode();
|
||||||
let moderator = initializeModerator(gameParams.moderatorName, gameParams.hasDedicatedModerator);
|
let moderator = initializeModerator(gameParams.moderatorName, gameParams.hasDedicatedModerator);
|
||||||
|
if (gameParams.timerParams !== null) {
|
||||||
|
gameParams.timerParams.paused = false;
|
||||||
|
}
|
||||||
this.activeGameRunner.activeGames[newAccessCode] = new Game(
|
this.activeGameRunner.activeGames[newAccessCode] = new Game(
|
||||||
newAccessCode,
|
newAccessCode,
|
||||||
globals.STATUS.LOBBY,
|
globals.STATUS.LOBBY,
|
||||||
|
|||||||
@@ -1,26 +1,43 @@
|
|||||||
const globals = require('../config/globals.js');
|
const globals = require('../config/globals.js');
|
||||||
const ServerTimer = require('./ServerTimer.js');
|
const ServerTimer = require('./ServerTimer.js');
|
||||||
|
|
||||||
|
let timer;
|
||||||
|
|
||||||
process.on('message', (msg) => {
|
process.on('message', (msg) => {
|
||||||
const logger = require('./Logger')(msg.logLevel);
|
const logger = require('./Logger')(msg.logLevel);
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case globals.GAME_PROCESS_COMMANDS.START_TIMER:
|
case globals.GAME_PROCESS_COMMANDS.START_TIMER:
|
||||||
logger.debug('CHILD PROCESS ' + msg.accessCode + ': START TIMER');
|
logger.debug('CHILD PROCESS ' + msg.accessCode + ': START TIMER');
|
||||||
runGameTimer(msg.hours, msg.minutes, logger).then(() => {
|
timer = new ServerTimer(
|
||||||
|
msg.hours,
|
||||||
|
msg.minutes,
|
||||||
|
globals.CLOCK_TICK_INTERVAL_MILLIS,
|
||||||
|
logger
|
||||||
|
);
|
||||||
|
timer.runTimer().then(() => {
|
||||||
logger.debug('Timer finished for ' + msg.accessCode);
|
logger.debug('Timer finished for ' + msg.accessCode);
|
||||||
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_GAME });
|
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_GAME });
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
case globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER:
|
||||||
|
timer.stopTimer();
|
||||||
|
logger.debug('CHILD PROCESS ' + msg.accessCode + ': PAUSE TIMER');
|
||||||
|
process.send({ command: globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER, timeRemaining: timer.currentTimeInMillis});
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case globals.GAME_PROCESS_COMMANDS.RESUME_TIMER:
|
||||||
|
timer.resumeTimer().then(() => {
|
||||||
|
logger.debug('Timer finished for ' + msg.accessCode);
|
||||||
|
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_GAME });
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
logger.debug('CHILD PROCESS ' + msg.accessCode + ': RESUME TIMER');
|
||||||
|
process.send({ command: globals.GAME_PROCESS_COMMANDS.RESUME_TIMER, timeRemaining: timer.currentTimeInMillis});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function runGameTimer (hours, minutes, logger) {
|
|
||||||
const cycleTimer = new ServerTimer(
|
|
||||||
hours,
|
|
||||||
minutes,
|
|
||||||
globals.CLOCK_TICK_INTERVAL_MILLIS,
|
|
||||||
logger
|
|
||||||
);
|
|
||||||
return cycleTimer.runTimer();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ function getGameStateBasedOnPermissions(game, person) {
|
|||||||
switch (person.userType) {
|
switch (person.userType) {
|
||||||
case globals.USER_TYPES.PLAYER:
|
case globals.USER_TYPES.PLAYER:
|
||||||
return {
|
return {
|
||||||
|
accessCode: game.accessCode,
|
||||||
status: game.status,
|
status: game.status,
|
||||||
moderator: mapPerson(game.moderator),
|
moderator: mapPerson(game.moderator),
|
||||||
userType: globals.USER_TYPES.PLAYER,
|
userType: globals.USER_TYPES.PLAYER,
|
||||||
@@ -30,10 +31,11 @@ function getGameStateBasedOnPermissions(game, person) {
|
|||||||
})
|
})
|
||||||
.map((filteredPerson) => ({ name: filteredPerson.name, userType: filteredPerson.userType })),
|
.map((filteredPerson) => ({ name: filteredPerson.name, userType: filteredPerson.userType })),
|
||||||
timerParams: game.timerParams,
|
timerParams: game.timerParams,
|
||||||
isFull: game.isFull
|
isFull: game.isFull,
|
||||||
}
|
}
|
||||||
case globals.USER_TYPES.MODERATOR:
|
case globals.USER_TYPES.MODERATOR:
|
||||||
return {
|
return {
|
||||||
|
accessCode: game.accessCode,
|
||||||
status: game.status,
|
status: game.status,
|
||||||
moderator: mapPerson(game.moderator),
|
moderator: mapPerson(game.moderator),
|
||||||
userType: globals.USER_TYPES.MODERATOR,
|
userType: globals.USER_TYPES.MODERATOR,
|
||||||
@@ -45,6 +47,7 @@ function getGameStateBasedOnPermissions(game, person) {
|
|||||||
}
|
}
|
||||||
case globals.USER_TYPES.TEMPORARY_MODERATOR:
|
case globals.USER_TYPES.TEMPORARY_MODERATOR:
|
||||||
return {
|
return {
|
||||||
|
accessCode: game.accessCode,
|
||||||
status: game.status,
|
status: game.status,
|
||||||
moderator: mapPerson(game.moderator),
|
moderator: mapPerson(game.moderator),
|
||||||
userType: globals.USER_TYPES.TEMPORARY_MODERATOR,
|
userType: globals.USER_TYPES.TEMPORARY_MODERATOR,
|
||||||
|
|||||||
@@ -1,60 +1,83 @@
|
|||||||
/* ALL TIMES ARE IN MILLIS */
|
|
||||||
|
|
||||||
function stepFn (expected, interval, start, totalTime, ticking, timesUpResolver, logger) {
|
function stepFn (serverTimerInstance, expected) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (now - start >= totalTime) {
|
serverTimerInstance.currentTimeInMillis = serverTimerInstance.totalTime - (now - serverTimerInstance.start);
|
||||||
clearTimeout(ticking);
|
if (now - serverTimerInstance.start >= serverTimerInstance.totalTime) {
|
||||||
logger.debug('ELAPSED: ' + (now - start) + 'ms (~' + (Math.abs(totalTime - (now - start)) / totalTime).toFixed(3) + '% error).');
|
clearTimeout(serverTimerInstance.ticking);
|
||||||
timesUpResolver(); // this is a reference to the callback defined in the construction of the promise in runTimer()
|
serverTimerInstance.logger.debug(
|
||||||
|
'ELAPSED: ' + (now - serverTimerInstance.start) + 'ms (~'
|
||||||
|
+ (Math.abs(serverTimerInstance.totalTime - (now - serverTimerInstance.start)) / serverTimerInstance.totalTime).toFixed(3) + '% error).'
|
||||||
|
);
|
||||||
|
serverTimerInstance.timesUpResolver(); // this is a reference to the callback defined in the construction of the promise in runTimer()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const delta = now - expected;
|
const delta = now - expected;
|
||||||
expected += interval;
|
expected += serverTimerInstance.interval;
|
||||||
ticking = setTimeout(function () {
|
serverTimerInstance.ticking = setTimeout(function () {
|
||||||
stepFn(
|
stepFn(
|
||||||
expected,
|
serverTimerInstance,
|
||||||
interval,
|
expected
|
||||||
start,
|
|
||||||
totalTime,
|
|
||||||
ticking,
|
|
||||||
timesUpResolver,
|
|
||||||
logger
|
|
||||||
);
|
);
|
||||||
}, Math.max(0, interval - delta)); // take into account drift
|
}, Math.max(0, serverTimerInstance.interval - delta)); // take into account drift
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServerTimer {
|
class ServerTimer {
|
||||||
|
|
||||||
constructor (hours, minutes, tickInterval, logger) {
|
constructor (hours, minutes, tickInterval, logger) {
|
||||||
this.hours = hours;
|
this.hours = hours;
|
||||||
this.minutes = minutes;
|
this.minutes = minutes;
|
||||||
this.tickInterval = tickInterval;
|
this.tickInterval = tickInterval;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
this.currentTimeInMillis = null;
|
||||||
|
this.ticking = null;
|
||||||
|
this.timesUpPromise = null;
|
||||||
|
this.timesUpResolver = null;
|
||||||
|
this.start = null;
|
||||||
|
this.totalTime = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
runTimer () {
|
runTimer () {
|
||||||
const interval = this.tickInterval;
|
this.totalTime = convertFromHoursToMilliseconds(this.hours) + convertFromMinutesToMilliseconds(this.minutes);
|
||||||
const totalTime = convertFromHoursToMilliseconds(this.hours) + convertFromMinutesToMilliseconds(this.minutes);
|
this.logger.debug('STARTING TIMER FOR ' + this.totalTime + 'ms');
|
||||||
const logger = this.logger;
|
this.start = Date.now();
|
||||||
logger.debug('STARTING TIMER FOR ' + totalTime + 'ms');
|
|
||||||
const start = Date.now();
|
|
||||||
const expected = Date.now() + this.tickInterval;
|
const expected = Date.now() + this.tickInterval;
|
||||||
let timesUpResolver;
|
this.timesUpPromise = new Promise((resolve) => {
|
||||||
const timesUpPromise = new Promise((resolve) => {
|
this.timesUpResolver = resolve;
|
||||||
timesUpResolver = resolve;
|
|
||||||
});
|
});
|
||||||
const ticking = setTimeout(function () {
|
const instance = this;
|
||||||
|
this.ticking = setTimeout(function () {
|
||||||
stepFn(
|
stepFn(
|
||||||
expected,
|
instance,
|
||||||
interval,
|
expected
|
||||||
start,
|
|
||||||
totalTime,
|
|
||||||
ticking,
|
|
||||||
timesUpResolver,
|
|
||||||
logger
|
|
||||||
);
|
);
|
||||||
}, this.tickInterval);
|
}, this.tickInterval);
|
||||||
|
|
||||||
return timesUpPromise;
|
return this.timesUpPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTimer() {
|
||||||
|
clearTimeout(this.ticking);
|
||||||
|
let now = Date.now();
|
||||||
|
this.logger.debug(
|
||||||
|
'ELAPSED (PAUSE): ' + (now - this.start) + 'ms (~'
|
||||||
|
+ (Math.abs(this.totalTime - (now - this.start)) / this.totalTime).toFixed(3) + '% error).'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
resumeTimer() {
|
||||||
|
this.logger.debug('RESUMING TIMER FOR ' + this.currentTimeInMillis + 'ms');
|
||||||
|
this.start = Date.now();
|
||||||
|
this.totalTime = this.currentTimeInMillis;
|
||||||
|
const expected = Date.now() + this.tickInterval;
|
||||||
|
const instance = this;
|
||||||
|
this.ticking = setTimeout(function () {
|
||||||
|
stepFn(
|
||||||
|
instance,
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
}, this.tickInterval);
|
||||||
|
|
||||||
|
return this.timesUpPromise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user