6internal sealed class FixedStepAccumulator
8 private long _lastDriverTick;
9 private long _accumulatedTicks;
12 internal long SimulationTick {
get;
private set; }
16 internal void Reset(
long tick)
18 _lastDriverTick = tick;
19 _accumulatedTicks = 0;
20 SimulationTick = tick;
32 internal FixedStepBatch Advance(
long driverTick,
int updatesPerSecond,
int maxSteps)
34 if (updatesPerSecond <= 0)
35 throw new ArgumentOutOfRangeException(nameof(updatesPerSecond));
37 throw new ArgumentOutOfRangeException(nameof(maxSteps));
39 long stepTicks = Math.Max(1, HighResTimer.TicksPerSecond / updatesPerSecond);
40 long elapsedTicks = driverTick > _lastDriverTick
41 ? driverTick - _lastDriverTick
44 if (driverTick > _lastDriverTick)
45 _lastDriverTick = driverTick;
47 long maxAccumulatedTicks = stepTicks > long.MaxValue / maxSteps
49 : stepTicks * maxSteps;
51 _accumulatedTicks = elapsedTicks >= maxAccumulatedTicks - _accumulatedTicks
53 : _accumulatedTicks + elapsedTicks;
55 int stepCount = (int)Math.Min(maxSteps, _accumulatedTicks / stepTicks);
56 _accumulatedTicks -= stepCount * stepTicks;
58 long firstStepTick = SimulationTick + stepTicks;
59 SimulationTick += stepCount * stepTicks;
61 return new FixedStepBatch(firstStepTick, stepTicks, stepCount);
69internal readonly record
struct FixedStepBatch(long FirstStepTick, long StepTicks, int StepCount)
74 internal long GetStepTick(
int index)
76 if ((uint)index >= (uint)StepCount)
77 throw new ArgumentOutOfRangeException(nameof(index));
79 return FirstStepTick + (index * StepTicks);