Add slowdown to low temperatures (#29692)

* TemperatureSpeed component

* temperature slowdown prediction (done right)

* remove unnecessary changes

* that too

* get in line

* make it readonly

* auto pause
This commit is contained in:
Nemanja
2024-08-05 04:07:02 -04:00
committed by GitHub
parent 50408da21a
commit b3a64d4bcd
9 changed files with 143 additions and 27 deletions

View File

@@ -2,7 +2,6 @@ using System.Linq;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Construction.Components; using Content.Server.Construction.Components;
using Content.Server.Temperature.Components; using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
using Content.Shared.Construction; using Content.Shared.Construction;
using Content.Shared.Construction.Components; using Content.Shared.Construction.Components;
using Content.Shared.Construction.EntitySystems; using Content.Shared.Construction.EntitySystems;
@@ -11,6 +10,7 @@ using Content.Shared.DoAfter;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Prying.Systems; using Content.Shared.Prying.Systems;
using Content.Shared.Radio.EntitySystems; using Content.Shared.Radio.EntitySystems;
using Content.Shared.Temperature;
using Content.Shared.Tools.Systems; using Content.Shared.Tools.Systems;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Utility; using Robust.Shared.Utility;

View File

@@ -1,4 +1,3 @@
using Content.Server.Temperature.Systems;
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Damage; using Content.Shared.Damage;
@@ -51,15 +50,6 @@ public sealed partial class TemperatureComponent : Component
[DataField, ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public float AtmosTemperatureTransferEfficiency = 0.1f; public float AtmosTemperatureTransferEfficiency = 0.1f;
[Obsolete("Use system method")]
public float HeatCapacity
{
get
{
return IoCManager.Resolve<IEntityManager>().System<TemperatureSystem>().GetHeatCapacity(Owner, this);
}
}
[DataField, ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier ColdDamage = new(); public DamageSpecifier ColdDamage = new();
@@ -71,7 +61,7 @@ public sealed partial class TemperatureComponent : Component
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Okay it genuinely reaches this basically immediately for a plasma fire. /// Okay it genuinely reaches this basically immediately for a plasma fire.
/// </summary> /// </remarks>
[DataField, ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 DamageCap = FixedPoint2.New(8); public FixedPoint2 DamageCap = FixedPoint2.New(8);
@@ -79,7 +69,7 @@ public sealed partial class TemperatureComponent : Component
/// Used to keep track of when damage starts/stops. Useful for logs. /// Used to keep track of when damage starts/stops. Useful for logs.
/// </summary> /// </summary>
[DataField] [DataField]
public bool TakingDamage = false; public bool TakingDamage;
[DataField] [DataField]
public ProtoId<AlertPrototype> HotAlert = "Hot"; public ProtoId<AlertPrototype> HotAlert = "Hot";

View File

@@ -412,17 +412,3 @@ public sealed class TemperatureSystem : EntitySystem
return (newHeatThreshold, newColdThreshold); return (newHeatThreshold, newColdThreshold);
} }
} }
public sealed class OnTemperatureChangeEvent : EntityEventArgs
{
public float CurrentTemperature { get; }
public float LastTemperature { get; }
public float TemperatureDelta { get; }
public OnTemperatureChangeEvent(float current, float last, float delta)
{
CurrentTemperature = current;
LastTemperature = last;
TemperatureDelta = delta;
}
}

View File

@@ -0,0 +1,30 @@
using Content.Shared.Temperature.Systems;
using Robust.Shared.GameStates;
namespace Content.Shared.Temperature.Components;
/// <summary>
/// This is used for an entity that varies in speed based on current temperature.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedTemperatureSystem)), AutoGenerateComponentState, AutoGenerateComponentPause]
public sealed partial class TemperatureSpeedComponent : Component
{
/// <summary>
/// Pairs of temperature thresholds to applied slowdown values.
/// </summary>
[DataField]
public Dictionary<float, float> Thresholds = new();
/// <summary>
/// The current speed modifier from <see cref="Thresholds"/> we reached.
/// Stored and networked so that the client doesn't mispredict temperature
/// </summary>
[DataField, AutoNetworkedField]
public float? CurrentSpeedModifier;
/// <summary>
/// The time at which the temperature slowdown is updated.
/// </summary>
[DataField, AutoNetworkedField, AutoPausedField]
public TimeSpan? NextSlowdownUpdate;
}

View File

@@ -0,0 +1,80 @@
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;
/// <summary>
/// This handles predicting temperature based speedup.
/// </summary>
public sealed class SharedTemperatureSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
/// <summary>
/// Band-aid for unpredicted atmos. Delays the application for a short period so that laggy clients can get the replicated temperature.
/// </summary>
private static readonly TimeSpan SlowdownApplicationDelay = TimeSpan.FromSeconds(1f);
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TemperatureSpeedComponent, OnTemperatureChangeEvent>(OnTemperatureChanged);
SubscribeLocalEvent<TemperatureSpeedComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
}
private void OnTemperatureChanged(Entity<TemperatureSpeedComponent> 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<TemperatureSpeedComponent> 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<TemperatureSpeedComponent, MovementSpeedModifierComponent>();
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);
}
}
}

View File

@@ -13,3 +13,18 @@ public sealed class ModifyChangedTemperatureEvent : EntityEventArgs, IInventoryR
TemperatureDelta = temperature; TemperatureDelta = temperature;
} }
} }
public sealed class OnTemperatureChangeEvent : EntityEventArgs
{
public readonly float CurrentTemperature;
public readonly float LastTemperature;
public readonly float TemperatureDelta;
public OnTemperatureChangeEvent(float current, float last, float delta)
{
CurrentTemperature = current;
LastTemperature = last;
TemperatureDelta = delta;
}
}

View File

@@ -249,6 +249,11 @@
heatDamage: heatDamage:
types: types:
Heat: 1.5 #per second, scales with temperature & other constants Heat: 1.5 #per second, scales with temperature & other constants
- type: TemperatureSpeed
thresholds:
293: 0.8
280: 0.6
260: 0.4
- type: ThermalRegulator - type: ThermalRegulator
metabolismHeat: 800 metabolismHeat: 800
radiatedHeat: 100 radiatedHeat: 100

View File

@@ -64,6 +64,11 @@
heatDamage: heatDamage:
types: types:
Heat : 3 #per second, scales with temperature & other constants Heat : 3 #per second, scales with temperature & other constants
- type: TemperatureSpeed
thresholds:
289: 0.8
275: 0.6
250: 0.4
- type: Sprite # sprite again because we want different layer ordering - type: Sprite # sprite again because we want different layer ordering
noRot: true noRot: true
drawdepth: Mobs drawdepth: Mobs

View File

@@ -59,6 +59,11 @@
heatDamage: heatDamage:
types: types:
Heat : 1.5 #per second, scales with temperature & other constants Heat : 1.5 #per second, scales with temperature & other constants
- type: TemperatureSpeed
thresholds:
301: 0.8
295: 0.6
285: 0.4
- type: Wagging - type: Wagging
- type: Inventory - type: Inventory
speciesId: reptilian speciesId: reptilian