-
Notifications
You must be signed in to change notification settings - Fork 371
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cherry pick "fix solution contents duplication on spill behavior" (#3…
…3231) (#2157) I’M SCREAMING INTO THE VOID AND IT’S NOT LISTENING
- Loading branch information
Showing
1 changed file
with
49 additions
and
31 deletions.
There are no files selected for viewing
80 changes: 49 additions & 31 deletions
80
Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,60 @@ | ||
using Content.Shared.Chemistry.EntitySystems; | ||
using Content.Server.Fluids.EntitySystems; | ||
using Content.Shared.Chemistry.Components; | ||
using Content.Shared.Chemistry.EntitySystems; | ||
using Content.Shared.Fluids.Components; | ||
using JetBrains.Annotations; | ||
|
||
namespace Content.Server.Destructible.Thresholds.Behaviors | ||
namespace Content.Server.Destructible.Thresholds.Behaviors; | ||
|
||
[UsedImplicitly] | ||
[DataDefinition] | ||
public sealed partial class SpillBehavior : IThresholdBehavior | ||
{ | ||
[UsedImplicitly] | ||
[DataDefinition] | ||
public sealed partial class SpillBehavior : IThresholdBehavior | ||
{ | ||
[DataField] | ||
public string? Solution; | ||
/// <summary> | ||
/// Optional fallback solution name if SpillableComponent is not present. | ||
/// </summary> | ||
[DataField] | ||
public string? Solution; | ||
|
||
/// <summary> | ||
/// If there is a SpillableComponent on EntityUidowner use it to create a puddle/smear. | ||
/// Or whatever solution is specified in the behavior itself. | ||
/// If none are available do nothing. | ||
/// </summary> | ||
/// <param name="owner">Entity on which behavior is executed</param> | ||
/// <param name="system">system calling the behavior</param> | ||
/// <param name="cause"></param> | ||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) | ||
{ | ||
var solutionContainerSystem = system.EntityManager.System<SharedSolutionContainerSystem>(); | ||
var spillableSystem = system.EntityManager.System<PuddleSystem>(); | ||
/// <summary> | ||
/// When triggered, spills the entity's solution onto the ground. | ||
/// Will first try to use the solution from a SpillableComponent if present, | ||
/// otherwise falls back to the solution specified in the behavior's data fields. | ||
/// The solution is properly drained/split before spilling to prevent double-spilling with other behaviors. | ||
/// </summary> | ||
/// <param name="owner">Entity whose solution will be spilled</param> | ||
/// <param name="system">System calling this behavior</param> | ||
/// <param name="cause">Optional entity that caused this behavior to trigger</param> | ||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) | ||
{ | ||
var solutionContainerSystem = system.EntityManager.System<SharedSolutionContainerSystem>(); | ||
var spillableSystem = system.EntityManager.System<PuddleSystem>(); | ||
var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates; | ||
|
||
var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates; | ||
Solution targetSolution; | ||
|
||
if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) && | ||
solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out _, out var compSolution)) | ||
{ | ||
spillableSystem.TrySplashSpillAt(owner, coordinates, compSolution, out _, false, user: cause); | ||
} | ||
else if (Solution != null && | ||
solutionContainerSystem.TryGetSolution(owner, Solution, out _, out var behaviorSolution)) | ||
{ | ||
spillableSystem.TrySplashSpillAt(owner, coordinates, behaviorSolution, out _, user: cause); | ||
} | ||
// First try to get solution from SpillableComponent | ||
if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) && | ||
solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out var solution, out var compSolution)) | ||
{ | ||
// If entity is drainable, drain the solution. Otherwise just split it. | ||
// Both methods ensure the solution is properly removed. | ||
targetSolution = system.EntityManager.HasComponent<DrainableSolutionComponent>(owner) | ||
? solutionContainerSystem.Drain((owner, system.EntityManager.GetComponent<DrainableSolutionComponent>(owner)), solution.Value, compSolution.Volume) | ||
: compSolution.SplitSolution(compSolution.Volume); | ||
} | ||
// Fallback to solution specified in behavior data | ||
else if (Solution != null && | ||
solutionContainerSystem.TryGetSolution(owner, Solution, out var solutionEnt, out var behaviorSolution)) | ||
{ | ||
targetSolution = system.EntityManager.HasComponent<DrainableSolutionComponent>(owner) | ||
? solutionContainerSystem.Drain((owner, system.EntityManager.GetComponent<DrainableSolutionComponent>(owner)), solutionEnt.Value, behaviorSolution.Volume) | ||
: behaviorSolution.SplitSolution(behaviorSolution.Volume); | ||
} | ||
else | ||
return; | ||
|
||
// Spill the solution that was drained/split | ||
spillableSystem.TrySplashSpillAt(owner, coordinates, targetSolution, out _, false, cause); | ||
} | ||
} |