I’m writing a game server in C# and I need to have a loop that invokes Update
method 60 times per second.
I tried to make it myself and wrote this:
async Task TickLoop() {
const int tps = 60;
const int maxTPS = 3;
Logger.Information("HPET enabled: {Value}", Stopwatch.IsHighResolution);
TimeSpan targetDeltaTime = TimeSpan.FromSeconds(1d / tps);
TimeSpan maximumDeltaTime = TimeSpan.FromSeconds(1d / maxTPS);
Stopwatch stopwatch = Stopwatch.StartNew();
TimeSpan lastTick = stopwatch.Elapsed;
while (true) {
TimeSpan currentTick = stopwatch.Elapsed;
TimeSpan deltaTime = TimeSpanUtils.Min(currentTick - lastTick, maximumDeltaTime);
lastTick = currentTick;
try {
Logger.Information($"Delta time: {deltaTime}; TPS: {1 / deltaTime.TotalSeconds}");
// todo
} catch (Exception e) {
Logger.Error(e, "Caught an exception in game loop");
}
TimeSpan freeTime = targetDeltaTime - (stopwatch.Elapsed - currentTick);
if (freeTime > TimeSpan.Zero)
await Task.Delay(freeTime);
}
}
(I don’t have enough reputation to post images, so I’ll put links instead, sorry about that)
Howewer, according to the logs, it invokes 62 times per second:
https://i.sstatic.net/1KS0kB83.png
I tried replacing Task.Delay
with Thread.Sleep
and that “solved” the problem:
https://i.sstatic.net/TVcf4hJj.png
But, as you can see, sometimes (and quite often) there are moments when TPS becomes above 60, but at other times it stays at 58, which is not very nice to see either.
I know I can just do that:
TimeSpan deltaTime = TimeSpanUtils.Clamp(currentTick - lastTick, targetDeltaTime, maximumDeltaTime);
, but would the code work correctly in that case?
And in general, is it possible that I don’t understand something and everything should be like this?