mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
playing and pausing the timer
This commit is contained in:
@@ -5,6 +5,7 @@ const globals = require('../config/globals');
|
||||
class ActiveGameRunner {
|
||||
constructor (logger) {
|
||||
this.activeGames = {};
|
||||
this.timerThreads = {};
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -14,6 +15,7 @@ class ActiveGameRunner {
|
||||
runGame = (game, namespace) => {
|
||||
this.logger.debug('running game ' + game.accessCode);
|
||||
const gameProcess = fork(path.join(__dirname, '/GameProcess.js'));
|
||||
this.timerThreads[game.accessCode] = gameProcess;
|
||||
gameProcess.on('message', (msg) => {
|
||||
switch (msg.command) {
|
||||
case globals.GAME_PROCESS_COMMANDS.END_GAME:
|
||||
@@ -21,11 +23,26 @@ class ActiveGameRunner {
|
||||
this.logger.debug('PARENT: END GAME');
|
||||
namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.END_GAME, game.accessCode);
|
||||
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', () => {
|
||||
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({
|
||||
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 {
|
||||
const newAccessCode = this.generateAccessCode();
|
||||
let moderator = initializeModerator(gameParams.moderatorName, gameParams.hasDedicatedModerator);
|
||||
if (gameParams.timerParams !== null) {
|
||||
gameParams.timerParams.paused = false;
|
||||
}
|
||||
this.activeGameRunner.activeGames[newAccessCode] = new Game(
|
||||
newAccessCode,
|
||||
globals.STATUS.LOBBY,
|
||||
|
||||
@@ -1,26 +1,43 @@
|
||||
const globals = require('../config/globals.js');
|
||||
const ServerTimer = require('./ServerTimer.js');
|
||||
|
||||
let timer;
|
||||
|
||||
process.on('message', (msg) => {
|
||||
const logger = require('./Logger')(msg.logLevel);
|
||||
switch (msg.command) {
|
||||
case globals.GAME_PROCESS_COMMANDS.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);
|
||||
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_GAME });
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
case globals.USER_TYPES.PLAYER:
|
||||
return {
|
||||
accessCode: game.accessCode,
|
||||
status: game.status,
|
||||
moderator: mapPerson(game.moderator),
|
||||
userType: globals.USER_TYPES.PLAYER,
|
||||
@@ -30,10 +31,11 @@ function getGameStateBasedOnPermissions(game, person) {
|
||||
})
|
||||
.map((filteredPerson) => ({ name: filteredPerson.name, userType: filteredPerson.userType })),
|
||||
timerParams: game.timerParams,
|
||||
isFull: game.isFull
|
||||
isFull: game.isFull,
|
||||
}
|
||||
case globals.USER_TYPES.MODERATOR:
|
||||
return {
|
||||
accessCode: game.accessCode,
|
||||
status: game.status,
|
||||
moderator: mapPerson(game.moderator),
|
||||
userType: globals.USER_TYPES.MODERATOR,
|
||||
@@ -45,6 +47,7 @@ function getGameStateBasedOnPermissions(game, person) {
|
||||
}
|
||||
case globals.USER_TYPES.TEMPORARY_MODERATOR:
|
||||
return {
|
||||
accessCode: game.accessCode,
|
||||
status: game.status,
|
||||
moderator: mapPerson(game.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();
|
||||
if (now - start >= totalTime) {
|
||||
clearTimeout(ticking);
|
||||
logger.debug('ELAPSED: ' + (now - start) + 'ms (~' + (Math.abs(totalTime - (now - start)) / totalTime).toFixed(3) + '% error).');
|
||||
timesUpResolver(); // this is a reference to the callback defined in the construction of the promise in runTimer()
|
||||
serverTimerInstance.currentTimeInMillis = serverTimerInstance.totalTime - (now - serverTimerInstance.start);
|
||||
if (now - serverTimerInstance.start >= serverTimerInstance.totalTime) {
|
||||
clearTimeout(serverTimerInstance.ticking);
|
||||
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;
|
||||
}
|
||||
const delta = now - expected;
|
||||
expected += interval;
|
||||
ticking = setTimeout(function () {
|
||||
expected += serverTimerInstance.interval;
|
||||
serverTimerInstance.ticking = setTimeout(function () {
|
||||
stepFn(
|
||||
expected,
|
||||
interval,
|
||||
start,
|
||||
totalTime,
|
||||
ticking,
|
||||
timesUpResolver,
|
||||
logger
|
||||
serverTimerInstance,
|
||||
expected
|
||||
);
|
||||
}, Math.max(0, interval - delta)); // take into account drift
|
||||
}, Math.max(0, serverTimerInstance.interval - delta)); // take into account drift
|
||||
}
|
||||
|
||||
class ServerTimer {
|
||||
|
||||
constructor (hours, minutes, tickInterval, logger) {
|
||||
this.hours = hours;
|
||||
this.minutes = minutes;
|
||||
this.tickInterval = tickInterval;
|
||||
this.logger = logger;
|
||||
this.currentTimeInMillis = null;
|
||||
this.ticking = null;
|
||||
this.timesUpPromise = null;
|
||||
this.timesUpResolver = null;
|
||||
this.start = null;
|
||||
this.totalTime = null;
|
||||
}
|
||||
|
||||
runTimer () {
|
||||
const interval = this.tickInterval;
|
||||
const totalTime = convertFromHoursToMilliseconds(this.hours) + convertFromMinutesToMilliseconds(this.minutes);
|
||||
const logger = this.logger;
|
||||
logger.debug('STARTING TIMER FOR ' + totalTime + 'ms');
|
||||
const start = Date.now();
|
||||
this.totalTime = convertFromHoursToMilliseconds(this.hours) + convertFromMinutesToMilliseconds(this.minutes);
|
||||
this.logger.debug('STARTING TIMER FOR ' + this.totalTime + 'ms');
|
||||
this.start = Date.now();
|
||||
const expected = Date.now() + this.tickInterval;
|
||||
let timesUpResolver;
|
||||
const timesUpPromise = new Promise((resolve) => {
|
||||
timesUpResolver = resolve;
|
||||
this.timesUpPromise = new Promise((resolve) => {
|
||||
this.timesUpResolver = resolve;
|
||||
});
|
||||
const ticking = setTimeout(function () {
|
||||
const instance = this;
|
||||
this.ticking = setTimeout(function () {
|
||||
stepFn(
|
||||
expected,
|
||||
interval,
|
||||
start,
|
||||
totalTime,
|
||||
ticking,
|
||||
timesUpResolver,
|
||||
logger
|
||||
instance,
|
||||
expected
|
||||
);
|
||||
}, 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