Fix slow drifting in FullReplaySender replay time (fixes #451)

This commit is contained in:
Jonas Herzig
2021-02-17 15:16:33 +01:00
parent 2f0160c4f6
commit 51a4ade37e

View File

@@ -339,9 +339,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
*/
@Override
public int currentTimeStamp() {
if (asyncMode) {
int timePassed = (int) (System.currentTimeMillis() - lastPacketSent);
return lastTimeStamp + (int) (timePassed * getReplaySpeed());
if (asyncMode && !paused()) {
return (int) ((System.currentTimeMillis() - realTimeStart) * realTimeStartSpeed);
} else {
return lastTimeStamp;
}
@@ -864,7 +863,11 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
*/
@Override
public void setReplaySpeed(final double d) {
if(d != 0) this.replaySpeed = d;
if (d != 0) {
this.replaySpeed = d;
this.realTimeStartSpeed = d;
this.realTimeStart = System.currentTimeMillis() - (long) (lastTimeStamp / d);
}
TimerAccessor timer = (TimerAccessor) ((MinecraftAccessor) mc).getTimer();
//#if MC>=11200
timer.setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK / (float) d);
@@ -878,9 +881,18 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
/////////////////////////////////////////////////////////
/**
* The real time at which the last packet was sent in milliseconds.
* Timestamp in milliseconds of when we started (or would have started when taking pauses and speed into account)
* the playback of the replay.
* Updated only when replay speed changes or on pause/unpause but definitely not on every packet to prevent gradual
* drifting.
*/
private long lastPacketSent;
private long realTimeStart;
/**
* The replay speed used for {@link #realTimeStart}.
* If the target speed differs from this one, the timestamp is recalculated.
*/
private double realTimeStartSpeed;
/**
* There is no waiting performed until a packet with at least this timestamp is reached (but not yet sent).
@@ -936,15 +948,13 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
// If we aren't jumping and the world has already been loaded (no dirt-screens) then wait
// the required amount to get proper packet timing
if (!isHurrying() && hasWorldLoaded) {
// How much time should have passed
int timeWait = (int) Math.round((nextTimeStamp - lastTimeStamp) / replaySpeed);
// How much time did pass
long timeDiff = System.currentTimeMillis() - lastPacketSent;
// How much time we need to wait to make up for the difference
long timeToSleep = Math.max(0, timeWait - timeDiff);
Thread.sleep(timeToSleep);
lastPacketSent = System.currentTimeMillis();
// Timestamp of when the next packet should be sent
long expectedTime = realTimeStart + (long) (nextTimeStamp / replaySpeed);
long now = System.currentTimeMillis();
// If the packet should not yet be sent, wait a bit
if (expectedTime > now) {
Thread.sleep(expectedTime - now);
}
}
// Process packet
@@ -961,7 +971,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
replayHandler.moveCameraToTargetPosition();
// Pause after jumping
// Pause after jumping (this will also reset realTimeStart accordingly)
setReplaySpeed(0);
}
} catch (EOFException eof) {
@@ -988,7 +998,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
loginPhase = true;
startFromBeginning = false;
nextPacket = null;
lastPacketSent = System.currentTimeMillis();
realTimeStart = System.currentTimeMillis();
if (replayIn != null) {
replayIn.close();
replayIn = null;
@@ -1133,7 +1143,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
}
// This might be required if we change to async mode anytime soon
lastPacketSent = System.currentTimeMillis();
realTimeStart = System.currentTimeMillis() - (long) (timestamp / replaySpeed);
lastTimeStamp = timestamp;
}
} catch (Exception e) {