Add game.time_scale cvar

Primary use case (other than silly) is to be a better way to speed up/slow down replays.
This commit is contained in:
PJB3005
2025-12-20 16:32:06 +01:00
parent 2e5856b54d
commit 9b02a4e718
8 changed files with 74 additions and 5 deletions

View File

@@ -788,6 +788,12 @@ namespace Robust.Shared
public static readonly CVarDef<bool> GameAutoPauseEmpty =
CVarDef.Create("game.auto_pause_empty", true, CVar.SERVERONLY);
/// <summary>
/// Scales the game simulation time. Higher values make the game slower.
/// </summary>
public static readonly CVarDef<float> GameTimeScale =
CVarDef.Create("game.time_scale", 1f, CVar.REPLICATED | CVar.SERVER);
/*
* LOG
*/

View File

@@ -219,7 +219,7 @@ namespace Robust.Shared.Timing
if (_timing.Paused)
continue;
_timing.TickRemainder = accumulator;
_timing.TickRemainder = accumulator / _timing.TimeScale;
countTicksRan += 1;
// update the simulation
@@ -282,7 +282,7 @@ namespace Robust.Shared.Timing
// if not paused, save how close to the next tick we are so interpolation works
if (!_timing.Paused)
_timing.TickRemainder = accumulator;
_timing.TickRemainder = accumulator / _timing.TimeScale;
_timing.InSimulation = false;

View File

@@ -137,6 +137,8 @@ namespace Robust.Shared.Timing
set => SetTickRateAt(value, CurTick);
}
public float TimeScale { get; set; }
/// <summary>
/// The length of a tick at the current TickRate. 1/TickRate.
/// </summary>
@@ -156,13 +158,15 @@ namespace Robust.Shared.Timing
}
}
public TimeSpan TickRemainderRealtime => TickRemainder * TimeScale;
public TimeSpan CalcAdjustedTickPeriod()
{
// ranges from -1 to 1, with 0 being 'default'
var ratio = MathHelper.Clamp(TickTimingAdjustment, -0.99f, 0.99f);
// Final period ranges from near 0 (runs very fast to catch up) or 2 * tick period (runs at half speed).
return TickPeriod * (1-ratio);
return TickPeriod * (1-ratio) * TimeScale;
}
/// <summary>
@@ -302,5 +306,10 @@ namespace Robust.Shared.Timing
var variance = devSquared / (count - 1);
return TimeSpan.FromTicks((long)Math.Sqrt(variance));
}
internal static bool IsTimescaleValid(float scale)
{
return scale > 0 && float.IsNormal(scale) && float.IsFinite(scale);
}
}
}

View File

@@ -98,8 +98,19 @@ namespace Robust.Shared.Timing
/// <summary>
/// The target ticks/second of the simulation.
/// </summary>
/// <remarks>
/// This is specified in simulation time, not real time.
/// </remarks>
ushort TickRate { get; set; }
/// <summary>
/// The scale of simulation time to real time.
/// </summary>
/// <remarks>
/// A scale of 2 means the game should go "twice as slow"
/// </remarks>
float TimeScale { get; set; }
/// <summary>
/// The baseline time value that CurTime is calculated relatively to.
/// </summary>
@@ -108,6 +119,9 @@ namespace Robust.Shared.Timing
/// <summary>
/// The length of a tick at the current TickRate. 1/TickRate.
/// </summary>
/// <remarks>
/// This is in simulation time, not necessarily real time.
/// </remarks>
TimeSpan TickPeriod { get; }
/// <summary>
@@ -115,6 +129,18 @@ namespace Robust.Shared.Timing
/// </summary>
TimeSpan TickRemainder { get; set; }
/// <summary>
/// <see cref="TickRemainder"/> in real time.
/// </summary>
TimeSpan TickRemainderRealtime { get; }
/// <summary>
/// Calculate the amount of <b>real time</b> to wait between ticks.
/// </summary>
/// <remarks>
/// This is adjusted for various "out of simulation"
/// factors such as <see cref="TickTimingAdjustment"/> and <see cref="TimeScale"/>.
/// </remarks>
TimeSpan CalcAdjustedTickPeriod();
/// <summary>