From 246fda53c58b8d501f5904ec9a4be4ca0a6903ef Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com> Date: Wed, 22 Sep 2021 13:02:25 +0200 Subject: [PATCH] Refactor Barotrauma to be ECS. (#4674) - Refactor IPressureProtection to be two different ECS events. --- .../Atmos/Components/AtmosExposedComponent.cs | 6 +- .../Atmos/Components/BarotraumaComponent.cs | 76 ---------- .../Components/PressureProtectionComponent.cs | 17 ++- .../Atmos/EntitySystems/BarotraumaSystem.cs | 138 ++++++++++++++++++ Content.Server/Atmos/PressureEvent.cs | 46 ++++++ .../Components/InventoryComponent.cs | 49 +------ Content.Server/Inventory/InventorySystem.cs | 21 +++ .../Pressure/IPressureProtection.cs | 8 - 8 files changed, 217 insertions(+), 144 deletions(-) create mode 100644 Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs create mode 100644 Content.Server/Atmos/PressureEvent.cs delete mode 100644 Content.Server/Pressure/IPressureProtection.cs diff --git a/Content.Server/Atmos/Components/AtmosExposedComponent.cs b/Content.Server/Atmos/Components/AtmosExposedComponent.cs index 0566252776..04c81e9a7c 100644 --- a/Content.Server/Atmos/Components/AtmosExposedComponent.cs +++ b/Content.Server/Atmos/Components/AtmosExposedComponent.cs @@ -17,11 +17,9 @@ namespace Content.Server.Atmos.Components [ViewVariables] [ComponentDependency] private readonly TemperatureComponent? _temperatureComponent = null; - [ViewVariables] - [ComponentDependency] private readonly BarotraumaComponent? _barotraumaComponent = null; - public void Update(GasMixture air, float frameDelta, AtmosphereSystem atmosphereSystem) { + // TODO: I'm coming for you next, TemperatureComponent... Fear me for I am death, destroyer of shitcode. if (_temperatureComponent != null) { var temperatureDelta = air.Temperature - _temperatureComponent.CurrentTemperature; @@ -30,8 +28,6 @@ namespace Content.Server.Atmos.Components _temperatureComponent.ReceiveHeat(heat); _temperatureComponent.Update(); } - - _barotraumaComponent?.Update(air.Pressure); } } } diff --git a/Content.Server/Atmos/Components/BarotraumaComponent.cs b/Content.Server/Atmos/Components/BarotraumaComponent.cs index c1cb079337..9452ccd29f 100644 --- a/Content.Server/Atmos/Components/BarotraumaComponent.cs +++ b/Content.Server/Atmos/Components/BarotraumaComponent.cs @@ -1,9 +1,3 @@ -using System; -using System.Runtime.CompilerServices; -using Content.Server.Alert; -using Content.Server.Pressure; -using Content.Shared.Alert; -using Content.Shared.Atmos; using Content.Shared.Damage; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; @@ -22,75 +16,5 @@ namespace Content.Server.Atmos.Components [DataField("damage", required: true)] [ViewVariables(VVAccess.ReadWrite)] public DamageSpecifier Damage = default!; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Update(float airPressure) - { - if (!Owner.HasComponent()) return; - - var status = Owner.GetComponentOrNull(); - var highPressureMultiplier = 1f; - var lowPressureMultiplier = 1f; - - foreach (var protection in Owner.GetAllComponents()) - { - highPressureMultiplier *= protection.HighPressureMultiplier; - lowPressureMultiplier *= protection.LowPressureMultiplier; - } - - var pressure = MathF.Max(airPressure, 1f); - - switch (pressure) - { - // Low pressure. - case var p when p <= Atmospherics.WarningLowPressure: - pressure *= lowPressureMultiplier; - if (pressure > Atmospherics.WarningLowPressure) - goto default; - - // Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear. - EntitySystem.Get().TryChangeDamage(Owner.Uid, Damage * Atmospherics.LowPressureDamage, true); - - if (status == null) break; - - if (pressure <= Atmospherics.HazardLowPressure) - { - status.ShowAlert(AlertType.LowPressure, 2); - break; - } - - status.ShowAlert(AlertType.LowPressure, 1); - break; - - // High pressure. - case var p when p >= Atmospherics.WarningHighPressure: - pressure *= highPressureMultiplier; - - if(pressure < Atmospherics.WarningHighPressure) - goto default; - - var damageScale = (int) MathF.Min((pressure / Atmospherics.HazardHighPressure) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage); - - // Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear. - EntitySystem.Get().TryChangeDamage(Owner.Uid, Damage * damageScale, true); - - if (status == null) break; - - if (pressure >= Atmospherics.HazardHighPressure) - { - status.ShowAlert(AlertType.HighPressure, 2); - break; - } - - status.ShowAlert(AlertType.HighPressure, 1); - break; - - // Normal pressure. - default: - status?.ClearAlertCategory(AlertCategory.Pressure); - break; - } - - } } } diff --git a/Content.Server/Atmos/Components/PressureProtectionComponent.cs b/Content.Server/Atmos/Components/PressureProtectionComponent.cs index 9ee628e98a..f3160528a4 100644 --- a/Content.Server/Atmos/Components/PressureProtectionComponent.cs +++ b/Content.Server/Atmos/Components/PressureProtectionComponent.cs @@ -1,21 +1,24 @@ -using Content.Server.Pressure; -using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; namespace Content.Server.Atmos.Components { [RegisterComponent] - public class PressureProtectionComponent : Component, IPressureProtection + public class PressureProtectionComponent : Component { public override string Name => "PressureProtection"; - [ViewVariables] [DataField("highPressureMultiplier")] - public float HighPressureMultiplier { get; private set; } = 1f; + public float HighPressureMultiplier { get; } = 1f; + + [DataField("highPressureModifier")] + public float HighPressureModifier { get; } = 0f; - [ViewVariables] [DataField("lowPressureMultiplier")] - public float LowPressureMultiplier { get; private set; } = 1f; + public float LowPressureMultiplier { get; } = 1f; + + [DataField("lowPressureModifier")] + public float LowPressureModifier { get; } = 0f; } } diff --git a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs new file mode 100644 index 0000000000..6b80158a70 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs @@ -0,0 +1,138 @@ +using System; +using Content.Server.Alert; +using Content.Server.Atmos.Components; +using Content.Shared.Alert; +using Content.Shared.Atmos; +using Content.Shared.Damage; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Server.Atmos.EntitySystems +{ + public class BarotraumaSystem : EntitySystem + { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + + private const float UpdateTimer = 1f; + + private float _timer = 0f; + + public override void Initialize() + { + SubscribeLocalEvent(OnHighPressureEvent); + SubscribeLocalEvent(OnLowPressureEvent); + } + + private void OnHighPressureEvent(EntityUid uid, PressureProtectionComponent component, HighPressureEvent args) + { + args.Modifier += component.HighPressureModifier; + args.Multiplier *= component.HighPressureMultiplier; + } + + private void OnLowPressureEvent(EntityUid uid, PressureProtectionComponent component, LowPressureEvent args) + { + args.Modifier += component.LowPressureModifier; + args.Multiplier *= component.LowPressureMultiplier; + } + + private float CalculateFeltPressure(float environmentPressure, PressureEvent pressureEvent) + { + environmentPressure += pressureEvent.Modifier; + environmentPressure *= pressureEvent.Multiplier; + return environmentPressure; + } + + public float GetFeltLowPressure(EntityUid uid, float environmentPressure) + { + var lowPressureEvent = new LowPressureEvent(environmentPressure); + RaiseLocalEvent(uid, lowPressureEvent, false); + + return CalculateFeltPressure(environmentPressure, lowPressureEvent); + } + + public float GetFeltHighPressure(EntityUid uid, float environmentPressure) + { + var highPressureEvent = new HighPressureEvent(environmentPressure); + RaiseLocalEvent(uid, highPressureEvent, false); + + return CalculateFeltPressure(environmentPressure, highPressureEvent); + } + + public override void Update(float frameTime) + { + _timer += frameTime; + + if (_timer < UpdateTimer) + return; + + _timer -= UpdateTimer; + + foreach (var (barotrauma, transform) in ComponentManager.EntityQuery()) + { + var uid = barotrauma.Owner.Uid; + + var status = barotrauma.Owner.GetComponentOrNull(); + + var pressure = 1f; + + if (_atmosphereSystem.GetTileMixture(transform.Coordinates) is { } mixture) + { + pressure = MathF.Max(mixture.Pressure, 1f);; + } + + switch (pressure) + { + // Low pressure. + case <= Atmospherics.WarningLowPressure: + pressure = GetFeltLowPressure(uid, pressure); + + if (pressure > Atmospherics.WarningLowPressure) + goto default; + + // Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear. + _damageableSystem.TryChangeDamage(uid, barotrauma.Damage * Atmospherics.LowPressureDamage, true); + + if (status == null) break; + + if (pressure <= Atmospherics.HazardLowPressure) + { + status.ShowAlert(AlertType.LowPressure, 2); + break; + } + + status.ShowAlert(AlertType.LowPressure, 1); + break; + + // High pressure. + case >= Atmospherics.WarningHighPressure: + pressure = GetFeltHighPressure(uid, pressure); + + if(pressure < Atmospherics.WarningHighPressure) + goto default; + + var damageScale = (int) MathF.Min((pressure / Atmospherics.HazardHighPressure) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage); + + // Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear. + _damageableSystem.TryChangeDamage(uid, barotrauma.Damage * damageScale, true); + + if (status == null) break; + + if (pressure >= Atmospherics.HazardHighPressure) + { + status.ShowAlert(AlertType.HighPressure, 2); + break; + } + + status.ShowAlert(AlertType.HighPressure, 1); + break; + + // Normal pressure. + default: + status?.ClearAlertCategory(AlertCategory.Pressure); + break; + } + } + } + } +} diff --git a/Content.Server/Atmos/PressureEvent.cs b/Content.Server/Atmos/PressureEvent.cs new file mode 100644 index 0000000000..57cf060df1 --- /dev/null +++ b/Content.Server/Atmos/PressureEvent.cs @@ -0,0 +1,46 @@ +using Robust.Shared.GameObjects; + +namespace Content.Server.Atmos +{ + public abstract class PressureEvent : EntityEventArgs + { + /// + /// The environment pressure. + /// + public float Pressure { get; } + + /// + /// The modifier for the apparent pressure. + /// This number will be added to the environment pressure for calculation purposes. + /// It can be negative to reduce the felt pressure, or positive to increase it. + /// + /// + /// Do not set this directly. Add to it, or subtract from it to modify it. + /// + public float Modifier { get; set; } = 0f; + + /// + /// The multiplier for the apparent pressure. + /// The environment pressure will be multiplied by this for calculation purposes. + /// + /// + /// Do not set, add to or subtract from this directly. Multiply this by your multiplier only. + /// + public float Multiplier { get; set; } = 1f; + + protected PressureEvent(float pressure) + { + Pressure = pressure; + } + } + + public class LowPressureEvent : PressureEvent + { + public LowPressureEvent(float pressure) : base(pressure) { } + } + + public class HighPressureEvent : PressureEvent + { + public HighPressureEvent(float pressure) : base(pressure) { } + } +} diff --git a/Content.Server/Inventory/Components/InventoryComponent.cs b/Content.Server/Inventory/Components/InventoryComponent.cs index 66746b0dec..37983eadfd 100644 --- a/Content.Server/Inventory/Components/InventoryComponent.cs +++ b/Content.Server/Inventory/Components/InventoryComponent.cs @@ -7,7 +7,6 @@ using Content.Server.Clothing.Components; using Content.Server.Hands.Components; using Content.Server.Interaction; using Content.Server.Items; -using Content.Server.Pressure; using Content.Server.Storage.Components; using Content.Shared.ActionBlocker; using Content.Shared.Acts; @@ -38,7 +37,7 @@ namespace Content.Server.Inventory.Components { [RegisterComponent] [ComponentReference(typeof(SharedInventoryComponent))] - public class InventoryComponent : SharedInventoryComponent, IExAct, IPressureProtection, IEffectBlocker + public class InventoryComponent : SharedInventoryComponent, IExAct, IEffectBlocker { [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; @@ -63,52 +62,6 @@ namespace Content.Server.Inventory.Components } } - // Optimization: Cache this - [ViewVariables] - public float HighPressureMultiplier - { - get - { - var multiplier = 1f; - - foreach (var (slot, containerSlot) in _slotContainers) - { - foreach (var entity in containerSlot.ContainedEntities) - { - foreach (var protection in entity.GetAllComponents()) - { - multiplier *= protection.HighPressureMultiplier; - } - } - } - - return multiplier; - } - } - - // Optimization: Cache this - [ViewVariables] - public float LowPressureMultiplier - { - get - { - var multiplier = 1f; - - foreach (var (slot, containerSlot) in _slotContainers) - { - foreach (var entity in containerSlot.ContainedEntities) - { - foreach (var protection in entity.GetAllComponents()) - { - multiplier *= protection.LowPressureMultiplier; - } - } - } - - return multiplier; - } - } - public override float WalkSpeedModifier { get diff --git a/Content.Server/Inventory/InventorySystem.cs b/Content.Server/Inventory/InventorySystem.cs index 79f2767089..a9210797df 100644 --- a/Content.Server/Inventory/InventorySystem.cs +++ b/Content.Server/Inventory/InventorySystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Atmos; using Content.Server.Inventory.Components; using Robust.Shared.Containers; using Robust.Shared.GameObjects; @@ -12,6 +13,8 @@ namespace Content.Server.Inventory SubscribeLocalEvent(HandleRemovedFromContainer); SubscribeLocalEvent(HandleInvRemovedFromContainer); + SubscribeLocalEvent(OnHighPressureEvent); + SubscribeLocalEvent(OnLowPressureEvent); } private static void HandleInvRemovedFromContainer(EntityUid uid, InventoryComponent component, EntRemovedFromContainerMessage args) @@ -23,5 +26,23 @@ namespace Content.Server.Inventory { component.CheckUniformExists(); } + + private void OnHighPressureEvent(EntityUid uid, InventoryComponent component, HighPressureEvent args) + { + RelayPressureEvent(component, args); + } + + private void OnLowPressureEvent(EntityUid uid, InventoryComponent component, LowPressureEvent args) + { + RelayPressureEvent(component, args); + } + + private void RelayPressureEvent(InventoryComponent component, T args) where T : PressureEvent + { + foreach (var equipped in component.GetAllHeldItems()) + { + RaiseLocalEvent(equipped.Uid, args, false); + } + } } } diff --git a/Content.Server/Pressure/IPressureProtection.cs b/Content.Server/Pressure/IPressureProtection.cs deleted file mode 100644 index fb033b9f55..0000000000 --- a/Content.Server/Pressure/IPressureProtection.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Content.Server.Pressure -{ - public interface IPressureProtection - { - public float HighPressureMultiplier { get; } - public float LowPressureMultiplier { get; } - } -}