diff --git a/frontend/src/js/fight_scene.ts b/frontend/src/js/fight_scene.ts index 67c0c67ad64daba3002bb36f822c5410a8ed0335..e16f7164d71809e4c47b3013b6a743b139950d4c 100644 --- a/frontend/src/js/fight_scene.ts +++ b/frontend/src/js/fight_scene.ts @@ -18,6 +18,8 @@ interface InputStatus { ended_at: string; typed: string; final: string; + began_at_gmtm: number; + ended_at_gmtm: number; } export default class FightScene extends Phaser.Scene { @@ -30,6 +32,7 @@ export default class FightScene extends Phaser.Scene { score: number; health: number; hud: HUD; + gameTime: Phaser.Time.TimerEvent; constructor() { super("fight"); @@ -83,6 +86,11 @@ export default class FightScene extends Phaser.Scene { } async create() { + this.gameTime = this.time.addEvent({ + delay: Number.MAX_SAFE_INTEGER, + paused: true, + }); + this.initCluesGroup(); this.createAnimations(); @@ -123,6 +131,7 @@ export default class FightScene extends Phaser.Scene { await this.initBeDevice(); await this.initBeGame(); + this.gameTime.paused = false; this.spawnFoes(); } @@ -140,6 +149,7 @@ export default class FightScene extends Phaser.Scene { this.beGame = ( await backend.createGame(this.beDevice.id, { began_at: new Date().toISOString(), + began_at_gmtm: this.getGameTime(), }) ).data; } @@ -212,11 +222,7 @@ export default class FightScene extends Phaser.Scene { } update(time: number, delta: number): void { - // TODO: please do not parse a date every few milliseconds - if (this.beGame?.began_at) - this.hud.setClock( - new Date().getTime() - Date.parse(this.beGame.began_at), - ); + this.hud.setClock(this.getGameTime()); } checkAlive() { @@ -228,6 +234,7 @@ export default class FightScene extends Phaser.Scene { this.beGame = ( await backend.updateGame(this.beGame.id, { ended_at: new Date().toISOString(), + ended_at_gmtm: this.getGameTime(), }) ).data; this.foes.forEach((foe) => foe.destroy()); @@ -315,6 +322,7 @@ export default class FightScene extends Phaser.Scene { } else { backend.updateClue(match.beClue.id, { ended_at: new Date().toISOString(), + ended_at_gmtm: this.getGameTime(), }); this.updateScore(+10); this.popFoe(match); @@ -334,9 +342,12 @@ export default class FightScene extends Phaser.Scene { this.typewriter.setHidden(false); this.typewriter.setShiftModeOneShot(); } + this.typewriter.getGameTime = this.getGameTime.bind(this); this.typewriter.onSubmit = async (inputStatus) => { if (inputStatus.began_at === null) return; if (inputStatus.ended_at === null) return; + if (inputStatus.began_at_gmtm === null) return; + if (inputStatus.ended_at_gmtm === null) return; if (inputStatus.final === "") return; this.hud.setInput(""); this.submitTranscription({ @@ -344,6 +355,8 @@ export default class FightScene extends Phaser.Scene { ended_at: inputStatus.ended_at.toISOString(), typed: inputStatus.typed, final: inputStatus.final, + began_at_gmtm: inputStatus.began_at_gmtm, + ended_at_gmtm: inputStatus.ended_at_gmtm, }); }; this.typewriter.onChange = (inputStatus) => { @@ -356,8 +369,9 @@ export default class FightScene extends Phaser.Scene { // TODO: think of a progression which makes sense const delay = Math.max( 2000, - (8 * 1000 * (60 * 1000 - this.time.now)) / 60 / 1000 + 2 * 1000, + (8 * 1000 * (60 * 1000 - this.getGameTime())) / 60 / 1000 + 2 * 1000, ); + // TODO: it should be ok calling this on time instead of gameTime, but... is it? this.time.delayedCall(delay, this.spawnFoes.bind(this)); } @@ -372,4 +386,10 @@ export default class FightScene extends Phaser.Scene { uncoverClues() { this.foes.forEach((foe) => foe.clue.uncover()); } + + getGameTime() { + // NOTE: we don't need sub-ms precision. + // NOTE: pretty please, don't access the timer directly. + return Math.round(this.gameTime.getElapsed()); + } } diff --git a/frontend/src/js/foe.ts b/frontend/src/js/foe.ts index cc0624efb7bc1da2ee962b68a7d9337b01a96134..9b1599b63d6973f69988f4dc148c0cdfad944365 100644 --- a/frontend/src/js/foe.ts +++ b/frontend/src/js/foe.ts @@ -28,6 +28,7 @@ class Foe { await backend.createClue(this.scene.beGame.id, { word_id: this.beWord.id, began_at: new Date().toISOString(), + began_at_gmtm: this.scene.getGameTime(), }) ).data; diff --git a/frontend/src/js/typewriter.ts b/frontend/src/js/typewriter.ts index 45eb1460104371929f85706113e4ceabf218c9b0..dcfad09974b7a879768cf730022bbf11f0bfc13b 100644 --- a/frontend/src/js/typewriter.ts +++ b/frontend/src/js/typewriter.ts @@ -6,6 +6,8 @@ interface InputStatus { ended_at: Date | null; typed: string; final: string; + began_at_gmtm: number | null; + ended_at_gmtm: number | null; } enum Key { @@ -114,6 +116,7 @@ class Typewriter { onChange: (inputStatus: InputStatus) => unknown; onSubmit: (inputStatus: InputStatus) => unknown; + getGameTime: () => number; // NOTE: sigh. constructor() { this.onChange = () => {}; @@ -124,6 +127,8 @@ class Typewriter { ended_at: null, typed: "", final: "", + began_at_gmtm: null, + ended_at_gmtm: null, }; this.keyboard = new Keyboard({ @@ -181,11 +186,15 @@ class Typewriter { event: KeyboardEvent | PointerEvent | MouseEvent | TouchEvent, ) { const key = this.extractKeyfromEvent(event); - if (!this.inputStatus.began_at) this.inputStatus.began_at = new Date(); + if (this.inputStatus.began_at === null) + this.inputStatus.began_at = new Date(); + if (this.inputStatus.began_at_gmtm === null) + this.inputStatus.began_at_gmtm = this.getGameTime(); if (key === Key.Enter) { this.keyboard.clearInput(); this.inputStatus.typed += "\n"; this.inputStatus.ended_at = new Date(); + this.inputStatus.ended_at_gmtm = this.getGameTime(); this.onSubmit(this.inputStatus); this.resetInputStatus(); } else if (key === Key.Backspace) { @@ -210,6 +219,8 @@ class Typewriter { ended_at: null, typed: "", final: "", + began_at_gmtm: null, + ended_at_gmtm: null, }; }