using System.Linq; using Content.Shared.Movement.Components; using Content.Shared.Movement.Systems; using Content.Shared.Temperature.Components; using Robust.Shared.Timing; namespace Content.Shared.Temperature.Systems; /// /// This handles predicting temperature based speedup. /// public sealed class SharedTemperatureSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; /// /// Band-aid for unpredicted atmos. Delays the application for a short period so that laggy clients can get the replicated temperature. /// private static readonly TimeSpan SlowdownApplicationDelay = TimeSpan.FromSeconds(1f); public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnTemperatureChanged); SubscribeLocalEvent(OnRefreshMovementSpeedModifiers); } private void OnTemperatureChanged(Entity ent, ref OnTemperatureChangeEvent args) { foreach (var (threshold, modifier) in ent.Comp.Thresholds) { if (args.CurrentTemperature < threshold && args.LastTemperature > threshold || args.CurrentTemperature > threshold && args.LastTemperature < threshold) { ent.Comp.NextSlowdownUpdate = _timing.CurTime + SlowdownApplicationDelay; ent.Comp.CurrentSpeedModifier = modifier; Dirty(ent); break; } } var maxThreshold = ent.Comp.Thresholds.Max(p => p.Key); if (args.CurrentTemperature > maxThreshold && args.LastTemperature < maxThreshold) { ent.Comp.NextSlowdownUpdate = _timing.CurTime + SlowdownApplicationDelay; ent.Comp.CurrentSpeedModifier = null; Dirty(ent); } } private void OnRefreshMovementSpeedModifiers(Entity ent, ref RefreshMovementSpeedModifiersEvent args) { // Don't update speed and mispredict while we're compensating for lag. if (ent.Comp.NextSlowdownUpdate != null || ent.Comp.CurrentSpeedModifier == null) return; args.ModifySpeed(ent.Comp.CurrentSpeedModifier.Value, ent.Comp.CurrentSpeedModifier.Value); } public override void Update(float frameTime) { base.Update(frameTime); var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var temp, out var movement)) { if (temp.NextSlowdownUpdate == null) continue; if (_timing.CurTime < temp.NextSlowdownUpdate) continue; temp.NextSlowdownUpdate = null; _movementSpeedModifier.RefreshMovementSpeedModifiers(uid, movement); Dirty(uid, temp); } } }