mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
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:
@@ -40,6 +40,7 @@ END TEMPLATE-->
|
||||
### New features
|
||||
|
||||
* Added `IsUiOpen` and `IsAnyUiOpen` to `SharedUserInterfaceSystem`. (was in previous engine release, missed in changelog)
|
||||
* Added `game.time_scale` CVar.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace Robust.Client
|
||||
NetMessageAccept.Handshake | NetMessageAccept.Client);
|
||||
|
||||
_configManager.OnValueChanged(CVars.NetTickrate, TickRateChanged, invokeImmediately: true);
|
||||
_configManager.OnValueChanged(CVars.GameTimeScale, TimeScaleChanged, invokeImmediately: true);
|
||||
|
||||
_playMan.Initialize(0);
|
||||
_playMan.PlayerListUpdated += OnPlayerListUpdated;
|
||||
@@ -95,6 +96,18 @@ namespace Robust.Client
|
||||
_logger.Info($"Tickrate changed to: {tickrate} on tick {_timing.CurTick}");
|
||||
}
|
||||
|
||||
private void TimeScaleChanged(float timeScale, in CVarChangeInfo info)
|
||||
{
|
||||
if (!GameTiming.IsTimescaleValid(timeScale))
|
||||
{
|
||||
_logger.Error($"Invalid time scale set: {timeScale}, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
_timing.TimeScale = timeScale;
|
||||
_logger.Info($"Tickrate changed to: {timeScale} on tick {_timing.CurTick}");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ConnectToServer(DnsEndPoint endPoint)
|
||||
{
|
||||
|
||||
@@ -440,7 +440,7 @@ namespace Robust.Client.GameStates
|
||||
|
||||
// If we are about to process an another tick in the same frame, lets not bother unnecessarily running prediction ticks
|
||||
// Really the main-loop ticking just needs to be more specialized for clients.
|
||||
if (_timing.TickRemainder >= _timing.CalcAdjustedTickPeriod())
|
||||
if (_timing.TickRemainderRealtime >= _timing.CalcAdjustedTickPeriod())
|
||||
return;
|
||||
|
||||
if (!processedAny)
|
||||
@@ -467,7 +467,8 @@ namespace Robust.Client.GameStates
|
||||
DebugTools.Assert(_timing.InSimulation);
|
||||
|
||||
var ping = (_network.ServerChannel?.Ping ?? 0) / 1000f + PredictLagBias; // seconds.
|
||||
var predictionTarget = _timing.LastProcessedTick + (uint) (_processor.TargetBufferSize + Math.Ceiling(_timing.TickRate * ping) + PredictTickBias);
|
||||
var lagTickCount = Math.Ceiling(_timing.TickRate * ping / _timing.TimeScale);
|
||||
var predictionTarget = _timing.LastProcessedTick + (uint) (_processor.TargetBufferSize + lagTickCount + PredictTickBias);
|
||||
|
||||
if (IsPredictionEnabled)
|
||||
{
|
||||
|
||||
@@ -594,6 +594,19 @@ namespace Robust.Server
|
||||
_logger.Info($"Tickrate changed to: {b} on tick {_time.CurTick}");
|
||||
});
|
||||
|
||||
_config.OnValueChanged(CVars.GameTimeScale, f =>
|
||||
{
|
||||
if (!GameTiming.IsTimescaleValid(f))
|
||||
{
|
||||
_logger.Error($"Invalid time scale set: {f}, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
_time.TimeScale = f;
|
||||
|
||||
_logger.Info($"Timescale changed to: {f} on tick {_time.CurTick}");
|
||||
}, true);
|
||||
|
||||
var startOffset = TimeSpan.FromSeconds(_config.GetCVar(CVars.NetTimeStartOffset));
|
||||
_time.TimeBase = (startOffset, GameTick.First);
|
||||
_time.TickRate = (ushort) _config.GetCVar(CVars.NetTickrate);
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user