From 6c85e1b255167e33944489cce9ac8130a5bab21e Mon Sep 17 00:00:00 2001 From: Alain Siegrist Date: Fri, 15 Apr 2022 23:17:48 +0200 Subject: [PATCH] Prevent closed drinks from transferring reagents (#7329) * Prevent closed drinks from transferring reagents * Inherit from cancellable event --- .../Components/SolutionTransferComponent.cs | 39 +-------- .../EntitySystems/SolutionTransferSystem.cs | 82 +++++++++++++++++++ .../Nutrition/EntitySystems/DrinkSystem.cs | 25 +++--- 3 files changed, 100 insertions(+), 46 deletions(-) diff --git a/Content.Server/Chemistry/Components/SolutionTransferComponent.cs b/Content.Server/Chemistry/Components/SolutionTransferComponent.cs index 9ebabd968a..c77f1af258 100644 --- a/Content.Server/Chemistry/Components/SolutionTransferComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionTransferComponent.cs @@ -113,12 +113,12 @@ namespace Content.Server.Chemistry.Components async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { - var solutionsSys = EntitySystem.Get(); - if (!eventArgs.CanReach || eventArgs.Target == null) return false; var target = eventArgs.Target!.Value; + var solutionsSys = EntitySystem.Get(); + var transferSystem = EntitySystem.Get(); //Special case for reagent tanks, because normally clicking another container will give solution, not take it. if (CanReceive && !_entities.HasComponent(target) // target must not be refillable (e.g. Reagent Tanks) @@ -135,7 +135,7 @@ namespace Content.Server.Chemistry.Components transferAmount = FixedPoint2.Min(transferAmount, (FixedPoint2) refill.MaxRefill); // if the receiver has a smaller transfer limit, use that instead } - var transferred = DoTransfer(eventArgs.User, target, targetDrain, Owner, ownerRefill, transferAmount); + var transferred = transferSystem.Transfer(eventArgs.User, target, targetDrain, Owner, ownerRefill, transferAmount); if (transferred > 0) { var toTheBrim = ownerRefill.AvailableVolume == 0; @@ -160,7 +160,7 @@ namespace Content.Server.Chemistry.Components transferAmount = FixedPoint2.Min(transferAmount, (FixedPoint2) refill.MaxRefill); } - var transferred = DoTransfer(eventArgs.User, Owner, ownerDrain, target, targetRefill, transferAmount); + var transferred = transferSystem.Transfer(eventArgs.User, Owner, ownerDrain, target, targetRefill, transferAmount); if (transferred > 0) { @@ -175,36 +175,5 @@ namespace Content.Server.Chemistry.Components return false; } - - /// The actual amount transferred. - private static FixedPoint2 DoTransfer(EntityUid user, - EntityUid sourceEntity, - Solution source, - EntityUid targetEntity, - Solution target, - FixedPoint2 amount) - { - - if (source.DrainAvailable == 0) - { - sourceEntity.PopupMessage(user, - Loc.GetString("comp-solution-transfer-is-empty", ("target", sourceEntity))); - return FixedPoint2.Zero; - } - - if (target.AvailableVolume == 0) - { - targetEntity.PopupMessage(user, - Loc.GetString("comp-solution-transfer-is-full", ("target", targetEntity))); - return FixedPoint2.Zero; - } - - var actualAmount = FixedPoint2.Min(amount, FixedPoint2.Min(source.DrainAvailable, target.AvailableVolume)); - - var solution = EntitySystem.Get().Drain(sourceEntity, source, actualAmount); - EntitySystem.Get().Refill(targetEntity, target, solution); - - return actualAmount; - } } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs index d46bea667d..e067351f1b 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs @@ -5,6 +5,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.Localization; using Robust.Server.GameObjects; using System.Collections.Generic; +using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Content.Shared.Popups; @@ -66,5 +67,86 @@ namespace Content.Server.Chemistry.EntitySystems args.Verbs.Add(verb); } } + + /// + /// Transfer from a solution to another. + /// + /// The actual amount transferred. + public FixedPoint2 Transfer(EntityUid user, + EntityUid sourceEntity, + Solution source, + EntityUid targetEntity, + Solution target, + FixedPoint2 amount) + { + var transferAttempt = new SolutionTransferAttemptEvent(sourceEntity, targetEntity); + + // Check if the source is cancelling the transfer + RaiseLocalEvent(sourceEntity, transferAttempt); + if (transferAttempt.Cancelled) + { + sourceEntity.PopupMessage(user, transferAttempt.CancelReason!); + return FixedPoint2.Zero; + } + + if (source.DrainAvailable == 0) + { + sourceEntity.PopupMessage(user, + Loc.GetString("comp-solution-transfer-is-empty", ("target", sourceEntity))); + return FixedPoint2.Zero; + } + + // Check if the target is cancelling the transfer + RaiseLocalEvent(targetEntity, transferAttempt); + if (transferAttempt.Cancelled) + { + sourceEntity.PopupMessage(user, transferAttempt.CancelReason!); + return FixedPoint2.Zero; + } + + if (target.AvailableVolume == 0) + { + targetEntity.PopupMessage(user, + Loc.GetString("comp-solution-transfer-is-full", ("target", targetEntity))); + return FixedPoint2.Zero; + } + + var actualAmount = FixedPoint2.Min(amount, FixedPoint2.Min(source.DrainAvailable, target.AvailableVolume)); + + var solutionSystem = Get(); + var solution = solutionSystem.Drain(sourceEntity, source, actualAmount); + solutionSystem.Refill(targetEntity, target, solution); + + return actualAmount; + } + } + + /// + /// Raised when attempting to transfer from one solution to another. + /// + public sealed class SolutionTransferAttemptEvent : CancellableEntityEventArgs + { + public SolutionTransferAttemptEvent(EntityUid from, EntityUid to) + { + From = from; + To = to; + } + + public EntityUid From { get; } + public EntityUid To { get; } + + /// + /// Why the transfer has been cancelled. + /// + public string? CancelReason { get; private set; } + + /// + /// Cancels the transfer. + /// + public void Cancel(string reason) + { + base.Cancel(); + CancelReason = reason; + } } } diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index fa23e907ce..d2319d0b28 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -54,6 +54,7 @@ namespace Content.Server.Nutrition.EntitySystems SubscribeLocalEvent(OnUse); SubscribeLocalEvent(AfterInteract); SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnTransferAttempt); SubscribeLocalEvent(OnDrink); SubscribeLocalEvent(OnDrinkCancelled); } @@ -94,17 +95,6 @@ namespace Content.Server.Nutrition.EntitySystems { appearance.SetData(DrinkCanStateVisual.Opened, opened); } - - if (opened) - { - EntityManager.EnsureComponent(uid).Solution= component.SolutionName; - EntityManager.EnsureComponent(uid).Solution= component.SolutionName; - } - else - { - EntityManager.RemoveComponent(uid); - EntityManager.RemoveComponent(uid); - } } private void AfterInteract(EntityUid uid, DrinkComponent component, AfterInteractEvent args) @@ -163,6 +153,10 @@ namespace Content.Server.Nutrition.EntitySystems } UpdateAppearance(component); + + // Synchronize solution in drink + EnsureComp(uid).Solution = component.SolutionName; + EnsureComp(uid).Solution = component.SolutionName; } private void OnSolutionChange(EntityUid uid, DrinkComponent component, SolutionChangedEvent args) @@ -183,6 +177,15 @@ namespace Content.Server.Nutrition.EntitySystems appearance.SetData(DrinkCanStateVisual.Opened, component.Opened); } + private void OnTransferAttempt(EntityUid uid, DrinkComponent component, SolutionTransferAttemptEvent args) + { + if (!component.Opened) + { + args.Cancel(Loc.GetString("drink-component-try-use-drink-not-open", + ("owner", EntityManager.GetComponent(component.Owner).EntityName))); + } + } + private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink) { // cannot stack do-afters