From 0f0c7437a6a24e4bc5f87980990506daf5ba06fb Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Fri, 11 Dec 2020 21:14:19 -0700 Subject: [PATCH] Allow rewinding a replay without desyncing it --- js/format-c2g.js | 37 +++++++++++++++++++++++++------------ js/main.js | 10 ++-------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/js/format-c2g.js b/js/format-c2g.js index 99f0566..6d5ef4d 100644 --- a/js/format-c2g.js +++ b/js/format-c2g.js @@ -25,13 +25,20 @@ class CC2Demo { this.blob_seed = this.bytes[2]; } - *[Symbol.iterator]() { + decompress() { + let duration = 0; let l = this.bytes.length; if (l % 2 === 0) { l--; } - let input = new Set; + for (let p = 3; p < l; p += 2) { + duration += this.bytes[p]; + } + + let inputs = new Uint8Array(duration); + let i = 0; let t = 0; + let input = 0; for (let p = 3; p < l; p += 2) { // The first byte measures how long the /previous/ input remains // valid, so yield that first. Note that this is measured in 60Hz @@ -44,24 +51,31 @@ class CC2Demo { t += delay; while (t >= 3) { t -= 3; - yield input; + inputs[i] = input; + i++; } - let input_mask = this.bytes[p + 1]; - let is_player_2 = ((input_mask & 0x80) !== 0); + input = this.bytes[p + 1]; + let is_player_2 = ((input & 0x80) !== 0); // TODO handle player 2 if (is_player_2) continue; + } - for (let [action, bit] of Object.entries(CC2_DEMO_INPUT_MASK)) { - if ((input_mask & bit) === 0) { - input.delete(action); + // TODO maybe turn this into, like, a type, or something + return { + inputs: inputs, + length: duration, + get(t) { + if (t >= this.inputs.length) { + return new Set; } else { - input.add(action); + let input = this.inputs[t]; + return new Set(Object.entries(CC2_DEMO_INPUT_MASK).filter(([action, bit]) => input & bit).map(([action, bit]) => action)); } - } - } + }, + }; } } @@ -1826,7 +1840,6 @@ const MAX_SIMULTANEOUS_REQUESTS = 5; resolve(game); } - console.log(game); return promise; } diff --git a/js/main.js b/js/main.js index 23656af..3064a14 100644 --- a/js/main.js +++ b/js/main.js @@ -898,7 +898,7 @@ class Player extends PrimaryView { play_demo() { this.restart_level(); let demo = this.level.stored_level.demo; - this.demo_faucet = demo[Symbol.iterator](); + this.demo_faucet = demo.decompress(); this.level.force_floor_direction = demo.initial_force_floor_direction; this.level._blob_modifier = demo.blob_seed; // FIXME should probably start playback on first real input @@ -908,13 +908,7 @@ class Player extends PrimaryView { get_input() { let input; if (this.demo_faucet) { - let step = this.demo_faucet.next(); - if (step.done) { - input = new Set; - } - else { - input = step.value; - } + input = this.demo_faucet.get(this.level.tic_counter); } else { // Convert input keys to actions. This is only done now