fix some rewind bugs and add replay support for rewind

This commit is contained in:
RandomityGuy 2023-05-08 01:10:58 +05:30
parent 3aaa419bd4
commit 80dba2a535
5 changed files with 97 additions and 14 deletions

View file

@ -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");
}

View file

@ -201,6 +201,9 @@ class MarbleWorld extends Scheduler {
var textureResources:Array<Resource<h3d.mat.Texture>> = [];
var soundResources:Array<Resource<Sound>> = [];
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;
});

View file

@ -203,6 +203,7 @@ class ReplayInitialState {
var landMineDisappearTimes:Array<Float> = [];
var pushButtonContactTimes:Array<Float> = [];
var randomGens:Array<Int> = [];
var randomGenTimes:Array<Float> = [];
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();

View file

@ -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 {

View file

@ -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;