Skip to content
Merged
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
92 changes: 92 additions & 0 deletions Content.Server/Chemistry/EntitySystems/TankLeakSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using Content.Server.Fluids.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Popups;

namespace Content.Server.Chemistry.EntitySystems;

public sealed class TankLeakSystem : EntitySystem
{
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly PuddleSystem _puddle = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;

private const float LeakInterval = 1f;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TankLeakComponent, ComponentStartup>(OnStartup);
}

private void OnStartup(EntityUid uid, TankLeakComponent comp, ComponentStartup args)
{
comp.LeakAccumulator = 0f;
}

public void AddLeak(EntityUid uid, TankLeakComponent? comp = null)
{
if (!Resolve(uid, ref comp, false))
comp = EnsureComp<TankLeakComponent>(uid);

comp.LeakCount++;
Dirty(uid, comp);

_popup.PopupEntity(
Loc.GetString("tank-leak-popup", ("entity", uid)),
uid,
PopupType.SmallCaution);

if (comp.LeakCount >= comp.MaxLeaks)
{
_popup.PopupEntity(
Loc.GetString("tank-leak-destroy-popup", ("entity", uid)),
uid,
PopupType.MediumCaution);

if (_solutionContainer.TryGetSolution(uid, comp.Solution, out _, out var solution))
{
var coords = Transform(uid).Coordinates;
_puddle.TrySpillAt(coords, solution, out _);
}

QueueDel(uid);
}
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var query = EntityQueryEnumerator<TankLeakComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (comp.LeakCount <= 0)
continue;

comp.LeakAccumulator += frameTime;
if (comp.LeakAccumulator < LeakInterval)
continue;

comp.LeakAccumulator -= LeakInterval;

var leakAmount = comp.LeakRatePerHole * comp.LeakCount;

Comment on lines +67 to +74

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Пропускаются интервалы утечки при просадке frameTime.

Сейчас за апдейт обрабатывается только один тик утечки, поэтому при frameTime > 1f фактическая скорость течи становится ниже ожидаемой. Нужно учитывать все накопленные интервалы за кадр.

💡 Предлагаемое исправление
-            comp.LeakAccumulator += frameTime;
-            if (comp.LeakAccumulator < LeakInterval)
-                continue;
-
-            comp.LeakAccumulator -= LeakInterval;
-
-            var leakAmount = comp.LeakRatePerHole * comp.LeakCount;
+            comp.LeakAccumulator += frameTime;
+            var intervals = (int)(comp.LeakAccumulator / LeakInterval);
+            if (intervals <= 0)
+                continue;
+
+            comp.LeakAccumulator -= intervals * LeakInterval;
+
+            var leakAmount = comp.LeakRatePerHole * comp.LeakCount * intervals;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Server/Chemistry/EntitySystems/TankLeakSystem.cs` around lines 67 -
74, The leak interval processing in TankLeakSystem.cs currently only handles one
leak tick per frame update, causing the actual leak rate to be lower than
expected when frameTime is large. Replace the single if check for
comp.LeakAccumulator < LeakInterval with a while loop that continues to process
and subtract LeakInterval from comp.LeakAccumulator for each accumulated
interval, ensuring that all accumulated leak intervals within a single frame are
properly accounted for in the leakAmount calculation.

if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out var soln, out var solution))
continue;

if (solution.Volume <= 0)
continue;

if (leakAmount > solution.Volume)
leakAmount = solution.Volume;

var leaked = _solutionContainer.SplitSolution(soln.Value, leakAmount);
if (leaked.Volume <= 0)
continue;

var coords = Transform(uid).Coordinates;
_puddle.TrySpillAt(coords, leaked, out _, sound: false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Components;
using JetBrains.Annotations;

namespace Content.Server.Destructible.Thresholds.Behaviors;

[UsedImplicitly]
[DataDefinition]
public sealed partial class TankLeakBehavior : IThresholdBehavior
{
[DataField]
public int LeaksToAdd = 1;

[DataField]
public string Solution = "tank";

public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
{
var tankLeakSystem = system.EntityManager.System<TankLeakSystem>();

var comp = system.EntityManager.EnsureComponent<TankLeakComponent>(owner);
comp.Solution = Solution;

for (var i = 0; i < LeaksToAdd; i++)
{
tankLeakSystem.AddLeak(owner, comp);
}
}
}
21 changes: 21 additions & 0 deletions Content.Server/_NF/Shuttles/Bank/BankSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using Robust.Shared.Network;
using Content.Server.Cargo.Components;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Mind.Components;
using Content.Shared.Mind;

namespace Content.Server.Bank;

Expand All @@ -23,10 +25,29 @@ public override void Initialize()
base.Initialize();
_log = Logger.GetSawmill("bank");
SubscribeLocalEvent<BankAccountComponent, ComponentGetState>(OnBankAccountChanged);
SubscribeLocalEvent<BankAccountComponent, MindAddedMessage>(OnMindAdded);
InitializeATM();
InitializeStationATM();
}

private void OnMindAdded(EntityUid uid, BankAccountComponent bank, ref MindAddedMessage args)
{
var mind = args.Mind.Comp;
if (mind.UserId == null)
return;

var prefs = _prefsManager.GetPreferences(mind.UserId.Value);
if (prefs.SelectedCharacter is not HumanoidCharacterProfile profile)
return;

if (bank.Balance != profile.BankBalance)
{
bank.Balance = profile.BankBalance;
EntityManager.Dirty(uid, bank);
_log.Info($"Mind transfer to {ToPrettyString(uid)}: bank balance reset to profile value {profile.BankBalance}");
}
}

// To ensure that bank account data gets saved, we are going to update the db every time the component changes
// I at first wanted to try to reduce database calls, however notafet suggested I just do it every time the account changes
// TODO: stop it from running 5 times every time
Expand Down
23 changes: 23 additions & 0 deletions Content.Shared/Chemistry/Components/TankLeakComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Content.Shared.FixedPoint;
using Robust.Shared.GameStates;

namespace Content.Shared.Chemistry.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class TankLeakComponent : Component
{
[DataField, AutoNetworkedField]
public int LeakCount;

[DataField]
public FixedPoint2 LeakRatePerHole = FixedPoint2.New(5);

[DataField]
public int MaxLeaks = 5;

[DataField]
public float LeakAccumulator;

[DataField]
public string Solution = "tank";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tank-leak-popup = { CAPITALIZE($entity) } springs a leak!
tank-leak-destroy-popup = { CAPITALIZE($entity) } breaks apart, spilling its contents!
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tank-leak-popup = В { $entity } образовалась дырка!
tank-leak-destroy-popup = { CAPITALIZE($entity) } разваливается, разливая содержимое!
Original file line number Diff line number Diff line change
Expand Up @@ -344,19 +344,19 @@
!type:DamageTrigger
damage: 100
behaviors:
- !type:SpillBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:ChangeConstructionNodeBehavior
node: machineFrame
- !type:DoActsBehavior
acts: ["Destruction"]
- trigger:
!type:DamageTypeTrigger
damageType: Piercing
damage: 75
behaviors:
- !type:SolutionExplosionBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
thresholds:
- trigger:
!type:DamageTrigger
damage: 50
damage: 100
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
Expand All @@ -43,19 +43,19 @@
damageType: Piercing
damage: 5
behaviors:
- !type:SolutionExplosionBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
- trigger:
!type:DamageTrigger
damage: 10
behaviors:
- !type:SpillBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:DoActsBehavior
acts: ["Destruction"]
- type: SolutionContainerManager
solutions:
tank:
Expand Down
21 changes: 16 additions & 5 deletions Resources/Prototypes/Entities/Structures/Storage/barrels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@
damageModifierSet: Metallic
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 100
behaviors:
- !type:SpillBehavior
solution: barrel
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:DoActsBehavior
acts: ["Destruction"]
- trigger:
!type:DamageTypeTrigger
damageType: Heat
Expand All @@ -40,19 +51,19 @@
damageType: Piercing
damage: 5
behaviors:
- !type:SolutionExplosionBehavior
- !type:TankLeakBehavior
solution: barrel
leaksToAdd: 1
- trigger:
!type:DamageTrigger
damage: 50
damage: 10
behaviors:
- !type:SpillBehavior
- !type:TankLeakBehavior
solution: barrel
leaksToAdd: 1
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:DoActsBehavior
acts: ["Destruction"]

# Base Open
- type: entity
Expand Down
8 changes: 4 additions & 4 deletions Resources/Prototypes/Entities/Structures/Storage/tanks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@
damageType: Piercing
damage: 5
behaviors:
- !type:SolutionExplosionBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
- trigger:
!type:DamageTrigger
damage: 10
behaviors:
- !type:SpillBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:DoActsBehavior
acts: ["Destruction"]
- type: SolutionContainerManager
solutions:
tank:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
thresholds:
- trigger:
!type:DamageTrigger
damage: 50
damage: 100
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
Expand All @@ -40,19 +40,19 @@
damageType: Piercing
damage: 5
behaviors:
- !type:SolutionExplosionBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
- trigger:
!type:DamageTrigger
damage: 10
behaviors:
- !type:SpillBehavior
- !type:TankLeakBehavior
solution: tank
leaksToAdd: 1
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:DoActsBehavior
acts: ["Destruction"]
- type: SolutionContainerManager
solutions:
tank:
Expand Down
5 changes: 2 additions & 3 deletions Resources/Prototypes/_Crescent/Power/boriaticgenerators.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,9 @@
collection: MetalBreak
- !type:ChangeConstructionNodeBehavior
node: machineFrame
- !type:DoActsBehavior
- !type:SolutionExplosionBehavior
- !type:TankLeakBehavior
solution: tank
# acts: ["Destruction"] YAMLFIX: This is deprecated
leaksToAdd: 1
- type: GuideHelp
guides: [ PortableGenerator, Power ]

Expand Down
Loading