Attempt #2 to fix the timing bugs. CurTime increases again, and all the unit tests pass this time.

This resolves https://github.com/space-wizards/space-station-14/issues/1560.
Special thanks to PJB's prediction unit tests.
This commit is contained in:
Acruid
2020-07-31 23:20:35 -07:00
parent ca297ee739
commit 900bf76a7d
7 changed files with 46 additions and 7 deletions

View File

@@ -117,6 +117,8 @@ namespace Robust.Client
_entityManager.Startup();
_mapManager.Startup();
_timing.ResetSimTime();
_timing.Paused = false;
PlayerJoinedServer?.Invoke(this, new PlayerEventArgs(session));
}
@@ -190,7 +192,7 @@ namespace Robust.Client
private void HandleSetTickRate(MsgSetTickRate message)
{
_timing.TickRate = message.NewTickRate;
Logger.InfoS("client", $"Tickrate changed to: {message.NewTickRate}");
Logger.InfoS("client", $"Tickrate changed to: {message.NewTickRate} on tick {_timing.CurTick}");
}
private void OnLocalStatusChanged(object? obj, StatusEventArgs eventArgs)

View File

@@ -268,6 +268,7 @@ namespace Robust.Client
{
_clyde.ProcessInput(frameEventArgs);
_networkManager.ProcessPackets();
_taskManager.ProcessPendingTasks(); // tasks like connect
}
private void Tick(FrameEventArgs frameEventArgs)

View File

@@ -400,11 +400,14 @@ namespace Robust.Server
_uptimeStopwatch.Start();
_mainLoop.Input += (sender, args) => Input(args);
_mainLoop.Tick += (sender, args) => Update(args);
_mainLoop.Update += (sender, args) => { ServerUpTime.Set(_uptimeStopwatch.Elapsed.TotalSeconds); };
// set GameLoop.Running to false to return from this function.
_time.Paused = false;
_mainLoop.Run();
_time.InSimulation = true;
@@ -454,6 +457,8 @@ namespace Robust.Server
{
var b = (byte) i;
_time.TickRate = b;
Logger.InfoS("game", $"Tickrate changed to: {b} on tick {_time.CurTick}");
SendTickRateUpdateToClients(b);
});
@@ -511,15 +516,20 @@ namespace Robust.Server
return bps;
}
private void Input(FrameEventArgs args)
{
_systemConsole.Update();
_network.ProcessPackets();
_taskManager.ProcessPendingTasks();
}
private void Update(FrameEventArgs frameEventArgs)
{
ServerCurTick.Set(_time.CurTick.Value);
ServerCurTime.Set(_time.CurTime.TotalSeconds);
UpdateTitle();
_systemConsole.Update();
_network.ProcessPackets();
_modLoader.BroadcastUpdate(ModUpdateLevel.PreEngine, frameEventArgs);

View File

@@ -136,5 +136,10 @@ namespace Robust.Shared.Interfaces.Timing
string TickStamp => $"{CurTick}, predFirst: {IsFirstTimePredicted}, tickRem: {TickRemainder.TotalSeconds}, sim: {InSimulation}";
static string TickStampStatic => IoCManager.Resolve<IGameTiming>().TickStamp;
/// <summary>
/// Resets the simulation time. This should be called on round restarts.
/// </summary>
void ResetSimTime();
}
}

View File

@@ -28,7 +28,7 @@ namespace Robust.Shared.Timing
// does nothing if timer is already running
_realTimer.Start();
Paused = false;
Paused = true;
TickRate = NumFrames;
}
@@ -60,8 +60,17 @@ namespace Robust.Shared.Timing
{
get
{
// last tickrate change epoch
var (time, lastTimeTick) = _cachedCurTimeInfo;
// add our current time to it.
// the server never rewinds time, and the client never rewinds time outside of prediction.
// the only way this assert should fail is if the TickRate is changed inside prediction, which should never happen.
//DebugTools.Assert(CurTick >= lastTimeTick);
//TODO: turns out prediction leaves CurTick at the last predicted tick, and not at the last processed server tick
//so time gets rewound when processing events like TickRate.
time += TickPeriod * (CurTick.Value - lastTimeTick.Value);
if (!InSimulation) // rendering can draw frames between ticks
{
DebugTools.Assert(0 <= (time + TickRemainder).TotalSeconds);
@@ -191,8 +200,7 @@ namespace Robust.Shared.Timing
}
// Calculate and store the current time value, based on the current tick rate.
// Call this whenever you want an updated value for CurTime, or when
// you change the TickRate
// Call this whenever you change the TickRate.
private void CacheCurTime()
{
var (cachedTime, lastTimeTick) = _cachedCurTimeInfo;
@@ -217,6 +225,17 @@ namespace Robust.Shared.Timing
_lastRealTime = TimeSpan.Zero;
}
/// <summary>
/// Resets the simulation time.
/// </summary>
public void ResetSimTime()
{
_cachedCurTimeInfo = (TimeSpan.Zero, GameTick.First);;
CurTick = GameTick.First;
TickRemainder = TimeSpan.Zero;
Paused = true;
}
public bool IsFirstTimePredicted { get; private set; } = true;
public void StartPastPrediction()

View File

@@ -26,6 +26,7 @@ namespace Robust.UnitTesting.Shared.Timing
var newStopwatch = new Mock<IStopwatch>();
newStopwatch.SetupGet(p => p.Elapsed).Returns(elapsedVal);
var gameTiming = GameTimingFactory(newStopwatch.Object);
gameTiming.Paused = false;
var loop = new GameLoop(gameTiming);
var callCount = 0;

View File

@@ -162,6 +162,7 @@ namespace Robust.UnitTesting.Shared.Timing
newStopwatch.SetupGet(p => p.Elapsed).Returns(() => elapsedVal);
var gameTiming = GameTimingFactory(newStopwatch.Object);
gameTiming.InSimulation = false;
gameTiming.Paused = false; // paused timing returns 0 frame time.
gameTiming.StartFrame(); // changes last time from 0 to 3
// Act