Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model static fires equalizing with the local atmosphere #32760

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions Content.Server/Atmos/Components/FlammableComponent.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,64 @@
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Prototypes;
using System.Linq;

namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public sealed partial class FlammableComponent : Component
{
// An array which represents the atmos gases as mols, Specifies 1 mol of Oxygen.
private static float[] _standardOxygenMols = new float[] { 1f }.Concat(Enumerable.Repeat(0f, Atmospherics.AdjustedNumberOfGases - 1)).ToArray();

[DataField]
public bool Resisting;

[ViewVariables(VVAccess.ReadWrite)]
/// <summary>
/// A gas mix which specifies the minimum mols of each gas needed for the entity to burn. Set to null to burn without atmosphere.
/// </summary>
[DataField]
public GasMixture? FuelGasMix = new GasMixture(_standardOxygenMols, Atmospherics.T20C, 1f);

[DataField]
public bool OnFire;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float FireStacks;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MaximumFireStacks = 10f;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MinimumFireStacks = -10f;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public string FlammableFixtureID = "flammable";

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MinIgnitionTemperature = 373.15f;

[ViewVariables(VVAccess.ReadWrite)]
/// <summary>
/// The peak temperature the entity will reach by burning alone.
/// </summary>
[DataField]
public float PeakFlameTemperature = 1500.00f; // vaguely how hot an incenerator gets.

/// <summary>
/// How much energy is released while the entity is burning.
/// </summary>
[DataField]
public float JoulesPerFirestack = 8500;

[DataField]
public bool FireSpread { get; private set; } = false;

[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public bool CanResistFire { get; private set; } = false;

[DataField(required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier Damage = new(); // Empty by default, we don't want any funny NREs.

/// <summary>
Expand All @@ -56,28 +70,25 @@ public sealed partial class FlammableComponent : Component
/// <summary>
/// Should the component be set on fire by interactions with isHot entities
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public bool AlwaysCombustible = false;

/// <summary>
/// Can the component anyhow lose its FireStacks?
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public bool CanExtinguish = true;

/// <summary>
/// How many firestacks should be applied to component when being set on fire?
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float FirestacksOnIgnite = 2.0f;

/// <summary>
/// Determines how quickly the object will fade out. With positive values, the object will flare up instead of going out.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float FirestackFade = -0.1f;

[DataField]
Expand Down
2 changes: 1 addition & 1 deletion Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public override void Update(float frameTime)
var query = EntityQueryEnumerator<AtmosExposedComponent, TransformComponent>();
while (query.MoveNext(out var uid, out _, out var transform))
{
var air = GetContainingMixture((uid, transform));
var air = GetContainingMixture((uid, transform), ignoreExposed: false, excite: true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default arguments need not be re-specified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all atmos exposed devices necessarily need to be excited. Things only need to be excited if the mixture is changed. So this call should be delayed until it's guaranteed that the mix is changed.


if (air == null)
continue;
Expand Down
39 changes: 32 additions & 7 deletions Content.Server/Atmos/EntitySystems/FlammableSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
using Content.Shared.Atmos.Piping.Binary.Components;

namespace Content.Server.Atmos.EntitySystems
{
Expand Down Expand Up @@ -413,7 +414,6 @@ public override void Update(float frameTime)

_timer -= UpdateTime;

// TODO: This needs cleanup to take off the crust from TemperatureComponent and shit.
var query = EntityQueryEnumerator<FlammableComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var flammable, out _))
{
Expand All @@ -433,20 +433,45 @@ public override void Update(float frameTime)

if (flammable.FireStacks > 0)
{
var air = _atmosphereSystem.GetContainingMixture(uid);
var air = _atmosphereSystem.GetContainingMixture(uid); // we dont excite the atmos here, and let AtmosExposedComponent handle if it is necessary.

// If we're in an oxygenless environment, put the fire out.
if (air == null || air.GetMoles(Gas.Oxygen) < 1f)
if (flammable.FuelGasMix != null)
{
Extinguish(uid, flammable);
continue;
// If we're in no atmos extinguish.
if (air == null)
{
Extinguish(uid, flammable);
continue;
}

// If our local atmos doesnt have enough of the required gases extinguish.
if (!flammable.FuelGasMix.HasMinMoles(air))
{
Extinguish(uid, flammable);
continue;
}
}

var source = EnsureComp<IgnitionSourceComponent>(uid);
_ignitionSourceSystem.SetIgnited((uid, source));

if (TryComp(uid, out TemperatureComponent? temp))
_temperatureSystem.ChangeHeat(uid, 12500 * flammable.FireStacks, false, temp);
{
// get hot
EnsureComp<AtmosExposedComponent>(uid); // required for the entity to ever cool down.
if (!_physicsQuery.TryComp(uid, out var physics))
continue;

_temperatureSystem.ChangeHeat(uid, flammable.JoulesPerFirestack * flammable.FireStacks, false, temp);

// var maxDeltaT = flammable.PeakFlameTemperature - temp.CurrentTemperature; // commented out in favor of the above simple linear heat change. Leaving this here in case that proves too abusable.
// if (maxDeltaT > 0) // we dont want to burn and get colder.
// {
//
// var tempBump = MathF.Sqrt(maxDeltaT * temp.SpecificHeat * physics.Mass) * flammable.FireStacks; //monotonic function, slows as it reaches maxT
// _temperatureSystem.ChangeHeat(uid, tempBump, false, temp);
// }
}

var ev = new GetFireProtectionEvent();
// let the thing on fire handle it
Expand Down
3 changes: 2 additions & 1 deletion Content.Server/Temperature/Systems/TemperatureSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ private void OnAtmosExposedUpdate(EntityUid uid, TemperatureComponent temperatur
var heatCapacity = GetHeatCapacity(uid, temperature);
var heat = temperatureDelta * (airHeatCapacity * heatCapacity /
(airHeatCapacity + heatCapacity));
ChangeHeat(uid, heat * temperature.AtmosTemperatureTransferEfficiency, temperature: temperature);
ChangeHeat(uid, heat * temperature.AtmosTemperatureTransferEfficiency, temperature: temperature); // move heat to entity
_atmosphere.AddHeat(args.GasMixture, -1 * heat * temperature.AtmosTemperatureTransferEfficiency); // remove heat from air
Comment on lines +163 to +164
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate PR, because this is a bug fix to TemperatureSystem.

Copy link
Contributor Author

@IProduceWidgets IProduceWidgets Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its necessary for temp-emitting fires.
Without it, temperatures cant equalize and run away.

}

public float GetHeatCapacity(EntityUid uid, TemperatureComponent? comp = null, PhysicsComponent? physics = null)
Expand Down
18 changes: 17 additions & 1 deletion Content.Shared/Atmos/GasMixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using Content.Shared.Atmos.EntitySystems;
Expand Down Expand Up @@ -271,6 +271,22 @@ public bool Equals(GasMixture? other)
&& Volume.Equals(other.Volume);
}

/// <summary>
/// Returns True if supersetMix has more moles for all gases by mole quantity only.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasMinMoles(GasMixture supersetMix)
{
for (int i = 0; i < Atmospherics.AdjustedNumberOfGases; i++)
{
if (supersetMix.GetMoles(i) < GetMoles(i))
{
return false;
}
}
return true;
}

[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override int GetHashCode()
{
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Catalog/Fills/Crates/engineering.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,4 @@
- type: StorageFill
contents:
- id: SpaceHeaterFlatpack

6 changes: 5 additions & 1 deletion Resources/Prototypes/Entities/Objects/Misc/candles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,19 @@
volume: 10
- type: UseDelay
- type: Flammable
peakFlameTemperature: 350
joulesPerFirestack: 80
fireSpread: false
canResistFire: false
alwaysCombustible: true
canExtinguish: true
firestacksOnIgnite: 3.0
firestacksOnIgnite: 3.3
IProduceWidgets marked this conversation as resolved.
Show resolved Hide resolved
firestackFade: -0.01
damage:
types:
Heat: 0.1
- type: Temperature
- type: AtmosExposed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not need to be added here, because you EnsureComp it when it gets lit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not strictly necessary, and probably fine if we drop it, but it does mean that the temperature of flammable things will be wrong when they initially catch fire. Could lead to weird behavior like catching fire initially cooling the room before heating it again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that?

This would mean that every single candle gets called in the AtmosUpdate event.

Copy link
Contributor Author

@IProduceWidgets IProduceWidgets Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They would have whatever the prototype temperature is (usually 20C) until they gain the AtmosExposedComponent and equalize. So if the room is already hot, say 50C, when the candle is lit it will initially be colder than the room and pull heat from the air until it reaches room temp.

Although now I'm saying that, I can probably just fake it by setting the entitie's temperature to the air temp when it first ignites.

- type: FireVisuals
sprite: Objects/Misc/candles.rsi
normalState: fire-big
Expand Down
Loading