fix rewind hogging all the memory when not on vsync

This commit is contained in:
RandomityGuy 2023-07-16 23:44:47 +05:30
parent 2ee42a2291
commit 6c20de1b8a
2 changed files with 111 additions and 89 deletions

View file

@ -11,25 +11,44 @@ import src.TimeState;
import src.DtsObject;
import shapes.Gem;
@:publicFields
class RewindMPState {
var currentTime:Float;
var targetTime:Float;
var stoppedPosition:Vector;
var prevPosition:Vector;
var position:Vector;
var velocity:Vector;
public function new() {}
public function clone() {
var c = new RewindMPState();
c.currentTime = currentTime;
c.targetTime = targetTime;
c.stoppedPosition = stoppedPosition != null ? stoppedPosition.clone() : null;
c.prevPosition = prevPosition.clone();
c.position = position.clone();
c.velocity = velocity.clone();
return c;
}
}
@:publicFields
class RewindFrame {
var timeState:TimeState;
var rewindAccumulator:Float;
var marbleColliderTransform:Matrix;
var marblePrevPosition:Vector;
var marbleNextPosition:Vector;
var marblePhysicsAccmulator:Float;
var marbleOrientation:Quat;
var marblePrevOrientation:Quat;
var marbleVelocity:Vector;
var marbleAngularVelocity:Vector;
var marblePowerup:PowerUp;
var bonusTime:Float;
var mpStates:Array<{
curState:PIState,
stopped:Bool,
stoppedPosition:Vector,
prevPosition:Vector,
position:Vector,
}>;
var mpStates:Array<RewindMPState>;
var gemCount:Int;
var gemStates:Array<Bool>;
var powerupStates:Array<Float>;
@ -58,11 +77,13 @@ class RewindFrame {
public function clone() {
var c = new RewindFrame();
c.timeState = timeState.clone();
c.rewindAccumulator = rewindAccumulator;
c.marbleColliderTransform = marbleColliderTransform.clone();
c.marblePrevPosition = marblePrevPosition.clone();
c.marbleNextPosition = marbleNextPosition.clone();
c.marblePhysicsAccmulator = marblePhysicsAccmulator;
c.marbleOrientation = marbleOrientation.clone();
c.marblePrevOrientation = marblePrevOrientation.clone();
c.marbleVelocity = marbleVelocity.clone();
c.marbleAngularVelocity = marbleAngularVelocity.clone();
c.marblePowerup = marblePowerup;
@ -74,20 +95,7 @@ class RewindFrame {
c.activePowerupStates = activePowerupStates.copy();
c.currentUp = currentUp.clone();
c.lastContactNormal = lastContactNormal.clone();
c.mpStates = [];
for (s in mpStates) {
c.mpStates.push({
curState: {
currentTime: s.curState.currentTime,
targetTime: s.curState.targetTime,
velocity: s.curState.velocity.clone(),
},
stopped: s.stopped,
position: s.position.clone(),
prevPosition: s.prevPosition.clone(),
stoppedPosition: s.stoppedPosition != null ? s.stoppedPosition.clone() : null,
});
}
c.mpStates = mpStates.copy();
c.trapdoorStates = [];
for (s in trapdoorStates) {
c.trapdoorStates.push({

View file

@ -1,5 +1,6 @@
package rewind;
import rewind.RewindFrame.RewindMPState;
import shapes.AbstractBumper;
import shapes.PowerUp;
import src.MarbleWorld;
@ -13,87 +14,93 @@ class RewindManager {
public var timeScale:Float = 1;
var timeAccumulator:Float = 0.0;
var saveResolution:Float = 0.032;
public function new(level:MarbleWorld) {
this.level = level;
this.timeScale = Settings.optionsSettings.rewindTimescale;
}
public function recordFrame() {
var rf = new RewindFrame();
rf.timeState = level.timeState.clone();
rf.marbleColliderTransform = level.marble.collider.transform.clone();
rf.marblePrevPosition = @:privateAccess level.marble.oldPos.clone();
rf.marbleNextPosition = @:privateAccess level.marble.newPos.clone();
rf.marbleOrientation = @:privateAccess level.marble.prevRot.clone();
rf.marblePhysicsAccmulator = @:privateAccess level.marble.physicsAccumulator;
rf.marbleVelocity = level.marble.velocity.clone();
rf.marbleAngularVelocity = level.marble.omega.clone();
rf.marblePowerup = level.marble.heldPowerup;
rf.bonusTime = level.bonusTime;
rf.gemCount = level.gemCount;
rf.gemStates = level.gems.map(x -> x.pickedUp);
rf.activePowerupStates = [@:privateAccess level.marble.helicopterEnableTime, @:privateAccess level.marble.megaMarbleEnableTime];
rf.currentUp = level.currentUp.clone();
rf.lastContactNormal = level.marble.lastContactNormal.clone();
rf.mpStates = level.pathedInteriors.map(x -> {
return {
curState: {
currentTime: x.currentTime,
targetTime: x.targetTime,
velocity: x.velocity.clone(),
},
stopped: @:privateAccess x.stopped,
position: @:privateAccess x.position.clone(),
prevPosition: @:privateAccess x.prevPosition.clone(),
stoppedPosition: @:privateAccess x.stoppedPosition != null ? @:privateAccess x.stoppedPosition.clone() : null,
}
});
rf.powerupStates = [];
rf.landMineStates = [];
rf.trapdoorStates = [];
for (dts in level.dtsObjects) {
if (dts is PowerUp) {
var pow:PowerUp = cast dts;
rf.powerupStates.push(pow.lastPickUpTime);
}
if (dts is Trapdoor) {
var td:Trapdoor = cast dts;
rf.trapdoorStates.push({
lastCompletion: td.lastCompletion,
lastDirection: td.lastDirection,
lastContactTime: td.lastContactTime
});
}
if (dts is AbstractBumper) {
var ab:AbstractBumper = cast dts;
rf.powerupStates.push(ab.lastContactTime);
timeAccumulator += level.timeState.dt;
while (timeAccumulator >= saveResolution) {
timeAccumulator -= saveResolution;
var rf = new RewindFrame();
rf.timeState = level.timeState.clone();
rf.marbleColliderTransform = level.marble.collider.transform.clone();
rf.marblePrevPosition = @:privateAccess level.marble.oldPos.clone();
rf.marbleNextPosition = @:privateAccess level.marble.newPos.clone();
rf.marbleOrientation = @:privateAccess level.marble.getRotationQuat().clone();
rf.marblePrevOrientation = @:privateAccess level.marble.prevRot.clone();
rf.marblePhysicsAccmulator = @:privateAccess level.marble.physicsAccumulator;
rf.marbleVelocity = level.marble.velocity.clone();
rf.marbleAngularVelocity = level.marble.omega.clone();
rf.marblePowerup = level.marble.heldPowerup;
rf.bonusTime = level.bonusTime;
rf.gemCount = level.gemCount;
rf.gemStates = level.gems.map(x -> x.pickedUp);
rf.activePowerupStates = [@:privateAccess level.marble.helicopterEnableTime, @:privateAccess level.marble.megaMarbleEnableTime];
rf.currentUp = level.currentUp.clone();
rf.lastContactNormal = level.marble.lastContactNormal.clone();
rf.mpStates = level.pathedInteriors.map(x -> {
var mpstate = new RewindMPState();
mpstate.currentTime = x.currentTime;
mpstate.targetTime = x.targetTime;
mpstate.velocity = x.velocity.clone();
mpstate.stoppedPosition = @:privateAccess x.stopped ? @:privateAccess x.stoppedPosition.clone() : null;
mpstate.position = @:privateAccess x.position.clone();
mpstate.prevPosition = @:privateAccess x.prevPosition.clone();
return mpstate;
});
rf.powerupStates = [];
rf.landMineStates = [];
rf.trapdoorStates = [];
for (dts in level.dtsObjects) {
if (dts is PowerUp) {
var pow:PowerUp = cast dts;
rf.powerupStates.push(pow.lastPickUpTime);
}
if (dts is Trapdoor) {
var td:Trapdoor = cast dts;
rf.trapdoorStates.push({
lastCompletion: td.lastCompletion,
lastDirection: td.lastDirection,
lastContactTime: td.lastContactTime
});
}
if (dts is AbstractBumper) {
var ab:AbstractBumper = cast dts;
rf.powerupStates.push(ab.lastContactTime);
}
}
rf.blastAmt = level.blastAmount;
rf.oobState = {
oob: level.outOfBounds,
timeState: level.outOfBoundsTime != null ? level.outOfBoundsTime.clone() : null
};
rf.checkpointState = {
currentCheckpoint: @:privateAccess level.currentCheckpoint,
currentCheckpointTrigger: @:privateAccess level.currentCheckpointTrigger,
checkpointBlast: @:privateAccess level.cheeckpointBlast,
checkpointCollectedGems: @:privateAccess level.checkpointCollectedGems.copy(),
checkpointHeldPowerup: @:privateAccess level.checkpointHeldPowerup,
};
rf.modeState = level.gameMode.getRewindState();
frames.push(rf);
}
rf.blastAmt = level.blastAmount;
rf.oobState = {
oob: level.outOfBounds,
timeState: level.outOfBoundsTime != null ? level.outOfBoundsTime.clone() : null
};
rf.checkpointState = {
currentCheckpoint: @:privateAccess level.currentCheckpoint,
currentCheckpointTrigger: @:privateAccess level.currentCheckpointTrigger,
checkpointBlast: @:privateAccess level.cheeckpointBlast,
checkpointCollectedGems: @:privateAccess level.checkpointCollectedGems.copy(),
checkpointHeldPowerup: @:privateAccess level.checkpointHeldPowerup,
};
rf.modeState = level.gameMode.getRewindState();
frames.push(rf);
}
public function applyFrame(rf:RewindFrame) {
timeAccumulator = rf.rewindAccumulator;
level.timeState = rf.timeState.clone();
@:privateAccess level.marble.oldPos.load(rf.marblePrevPosition);
@:privateAccess level.marble.newPos.load(rf.marbleNextPosition);
@:privateAccess level.marble.collider.transform.load(rf.marbleColliderTransform);
@:privateAccess level.marble.physicsAccumulator = rf.marblePhysicsAccmulator;
@:privateAccess level.marble.prevRot.load(rf.marbleOrientation);
@:privateAccess level.marble.prevRot.load(rf.marblePrevOrientation);
// level.marble.setMarblePosition(rf.marblePosition.x, rf.marblePosition.y, rf.marblePosition.z);
// level.marble.setRotationQuat(rf.marbleOrientation.clone());
level.marble.setRotationQuat(rf.marbleOrientation.clone());
level.marble.velocity.load(rf.marbleVelocity);
level.marble.omega.load(rf.marbleAngularVelocity);
@ -136,13 +143,19 @@ class RewindManager {
level.currentUp.load(rf.currentUp);
level.marble.lastContactNormal.load(rf.lastContactNormal);
for (i in 0...rf.mpStates.length) {
level.pathedInteriors[i].currentTime = rf.mpStates[i].curState.currentTime;
level.pathedInteriors[i].targetTime = rf.mpStates[i].curState.targetTime;
level.pathedInteriors[i].velocity.load(rf.mpStates[i].curState.velocity);
@:privateAccess level.pathedInteriors[i].stopped = rf.mpStates[i].stopped;
level.pathedInteriors[i].currentTime = rf.mpStates[i].currentTime;
level.pathedInteriors[i].targetTime = rf.mpStates[i].targetTime;
level.pathedInteriors[i].velocity.load(rf.mpStates[i].velocity);
@:privateAccess level.pathedInteriors[i].stopped = rf.mpStates[i].stoppedPosition != null;
@:privateAccess level.pathedInteriors[i].position.load(rf.mpStates[i].position);
@:privateAccess level.pathedInteriors[i].prevPosition.load(rf.mpStates[i].prevPosition);
@:privateAccess level.pathedInteriors[i].stoppedPosition = rf.mpStates[i].stoppedPosition;
if (level.pathedInteriors[i].isCollideable) {
var tform = level.pathedInteriors[i].getAbsPos().clone();
tform.setPosition(rf.mpStates[i].position);
@:privateAccess level.pathedInteriors[i].collider.setTransform(tform);
level.collisionWorld.updateTransform(@:privateAccess level.pathedInteriors[i].collider);
}
// level.pathedInteriors[i].setTransform(level.pathedInteriors[i].getTransform());
}
var pstates = rf.powerupStates.copy();
@ -209,5 +222,6 @@ class RewindManager {
public function clear() {
frames = [];
timeAccumulator = 0.0;
}
}