From 80dba2a535f1bdde13a14bf7ae2cca2bbf31154f Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Mon, 8 May 2023 01:10:58 +0530 Subject: [PATCH] fix some rewind bugs and add replay support for rewind --- src/Console.hx | 14 +++++++++++++ src/MarbleWorld.hx | 37 +++++++++++++++++++------------- src/Replay.hx | 42 +++++++++++++++++++++++++++++++++++++ src/Settings.hx | 10 +++++++++ src/rewind/RewindManager.hx | 8 +++++++ 5 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/Console.hx b/src/Console.hx index 99764e31..7f3a81ec 100644 --- a/src/Console.hx +++ b/src/Console.hx @@ -6,6 +6,7 @@ import sys.FileSystem; import mis.MisParser; import src.Settings; import src.Debug; +import src.MarbleGame; @:publicFields class ConsoleEntry { @@ -142,6 +143,19 @@ class Console { } else { error("Expected one argument, got " + (cmdSplit.length - 1)); } + } else if (cmdType == "rewindTimeScale") { + if (cmdSplit.length == 2) { + var scale = Std.parseFloat(cmdSplit[1]); + if (Math.isNaN(scale)) + scale = 1; + if (MarbleGame.instance.world != null) { + MarbleGame.instance.world.rewindManager.timeScale = scale; + + log("Rewind Time scale set to " + scale); + } + } else { + error("Expected one argument, got " + (cmdSplit.length - 1)); + } } else { error("Unknown command"); } diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 42b24927..985c2de1 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -201,6 +201,9 @@ class MarbleWorld extends Scheduler { var textureResources:Array> = []; var soundResources:Array> = []; + var oobSchedule:Float; + var oobSchedule2:Float; + var lock:Bool = false; public function new(scene:Scene, scene2d:h2d.Scene, mission:Mission, record:Bool = false) { @@ -982,8 +985,22 @@ class MarbleWorld extends Scheduler { if (!_ready) { return; } + + var realDt = dt; + + if (Key.isDown(Settings.controlsSettings.rewind) && Settings.optionsSettings.rewindEnabled && !this.isWatching) { + this.rewinding = true; + } else { + this.rewinding = false; + if (Key.isReleased(Settings.controlsSettings.rewind)) { + if (this.isRecording) { + this.replay.spliceReplay(timeState.currentAttemptTime); + } + } + } + if (!this.isWatching) { - if (this.isRecording) { + if (this.isRecording && !this.rewinding) { this.replay.startFrame(); } } else { @@ -1005,15 +1022,7 @@ class MarbleWorld extends Scheduler { } } - var realDt = dt; - - if (Key.isDown(Key.R)) { - this.rewinding = true; - } else { - this.rewinding = false; - } - - if (this.rewinding) { + if (this.rewinding && !this.isWatching) { var rframe = rewindManager.getNextRewindFrame(timeState.currentAttemptTime - dt * rewindManager.timeScale); if (rframe != null) { var actualDt = timeState.currentAttemptTime - rframe.timeState.currentAttemptTime - dt * rewindManager.timeScale; @@ -1109,12 +1118,12 @@ class MarbleWorld extends Scheduler { } if (!this.isWatching) { - if (this.isRecording) { + if (this.isRecording && !this.rewinding) { this.replay.endFrame(); } } - if (!this.rewinding) + if (!this.rewinding && Settings.optionsSettings.rewindEnabled) this.rewindManager.recordFrame(); this.updateTexts(); @@ -1721,11 +1730,11 @@ class MarbleWorld extends Scheduler { playGui.setCenterText('outofbounds'); AudioManager.playSound(ResourceLoader.getResource('data/sound/whoosh.wav', ResourceLoader.getAudio, this.soundResources)); // if (this.replay.mode != = 'playback') - this.schedule(this.timeState.currentAttemptTime + 2, () -> { + this.oobSchedule = this.schedule(this.timeState.currentAttemptTime + 2, () -> { playGui.setCenterText('none'); return null; }); - this.schedule(this.timeState.currentAttemptTime + 2.5, () -> { + this.oobSchedule2 = this.schedule(this.timeState.currentAttemptTime + 2.5, () -> { this.restart(); return null; }); diff --git a/src/Replay.hx b/src/Replay.hx index 7e84a00f..781b3e8d 100644 --- a/src/Replay.hx +++ b/src/Replay.hx @@ -203,6 +203,7 @@ class ReplayInitialState { var landMineDisappearTimes:Array = []; var pushButtonContactTimes:Array = []; var randomGens:Array = []; + var randomGenTimes:Array = []; public function new() {} @@ -293,12 +294,16 @@ class Replay { } public function recordTimeState(time:Float, clockTime:Float, bonusTime:Float) { + if (currentRecordFrame == null) + return; currentRecordFrame.time = time; currentRecordFrame.clockTime = clockTime; currentRecordFrame.bonusTime = bonusTime; } public function recordMarbleState(position:Vector, velocity:Vector, orientation:Quat, angularVelocity:Vector) { + if (currentRecordFrame == null) + return; currentRecordFrame.marblePosition = position.clone(); currentRecordFrame.marbleVelocity = velocity.clone(); currentRecordFrame.marbleOrientation = orientation.clone(); @@ -306,6 +311,8 @@ class Replay { } public function recordMarbleStateFlags(jumped:Bool, usedPowerup:Bool, instantTeleport:Bool, usedBlast:Bool) { + if (currentRecordFrame == null) + return; if (jumped) currentRecordFrame.marbleStateFlags.set(Jumped); if (usedPowerup) @@ -317,6 +324,8 @@ class Replay { } public function recordPowerupPickup(powerup:PowerUp) { + if (currentRecordFrame == null) + return; if (powerup == null) currentRecordFrame.powerupPickup = ""; // Use powerup else @@ -324,16 +333,22 @@ class Replay { } public function recordMarbleInput(x:Float, y:Float) { + if (currentRecordFrame == null) + return; currentRecordFrame.marbleX = x; currentRecordFrame.marbleY = y; } public function recordCameraState(pitch:Float, yaw:Float) { + if (currentRecordFrame == null) + return; currentRecordFrame.cameraPitch = pitch; currentRecordFrame.cameraYaw = yaw; } public function recordGravity(gravity:Vector, instant:Bool) { + if (currentRecordFrame == null) + return; currentRecordFrame.gravityChange = true; currentRecordFrame.gravity = gravity.clone(); if (instant) @@ -341,21 +356,30 @@ class Replay { } public function recordTrapdoorState(lastContactTime:Float, lastDirection:Int, lastCompletion:Float) { + if (currentRecordFrame == null) + return; initialState.trapdoorLastContactTimes.push(lastContactTime); initialState.trapdoorLastDirections.push(lastDirection); initialState.trapdoorLastCompletions.push(lastCompletion); } public function recordLandMineState(disappearTime:Float) { + if (currentRecordFrame == null) + return; initialState.landMineDisappearTimes.push(disappearTime); } public function recordPushButtonState(lastContactTime:Float) { + if (currentRecordFrame == null) + return; initialState.pushButtonContactTimes.push(lastContactTime); } public function recordRandomGenState(ri:Int) { + if (currentRecordFrame == null) + return; initialState.randomGens.push(ri); + initialState.randomGenTimes.push(currentRecordFrame.time); } public function getRandomGenState() { @@ -442,6 +466,24 @@ class Replay { this.currentPlaybackFrameIdx = 0; } + public function spliceReplay(cutAfterTime:Float) { + if (this.frames.length > 0) { + var curframe = this.frames[this.frames.length - 1]; + while (curframe.time > cutAfterTime && this.frames.length > 0) { + this.frames.pop(); + curframe = this.frames[this.frames.length - 1]; + } + } + if (this.initialState.randomGenTimes.length > 0) { + var rtimeIdx = this.initialState.randomGenTimes.length - 1; + while (this.initialState.randomGenTimes[rtimeIdx] > cutAfterTime && this.initialState.randomGenTimes.length > 0) { + this.initialState.randomGenTimes.pop(); + this.initialState.randomGens.pop(); + rtimeIdx = this.initialState.randomGenTimes.length - 1; + } + } + } + public function write() { var bw = new BytesWriter(); diff --git a/src/Settings.hx b/src/Settings.hx index f8a6c5e6..e26e0a88 100644 --- a/src/Settings.hx +++ b/src/Settings.hx @@ -43,6 +43,7 @@ typedef OptionsSettings = { var marbleModel:String; var marbleShader:String; var cameraDistance:Float; + var rewindEnabled:Bool; } typedef ControlsSettings = { @@ -122,6 +123,7 @@ class Settings { marbleModel: "data/shapes/balls/ball-superball.dts", marbleShader: "Default", cameraDistance: 2.5, + rewindEnabled: false, vsync: #if js true #end #if hl false @@ -363,10 +365,15 @@ class Settings { optionsSettings = json.options; if (optionsSettings.fovX == 0 #if js || optionsSettings.fovX == null #end) optionsSettings.fovX = 90; + if (optionsSettings.rewindEnabled == false #if js || optionsSettings.rewindEnabled == null #end) + optionsSettings.rewindEnabled = false; controlsSettings = json.controls; if (json.touch != null) { touchSettings = json.touch; } + if (controlsSettings.rewind == 0) { + controlsSettings.rewind = Key.R; + } if (touchSettings.blastButtonPos == null) { touchSettings.blastButtonPos = [300, 240]; touchSettings.blastButtonSize = 60; @@ -401,6 +408,9 @@ class Settings { if (controlsSettings.rewind == null) { controlsSettings.rewind = Key.R; } + if (optionsSettings.rewindEnabled == null) { + optionsSettings.rewindEnabled = false; + } #end highscoreName = json.highscoreName; } else { diff --git a/src/rewind/RewindManager.hx b/src/rewind/RewindManager.hx index 9f0ecde2..2b01a85d 100644 --- a/src/rewind/RewindManager.hx +++ b/src/rewind/RewindManager.hx @@ -204,6 +204,14 @@ class RewindManager { td.lastContactTime = tdState.lastContactTime; } } + + if (!rf.oobState.oob) { + @:privateAccess level.cancel(level.oobSchedule); + @:privateAccess level.cancel(level.oobSchedule2); + } else { + level.goOutOfBounds(); + } + level.outOfBounds = rf.oobState.oob; level.marble.camera.oob = rf.oobState.oob; level.outOfBoundsTime = rf.oobState.timeState != null ? rf.oobState.timeState.clone() : null;