Add verbose (client predicted!) examine text to Gas Miners (#30480)
* add verbose examine text to gas miners so their behaviour can be understood * no need for these to be properties * use an enum instead of two booleans for the miner state * require the gas miner to be anchored in order to not be disabled * xmldoc * pr feedback * file-scope namespace * it's to late to hide my transgressions in a rebase * turns out the normal examine distance is totally fine for this
This commit is contained in:
10
Content.Client/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
10
Content.Client/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Client.Atmos.EntitySystems;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class GasMinerSystem : SharedGasMinerSystem
|
||||
{
|
||||
|
||||
}
|
||||
90
Content.Server/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
90
Content.Server/Atmos/EntitySystems/GasMinerSystem.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class GasMinerSystem : SharedGasMinerSystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
|
||||
}
|
||||
|
||||
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var miner = ent.Comp;
|
||||
var oldState = miner.MinerState;
|
||||
float toSpawn;
|
||||
|
||||
if (!GetValidEnvironment(ent, out var environment) || !Transform(ent).Anchored)
|
||||
{
|
||||
miner.MinerState = GasMinerState.Disabled;
|
||||
}
|
||||
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
|
||||
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
|
||||
else if ((toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment)) == 0)
|
||||
{
|
||||
miner.MinerState = GasMinerState.Idle;
|
||||
}
|
||||
else
|
||||
{
|
||||
miner.MinerState = GasMinerState.Working;
|
||||
|
||||
// Time to mine some gas.
|
||||
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
|
||||
merger.SetMoles(miner.SpawnGas, toSpawn);
|
||||
_atmosphereSystem.Merge(environment, merger);
|
||||
}
|
||||
|
||||
if (miner.MinerState != oldState)
|
||||
{
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
var transform = Transform(uid);
|
||||
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
|
||||
|
||||
// Treat space as an invalid environment
|
||||
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
|
||||
{
|
||||
environment = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
|
||||
return environment != null;
|
||||
}
|
||||
|
||||
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
|
||||
// How many moles could we theoretically spawn. Cap by pressure and amount.
|
||||
var allowableMoles = Math.Min(
|
||||
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
|
||||
miner.MaxExternalAmount - environment.TotalMoles);
|
||||
|
||||
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
|
||||
|
||||
if (toSpawnReal < Atmospherics.GasMinMoles) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return toSpawnReal;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using Content.Shared.Atmos;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Other.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class GasMinerComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Idle { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// If the number of moles in the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("maxExternalAmount")]
|
||||
public float MaxExternalAmount { get; set; } = float.PositiveInfinity;
|
||||
|
||||
/// <summary>
|
||||
/// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("maxExternalPressure")]
|
||||
public float MaxExternalPressure { get; set; } = Atmospherics.GasMinerDefaultMaxExternalPressure;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("spawnGas")]
|
||||
public Gas? SpawnGas { get; set; } = null;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("spawnTemperature")]
|
||||
public float SpawnTemperature { get; set; } = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// Number of moles created per second when the miner is working.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("spawnAmount")]
|
||||
public float SpawnAmount { get; set; } = Atmospherics.MolesCellStandard * 20f;
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Other.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Other.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class GasMinerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
|
||||
}
|
||||
|
||||
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var miner = ent.Comp;
|
||||
|
||||
if (!GetValidEnvironment(ent, out var environment))
|
||||
{
|
||||
miner.Idle = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
|
||||
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
|
||||
var toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment);
|
||||
miner.Idle = toSpawn == 0;
|
||||
if (miner.Idle || !miner.Enabled || !miner.SpawnGas.HasValue)
|
||||
return;
|
||||
|
||||
// Time to mine some gas.
|
||||
|
||||
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
|
||||
merger.SetMoles(miner.SpawnGas.Value, toSpawn);
|
||||
|
||||
_atmosphereSystem.Merge(environment, merger);
|
||||
}
|
||||
|
||||
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
var transform = Transform(uid);
|
||||
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
|
||||
|
||||
// Treat space as an invalid environment
|
||||
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
|
||||
{
|
||||
environment = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
|
||||
return environment != null;
|
||||
}
|
||||
|
||||
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
|
||||
{
|
||||
var (uid, miner) = ent;
|
||||
|
||||
// How many moles could we theoretically spawn. Cap by pressure and amount.
|
||||
var allowableMoles = Math.Min(
|
||||
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
|
||||
miner.MaxExternalAmount - environment.TotalMoles);
|
||||
|
||||
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
|
||||
|
||||
if (toSpawnReal < Atmospherics.GasMinMoles) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return toSpawnReal;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Content.Shared/Atmos/Components/GasMinerComponent.cs
Normal file
60
Content.Shared/Atmos/Components/GasMinerComponent.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Atmos.Components;
|
||||
|
||||
[NetworkedComponent]
|
||||
[AutoGenerateComponentState]
|
||||
[RegisterComponent]
|
||||
public sealed partial class GasMinerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Operational state of the miner.
|
||||
/// </summary>
|
||||
[AutoNetworkedField]
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public GasMinerState MinerState = GasMinerState.Disabled;
|
||||
|
||||
/// <summary>
|
||||
/// If the number of moles in the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float MaxExternalAmount = float.PositiveInfinity;
|
||||
|
||||
/// <summary>
|
||||
/// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float MaxExternalPressure = Atmospherics.GasMinerDefaultMaxExternalPressure;
|
||||
|
||||
/// <summary>
|
||||
/// Gas to spawn.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField(required: true)]
|
||||
public Gas SpawnGas;
|
||||
|
||||
/// <summary>
|
||||
/// Temperature in Kelvin.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float SpawnTemperature = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// Number of moles created per second when the miner is working.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float SpawnAmount = Atmospherics.MolesCellStandard * 20f;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum GasMinerState : byte
|
||||
{
|
||||
Disabled,
|
||||
Idle,
|
||||
Working,
|
||||
}
|
||||
55
Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs
Normal file
55
Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Temperature;
|
||||
|
||||
namespace Content.Shared.Atmos.EntitySystems;
|
||||
|
||||
public abstract class SharedGasMinerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAtmosphereSystem _sharedAtmosphereSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<GasMinerComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<GasMinerComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var component = ent.Comp;
|
||||
|
||||
using (args.PushGroup(nameof(GasMinerComponent)))
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("gas-miner-mines-text",
|
||||
("gas", Loc.GetString(_sharedAtmosphereSystem.GetGas(component.SpawnGas).Name))));
|
||||
|
||||
args.PushText(Loc.GetString("gas-miner-amount-text",
|
||||
("moles", $"{component.SpawnAmount:0.#}")));
|
||||
|
||||
args.PushText(Loc.GetString("gas-miner-temperature-text",
|
||||
("tempK", $"{component.SpawnTemperature:0.#}"),
|
||||
("tempC", $"{TemperatureHelpers.KelvinToCelsius(component.SpawnTemperature):0.#}")));
|
||||
|
||||
if (component.MaxExternalAmount < float.PositiveInfinity)
|
||||
{
|
||||
args.PushText(Loc.GetString("gas-miner-moles-cutoff-text",
|
||||
("moles", $"{component.MaxExternalAmount:0.#}")));
|
||||
}
|
||||
|
||||
if (component.MaxExternalPressure < float.PositiveInfinity)
|
||||
{
|
||||
args.PushText(Loc.GetString("gas-miner-pressure-cutoff-text",
|
||||
("pressure", $"{component.MaxExternalPressure:0.#}")));
|
||||
}
|
||||
|
||||
args.AddMarkup(component.MinerState switch
|
||||
{
|
||||
GasMinerState.Disabled => Loc.GetString("gas-miner-state-disabled-text"),
|
||||
GasMinerState.Idle => Loc.GetString("gas-miner-state-idle-text"),
|
||||
GasMinerState.Working => Loc.GetString("gas-miner-state-working-text"),
|
||||
// C# pattern matching is not exhaustive for enums
|
||||
_ => throw new IndexOutOfRangeException(nameof(component.MinerState)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Resources/Locale/en-US/atmos/gas-miner-component.ftl
Normal file
11
Resources/Locale/en-US/atmos/gas-miner-component.ftl
Normal file
@@ -0,0 +1,11 @@
|
||||
gas-miner-mines-text = It mines [color=lightgray]{$gas}[/color] when active.
|
||||
|
||||
gas-miner-amount-text = It mines {$moles} moles of gas a second when active.
|
||||
gas-miner-temperature-text = Mined gas temp: {$tempK}K ({$tempC}°C).
|
||||
|
||||
gas-miner-moles-cutoff-text = Surrounding moles cutoff: {$moles} moles.
|
||||
gas-miner-pressure-cutoff-text = Surrounding pressure cutoff: {$pressure} kPA.
|
||||
|
||||
gas-miner-state-working-text = The miner is [color=green]active[/color] and mining gas.
|
||||
gas-miner-state-idle-text = The miner is [color=yellow]idle[/color] and not mining gas.
|
||||
gas-miner-state-disabled-text = The miner is [color=red]disabled[/color] and not mining gas.
|
||||
Reference in New Issue
Block a user