mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 18:31:17 +03:00
* Hope I'm not forgetting anything... * They call me the sender the way I'm sending it. * remove commented out YAML * last of the slop * fix test fails * first batch of test fails * no more test fails * make cryo pods work again. * Make cryo work better-er * I didn't like that a firesuit helmet was so effective on its own so I decided to be a dick about it. * review.com * oop * actually real quick do this * fix YAML issues * IHeatContainer my beloved <3 * borger * not networked :( * jackets * burgeewqjfrwjkhaskfjfsahjkfsahjkfsahjkfsajhkfsa * utter yaml nonsense * phishing --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
211 lines
9.6 KiB
C#
211 lines
9.6 KiB
C#
using System.Linq;
|
|
using Content.Shared.Movement.Components;
|
|
using Content.Shared.Movement.Systems;
|
|
using Content.Shared.Temperature.Components;
|
|
using Content.Shared.Temperature.HeatContainer;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Physics.Events;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Shared.Temperature.Systems;
|
|
|
|
/// <summary>
|
|
/// This handles predicting temperature based speedup.
|
|
/// </summary>
|
|
public abstract partial class SharedTemperatureSystem : EntitySystem
|
|
{
|
|
[Dependency] private IGameTiming _timing = default!;
|
|
[Dependency] private MovementSpeedModifierSystem _movementSpeedModifier = default!;
|
|
|
|
[Dependency] protected EntityQuery<TemperatureComponent> TemperatureQuery = 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<TemperatureComponent, MapInitEvent>(OnMapInit);
|
|
SubscribeLocalEvent<TemperatureComponent, MassDataChangedEvent>(OnMassDataChanged);
|
|
SubscribeLocalEvent<TemperatureSpeedComponent, TemperatureChangedEvent>(OnTemperatureChanged);
|
|
SubscribeLocalEvent<TemperatureSpeedComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
|
}
|
|
|
|
/// <remarks>
|
|
/// Calculates the HeatCapacity for this entity based on its SpecificHeat and mass.
|
|
/// This is a carryover from the old TemperatureSystem.
|
|
/// If this entity does not have a <see cref="PhysicsComponent"/>, then it assumes it's 1kg.
|
|
/// </remarks>
|
|
protected virtual void OnMapInit(Entity<TemperatureComponent> entity, ref MapInitEvent args)
|
|
{
|
|
// We calculate the heat capacity for our entity by multiplying its mass by its specific heat.
|
|
// If the entity has no mass, we assume it's 1 kilogram.
|
|
var mass = CompOrNull<PhysicsComponent>(entity)?.FixturesMass ?? 1f;
|
|
|
|
// TODO: This assumes this is temperature for the whole body, but ideally we want it split into surface and internal temperature!
|
|
entity.Comp.HeatCapacity = mass * entity.Comp.SpecificHeat;
|
|
}
|
|
|
|
private void OnMassDataChanged(Entity<TemperatureComponent> entity, ref MassDataChangedEvent args)
|
|
{
|
|
entity.Comp.HeatCapacity = args.NewMass * entity.Comp.SpecificHeat;
|
|
}
|
|
|
|
private void OnTemperatureChanged(Entity<TemperatureSpeedComponent> ent, ref TemperatureChangedEvent 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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Conducts heat between an entity with TemperatureComponent and another <see cref="HeatContainer"/>
|
|
/// </summary>
|
|
/// <param name="entity">Entity we're conducting heat with</param>
|
|
/// <param name="heatContainer">Heat container which is conducting heat with our entity</param>
|
|
/// <param name="deltaT">The amount of time that the heat is allowed to conduct, in seconds. This value should be small.</param>
|
|
/// <param name="heatTransferMod">An optional heat transfer modifier for this exchange</param>
|
|
/// <param name="ignoreHeatResistance">Whether we should avoid raising an event which checks for conduction modifiers on our entity.</param>
|
|
/// <returns>Returns the amount of heat exchanged, in Joules. A positive value means the entity lost heat energy.</returns>
|
|
public float ConductHeat<T>(Entity<TemperatureComponent?> entity, ref T heatContainer, float deltaT, float heatTransferMod = 1f, bool ignoreHeatResistance = false) where T : IHeatContainer
|
|
{
|
|
if (!TemperatureQuery.Resolve(entity, ref entity.Comp, false)
|
|
|| MathHelper.CloseTo(entity.Comp.Temperature, heatContainer.Temperature))
|
|
return 0f;
|
|
|
|
var conductance = entity.Comp.ThermalConductivity * heatTransferMod;
|
|
if (!ignoreHeatResistance)
|
|
{
|
|
var ev = new BeforeHeatExchangeEvent();
|
|
RaiseLocalEvent(entity, ref ev);
|
|
conductance *= ev.HeatTransferModifier;
|
|
}
|
|
|
|
var lastTemp = entity.Comp.Temperature;
|
|
var heatEx = HeatContainerHelpers.ConductHeat(ref entity.Comp, ref heatContainer, deltaT, conductance);
|
|
|
|
var changeEv = new TemperatureChangedEvent(entity.Comp.Temperature, lastTemp);
|
|
RaiseLocalEvent(entity, ref changeEv, broadcast: true);
|
|
return heatEx;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Conducts heat for an entity with a TemperatureComponent to a source at a fixed temperature.
|
|
/// </summary>
|
|
/// <param name="entity">Entity we're conducting heat with</param>
|
|
/// <param name="temperature">Temperature this entity is being exposed to</param>
|
|
/// <param name="deltaT">The amount of time that the heat is allowed to conduct, in seconds. This value should be small.</param>
|
|
/// <param name="heatTransferMod">An optional heat transfer modifier for this exchange</param>
|
|
/// <param name="ignoreHeatResistance">Whether we should avoid raising an event which checks for conduction modifiers on our entity.</param>
|
|
/// <returns>Returns the amount of heat exchanged, in Joules. A positive value means the entity lost heat energy.</returns>
|
|
public float ConductHeat(Entity<TemperatureComponent?> entity, float temperature, float deltaT, float heatTransferMod = 1f, bool ignoreHeatResistance = false)
|
|
{
|
|
if (!TemperatureQuery.Resolve(entity, ref entity.Comp, false)
|
|
|| MathHelper.CloseTo(entity.Comp.Temperature, temperature))
|
|
return 0f;
|
|
|
|
var conductance = entity.Comp.ThermalConductivity * heatTransferMod;
|
|
if (!ignoreHeatResistance)
|
|
{
|
|
var ev = new BeforeHeatExchangeEvent();
|
|
RaiseLocalEvent(entity, ref ev);
|
|
conductance *= ev.HeatTransferModifier;
|
|
}
|
|
|
|
var lastTemp = entity.Comp.Temperature;
|
|
var heatEx = HeatContainerHelpers.ConductHeat(ref entity.Comp, temperature, deltaT, conductance);
|
|
|
|
var changeEv = new TemperatureChangedEvent(entity.Comp.Temperature, lastTemp);
|
|
RaiseLocalEvent(entity, ref changeEv, broadcast: true);
|
|
return heatEx;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds or removes the specified amount of heat from an entity.
|
|
/// </summary>
|
|
/// <param name="entity">Entity whose temperature we're modifying.</param>
|
|
/// <param name="heatAmount">The change in heat.</param>
|
|
/// <param name="ignoreHeatResistance">Whether we should avoid raising an event to modify the conductance of our entity.</param>
|
|
/// <returns>Returns the amount of heat that was actually added, after applying heat resistances.</returns>
|
|
public float ChangeHeat(Entity<TemperatureComponent?> entity, float heatAmount, bool ignoreHeatResistance = false)
|
|
{
|
|
if (!TemperatureQuery.Resolve(entity, ref entity.Comp, false) || heatAmount == 0f)
|
|
return 0f;
|
|
|
|
if (!ignoreHeatResistance)
|
|
{
|
|
var ev = new BeforeHeatExchangeEvent();
|
|
RaiseLocalEvent(entity, ref ev );
|
|
heatAmount *= ev.HeatTransferModifier;
|
|
}
|
|
|
|
var lastTemp = entity.Comp.Temperature;
|
|
HeatContainerHelpers.AddHeat(ref entity.Comp, heatAmount);
|
|
|
|
var changeEv = new TemperatureChangedEvent(entity.Comp.Temperature, lastTemp);
|
|
RaiseLocalEvent(entity, ref changeEv, broadcast: true);
|
|
|
|
return heatAmount;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Protected because you should not be calling this. Sets heat to a new value.
|
|
/// </summary>
|
|
protected void SetTemperature(Entity<TemperatureComponent?> entity, float temp)
|
|
{
|
|
if (!TemperatureQuery.Resolve(entity, ref entity.Comp))
|
|
return;
|
|
|
|
var lastTemp = entity.Comp.Temperature;
|
|
entity.Comp.Temperature = temp;
|
|
var changeEv = new TemperatureChangedEvent(entity.Comp.Temperature, lastTemp);
|
|
RaiseLocalEvent(entity, ref changeEv, broadcast: true);
|
|
}
|
|
}
|