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:
@@ -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;
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user