Cached barotrauma resistance and immunity values instead of computing them each Update() (#15055)

This commit is contained in:
Menshin 2023-04-30 19:58:26 +02:00 committed by GitHub
parent 6492315344
commit 76903dd145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 122 additions and 90 deletions

View File

@ -26,6 +26,25 @@ namespace Content.Server.Atmos.Components
/// These are the inventory slots that are checked for pressure protection. If a slot is missing protection, no protection is applied.
/// </summary>
[DataField("protectionSlots")]
public List<string> ProtectionSlots = new() { "head", "outerClothing" };
public List<string> ProtectionSlots = new() { "head", "outerClothing" };
/// <summary>
/// Cached pressure protection values
/// </summary>
[ViewVariables]
public float HighPressureMultiplier = 1f;
[ViewVariables]
public float HighPressureModifier = 0f;
[ViewVariables]
public float LowPressureMultiplier = 1f;
[ViewVariables]
public float LowPressureModifier = 0f;
/// <summary>
/// Whether the entity is immuned to pressure (i.e possess the PressureImmunity component)
/// </summary>
[ViewVariables]
public bool HasImmunity = false;
}
}

View File

@ -6,6 +6,7 @@ using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Robust.Shared.Containers;
namespace Content.Server.Atmos.EntitySystems
@ -23,124 +24,136 @@ namespace Content.Server.Atmos.EntitySystems
public override void Initialize()
{
SubscribeLocalEvent<PressureProtectionComponent, HighPressureEvent>(OnHighPressureEvent);
SubscribeLocalEvent<PressureProtectionComponent, LowPressureEvent>(OnLowPressureEvent);
SubscribeLocalEvent<PressureImmunityComponent, HighPressureEvent>(OnHighPressureImmuneEvent);
SubscribeLocalEvent<PressureImmunityComponent, LowPressureEvent>(OnLowPressureImmuneEvent);
SubscribeLocalEvent<PressureProtectionComponent, GotEquippedEvent>(OnPressureProtectionEquipped);
SubscribeLocalEvent<PressureProtectionComponent, GotUnequippedEvent>(OnPressureProtectionUnequipped);
SubscribeLocalEvent<PressureProtectionComponent, ComponentInit>(OnUpdateResistance);
SubscribeLocalEvent<PressureProtectionComponent, ComponentRemove>(OnUpdateResistance);
SubscribeLocalEvent<PressureImmunityComponent, ComponentInit>(OnPressureImmuneInit);
SubscribeLocalEvent<PressureImmunityComponent, ComponentRemove>(OnPressureImmuneRemove);
}
private void OnHighPressureEvent(EntityUid uid, PressureProtectionComponent component, HighPressureEvent args)
private void OnPressureImmuneInit(EntityUid uid, PressureImmunityComponent pressureImmunity, ComponentInit args)
{
args.Modifier += component.HighPressureModifier;
args.Multiplier *= component.HighPressureMultiplier;
if (TryComp<BarotraumaComponent>(uid, out var barotrauma))
{
barotrauma.HasImmunity = true;
}
}
private void OnLowPressureEvent(EntityUid uid, PressureProtectionComponent component, LowPressureEvent args)
private void OnPressureImmuneRemove(EntityUid uid, PressureImmunityComponent pressureImmunity, ComponentRemove args)
{
args.Modifier += component.LowPressureModifier;
args.Multiplier *= component.LowPressureMultiplier;
}
/// <summary>
/// Completely prevent high pressure damage
/// </summary>
private void OnHighPressureImmuneEvent(EntityUid uid, PressureImmunityComponent component, HighPressureEvent args)
{
args.Multiplier = 0;
if (TryComp<BarotraumaComponent>(uid, out var barotrauma))
{
barotrauma.HasImmunity = false;
}
}
/// <summary>
/// Completely prevent low pressure damage
/// Generic method for updating resistance on component Lifestage events
/// </summary>
private void OnLowPressureImmuneEvent(EntityUid uid, PressureImmunityComponent component, LowPressureEvent args)
private void OnUpdateResistance(EntityUid uid, PressureProtectionComponent pressureProtection, EntityEventArgs args)
{
args.Modifier = 100;
args.Multiplier = 10000;
if (TryComp<BarotraumaComponent>(uid, out var barotrauma))
{
UpdateCachedResistances(uid, barotrauma);
}
}
public float GetFeltLowPressure(EntityUid uid, BarotraumaComponent baro, float environmentPressure)
private void OnPressureProtectionEquipped(EntityUid uid, PressureProtectionComponent pressureProtection, GotEquippedEvent args)
{
var modifier = float.MaxValue;
var multiplier = float.MaxValue;
TryComp(uid, out InventoryComponent? inv);
TryComp(uid, out ContainerManagerComponent? contMan);
// TODO: cache this & update when equipment changes?
// This continuously raises events for every player in space.
if (baro.ProtectionSlots.Count == 0)
if (TryComp<BarotraumaComponent>(args.Equipee, out var barotrauma) && barotrauma.ProtectionSlots.Contains(args.Slot))
{
modifier = 0;
multiplier = 1;
UpdateCachedResistances(args.Equipee, barotrauma);
}
// First, check if for protective equipment
foreach (var slot in baro.ProtectionSlots)
{
if (!_inventorySystem.TryGetSlotEntity(uid, slot, out var equipment, inv, contMan)
|| ! TryComp(equipment, out PressureProtectionComponent? protection))
{
// Missing protection, skin is exposed.
modifier = 0;
multiplier = 1;
break;
}
modifier = Math.Min(protection.LowPressureModifier, modifier);
multiplier = Math.Min(protection.LowPressureMultiplier, multiplier);
}
// Then apply any generic, non-clothing related modifiers.
var lowPressureEvent = new LowPressureEvent(environmentPressure);
RaiseLocalEvent(uid, lowPressureEvent);
return (environmentPressure + modifier + lowPressureEvent.Modifier)
* (multiplier * lowPressureEvent.Multiplier);
}
public float GetFeltHighPressure(EntityUid uid, BarotraumaComponent baro, float environmentPressure)
private void OnPressureProtectionUnequipped(EntityUid uid, PressureProtectionComponent pressureProtection, GotUnequippedEvent args)
{
var modifier = float.MinValue;
var multiplier = float.MinValue;
TryComp(uid, out InventoryComponent? inv);
TryComp(uid, out ContainerManagerComponent? contMan);
// TODO: cache this & update when equipment changes?
// Not as import and as low-pressure, but probably still useful.
if (baro.ProtectionSlots.Count == 0)
if (TryComp<BarotraumaComponent>(args.Equipee, out var barotrauma) && barotrauma.ProtectionSlots.Contains(args.Slot))
{
modifier = 0;
multiplier = 1;
UpdateCachedResistances(args.Equipee, barotrauma);
}
}
// First, check if for protective equipment
foreach (var slot in baro.ProtectionSlots)
/// <summary>
/// Computes the pressure resistance for the entity coming from the equipment and any innate resistance.
/// The ProtectionSlots field of the Barotrauma component specifies which parts must be protected for the protection to have any effet.
/// </summary>
private void UpdateCachedResistances(EntityUid uid, BarotraumaComponent barotrauma)
{
if (barotrauma.ProtectionSlots.Count != 0)
{
if (!_inventorySystem.TryGetSlotEntity(uid, slot, out var equipment, inv, contMan)
|| !TryComp(equipment, out PressureProtectionComponent? protection))
if (!TryComp(uid, out InventoryComponent? inv) || !TryComp(uid, out ContainerManagerComponent? contMan))
{
// Missing protection, skin is exposed.
modifier = 0;
multiplier = 1;
break;
return;
}
var hPModifier = float.MinValue;
var hPMultiplier = float.MinValue;
var lPModifier = float.MaxValue;
var lPMultiplier = float.MaxValue;
foreach (var slot in barotrauma.ProtectionSlots)
{
if (!_inventorySystem.TryGetSlotEntity(uid, slot, out var equipment, inv, contMan)
|| !TryComp(equipment, out PressureProtectionComponent? protection))
{
// Missing protection, skin is exposed.
hPModifier = 0f;
hPMultiplier = 1f;
lPModifier = 0f;
lPMultiplier = 1f;
break;
}
// The entity is as protected as its weakest part protection
hPModifier = Math.Max(hPModifier, protection.HighPressureModifier);
hPMultiplier = Math.Max(hPMultiplier, protection.HighPressureMultiplier);
lPModifier = Math.Min(lPModifier, protection.LowPressureModifier);
lPMultiplier = Math.Min(lPMultiplier, protection.LowPressureMultiplier);
}
modifier = Math.Max(protection.HighPressureModifier, modifier);
multiplier = Math.Max(protection.HighPressureMultiplier, multiplier);
barotrauma.HighPressureModifier = hPModifier;
barotrauma.HighPressureMultiplier = hPMultiplier;
barotrauma.LowPressureModifier = lPModifier;
barotrauma.LowPressureMultiplier = lPMultiplier;
}
// Then apply any generic, non-clothing related modifiers.
var highPressureEvent = new HighPressureEvent(environmentPressure);
RaiseLocalEvent(uid, highPressureEvent);
// any innate pressure resistance ?
if (TryComp<PressureProtectionComponent>(uid, out var innatePressureProtection))
{
barotrauma.HighPressureModifier += innatePressureProtection.HighPressureModifier;
barotrauma.HighPressureMultiplier *= innatePressureProtection.HighPressureMultiplier;
barotrauma.LowPressureModifier += innatePressureProtection.LowPressureModifier;
barotrauma.LowPressureMultiplier *= innatePressureProtection.LowPressureMultiplier;
}
}
return (environmentPressure + modifier + highPressureEvent.Modifier)
* (multiplier * highPressureEvent.Multiplier);
/// <summary>
/// Returns adjusted pressure after having applied resistances from equipment and innate (if any), to check against a low pressure hazard threshold
/// </summary>
public float GetFeltLowPressure(EntityUid uid, BarotraumaComponent barotrauma, float environmentPressure)
{
if (barotrauma.HasImmunity)
{
return Atmospherics.OneAtmosphere;
}
return (environmentPressure + barotrauma.LowPressureModifier) * (barotrauma.LowPressureMultiplier);
}
/// <summary>
/// Returns adjusted pressure after having applied resistances from equipment and innate (if any), to check against a high pressure hazard threshold
/// </summary>
public float GetFeltHighPressure(EntityUid uid, BarotraumaComponent barotrauma, float environmentPressure)
{
if (barotrauma.HasImmunity)
{
return Atmospherics.OneAtmosphere;
}
return (environmentPressure + barotrauma.HighPressureModifier) * (barotrauma.HighPressureMultiplier);
}
public override void Update(float frameTime)
@ -203,7 +216,7 @@ namespace Content.Server.Atmos.EntitySystems
case >= Atmospherics.WarningHighPressure:
pressure = GetFeltHighPressure(uid, barotrauma, pressure);
if(pressure < Atmospherics.WarningHighPressure)
if (pressure < Atmospherics.WarningHighPressure)
goto default;
var damageScale = MathF.Min((pressure / Atmospherics.HazardHighPressure) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage);