From aaffd7e1986a67c3686acbf079d5cd7afbd988ba Mon Sep 17 00:00:00 2001 From: Exp Date: Mon, 10 Aug 2020 16:30:56 +0200 Subject: [PATCH] Chem Master & Dispenser Power Fixes (#1622) * -ChemDispenser & Master can now open the UI without power -Both can also eject beaker without power * -Disables button if not powered -Disables clear & eject buttons if no beaker * Fix server freeze --- .../Chemistry/ChemMaster/ChemMasterWindow.cs | 30 ++++++++++++++- .../ReagentDispenserBoundUserInterface.cs | 2 +- .../ReagentDispenserWindow.cs | 37 +++++++++++++++++++ .../Chemistry/ChemMasterComponent.cs | 36 +++++++++++++----- .../Chemistry/ReagentDispenserComponent.cs | 27 +++++++++----- .../ChemMaster/SharedChemMasterComponent.cs | 6 ++- .../SharedReagentDispenserComponent.cs | 4 +- 7 files changed, 119 insertions(+), 23 deletions(-) diff --git a/Content.Client/GameObjects/Components/Chemistry/ChemMaster/ChemMasterWindow.cs b/Content.Client/GameObjects/Components/Chemistry/ChemMaster/ChemMasterWindow.cs index a204c63124..3a2dece8e9 100644 --- a/Content.Client/GameObjects/Components/Chemistry/ChemMaster/ChemMasterWindow.cs +++ b/Content.Client/GameObjects/Components/Chemistry/ChemMaster/ChemMasterWindow.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Content.Client.UserInterface; @@ -273,6 +273,34 @@ namespace Content.Client.GameObjects.Components.Chemistry.ChemMaster var castState = (ChemMasterBoundUserInterfaceState) state; Title = castState.DispenserName; UpdatePanelInfo(castState); + if (Contents.Children != null) + { + SetButtonDisabledRecursive(Contents, !castState.HasPower); + EjectButton.Disabled = !castState.HasBeaker; + } + } + + /// + /// This searches recursively through all the children of "parent" + /// and sets the Disabled value of any buttons found to "val" + /// + /// The control which childrens get searched + /// The value to which disabled gets set + private void SetButtonDisabledRecursive(Control parent, bool val) + { + foreach (var child in parent.Children) + { + if (child is Button but) + { + but.Disabled = val; + continue; + } + + if (child.Children != null) + { + SetButtonDisabledRecursive(child, val); + } + } } /// diff --git a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs index 8f362cc49a..1aabef19dc 100644 --- a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs +++ b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs @@ -72,8 +72,8 @@ namespace Content.Client.GameObjects.Components.Chemistry var castState = (ReagentDispenserBoundUserInterfaceState)state; _lastState = castState; - _window?.UpdateState(castState); //Update window state UpdateReagentsList(castState.Inventory); //Update reagents list & reagent button actions + _window?.UpdateState(castState); //Update window state } /// diff --git a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs index fade17e84c..66b5fd693f 100644 --- a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs +++ b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs @@ -161,6 +161,29 @@ namespace Content.Client.GameObjects.Components.Chemistry } } + /// + /// This searches recursively through all the children of "parent" + /// and sets the Disabled value of any buttons found to "val" + /// + /// The control which childrens get searched + /// The value to which disabled gets set + private void SetButtonDisabledRecursive(Control parent, bool val) + { + foreach (var child in parent.Children) + { + if (child is Button but) + { + but.Disabled = val; + continue; + } + + if (child.Children != null) + { + SetButtonDisabledRecursive(child, val); + } + } + } + /// /// Update the UI state when new state data is received from the server. /// @@ -171,6 +194,20 @@ namespace Content.Client.GameObjects.Components.Chemistry Title = castState.DispenserName; UpdateContainerInfo(castState); + // Disable all buttons if not powered + if (Contents.Children != null) + { + SetButtonDisabledRecursive(Contents, !castState.HasPower); + EjectButton.Disabled = false; + } + + // Disable the Clear & Eject button if no beaker + if (!castState.HasBeaker) + { + ClearButton.Disabled = true; + EjectButton.Disabled = true; + } + switch (castState.SelectedDispenseAmount.Int()) { case 1: diff --git a/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs index 2f7caaf156..4f20a0c4e9 100644 --- a/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs @@ -83,6 +83,7 @@ namespace Content.Server.GameObjects.Components.Chemistry _beakerContainer = ContainerManagerComponent.Ensure($"{Name}-reagentContainerContainer", Owner); _powerReceiver = Owner.GetComponent(); + _powerReceiver.OnPowerStateChanged += OnPowerChanged; //BufferSolution = Owner.BufferSolution BufferSolution.Solution = new Solution(); @@ -91,6 +92,11 @@ namespace Content.Server.GameObjects.Components.Chemistry UpdateUserInterface(); } + private void OnPowerChanged(object sender, PowerStateEventArgs e) + { + UpdateUserInterface(); + } + /// /// Handles ui messages from the client. For things such as button presses /// which interact with the world and require server action. @@ -98,10 +104,16 @@ namespace Content.Server.GameObjects.Components.Chemistry /// A user interface message from the client. private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { - if (!PlayerCanUseChemMaster(obj.Session.AttachedEntity)) + var msg = (UiActionMessage) obj.Message; + var needsPower = msg.action switch + { + UiAction.Eject => false, + _ => true, + }; + + if (!PlayerCanUseChemMaster(obj.Session.AttachedEntity, needsPower)) return; - var msg = (UiActionMessage) obj.Message; switch (msg.action) { case UiAction.Eject: @@ -134,7 +146,7 @@ namespace Content.Server.GameObjects.Components.Chemistry /// /// The player entity. /// Returns true if the entity can use the chem master, and false if it cannot. - private bool PlayerCanUseChemMaster(IEntity playerEntity) + private bool PlayerCanUseChemMaster(IEntity playerEntity, bool needsPower = true) { //Need player entity to check if they are still able to use the chem master if (playerEntity == null) @@ -143,7 +155,7 @@ namespace Content.Server.GameObjects.Components.Chemistry if (!ActionBlockerSystem.CanInteract(playerEntity) || !ActionBlockerSystem.CanUse(playerEntity)) return false; //Check if device is powered - if (!Powered) + if (needsPower && !Powered) return false; return true; @@ -158,12 +170,12 @@ namespace Content.Server.GameObjects.Components.Chemistry var beaker = _beakerContainer.ContainedEntity; if (beaker == null) { - return new ChemMasterBoundUserInterfaceState(false, ReagentUnit.New(0), ReagentUnit.New(0), + return new ChemMasterBoundUserInterfaceState(Powered, false, ReagentUnit.New(0), ReagentUnit.New(0), "", Owner.Name, null, BufferSolution.ReagentList.ToList(), BufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume); } var solution = beaker.GetComponent(); - return new ChemMasterBoundUserInterfaceState(true, solution.CurrentVolume, solution.MaxVolume, + return new ChemMasterBoundUserInterfaceState(Powered, true, solution.CurrentVolume, solution.MaxVolume, beaker.Name, Owner.Name, solution.ReagentList.ToList(), BufferSolution.ReagentList.ToList(), BufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume); } @@ -252,9 +264,15 @@ namespace Content.Server.GameObjects.Components.Chemistry { var random = IoCManager.Resolve(); + if (BufferSolution.CurrentVolume == 0) + return; + if (action == UiAction.CreateBottles) { var individualVolume = BufferSolution.CurrentVolume / ReagentUnit.New(bottleAmount); + if (individualVolume < ReagentUnit.New(1)) + return; + var actualVolume = ReagentUnit.Min(individualVolume, ReagentUnit.New(30)); for (int i = 0; i < bottleAmount; i++) { @@ -289,6 +307,9 @@ namespace Content.Server.GameObjects.Components.Chemistry else //Pills { var individualVolume = BufferSolution.CurrentVolume / ReagentUnit.New(pillAmount); + if (individualVolume < ReagentUnit.New(1)) + return; + var actualVolume = ReagentUnit.Min(individualVolume, ReagentUnit.New(50)); for (int i = 0; i < pillAmount; i++) { @@ -341,9 +362,6 @@ namespace Content.Server.GameObjects.Components.Chemistry return; } - if (!Powered) - return; - var activeHandEntity = hands.GetActiveHand?.Owner; if (activeHandEntity == null) { diff --git a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs index f9a698e717..a9c384dafb 100644 --- a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs @@ -80,6 +80,7 @@ namespace Content.Server.GameObjects.Components.Chemistry _beakerContainer = ContainerManagerComponent.Ensure($"{Name}-reagentContainerContainer", Owner); _powerReceiver = Owner.GetComponent(); + _powerReceiver.OnPowerStateChanged += OnPowerChanged; InitializeFromPrototype(); UpdateUserInterface(); @@ -105,6 +106,11 @@ namespace Content.Server.GameObjects.Components.Chemistry } } + private void OnPowerChanged(object sender, PowerStateEventArgs e) + { + UpdateUserInterface(); + } + /// /// Handles ui messages from the client. For things such as button presses /// which interact with the world and require server action. @@ -112,10 +118,16 @@ namespace Content.Server.GameObjects.Components.Chemistry /// A user interface message from the client. private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { - if(!PlayerCanUseDispenser(obj.Session.AttachedEntity)) + var msg = (UiButtonPressedMessage) obj.Message; + var needsPower = msg.Button switch + { + UiButton.Eject => false, + _ => true, + }; + + if(!PlayerCanUseDispenser(obj.Session.AttachedEntity, needsPower)) return; - var msg = (UiButtonPressedMessage) obj.Message; switch (msg.Button) { case UiButton.Eject: @@ -161,7 +173,7 @@ namespace Content.Server.GameObjects.Components.Chemistry /// /// The player entity. /// Returns true if the entity can use the dispenser, and false if it cannot. - private bool PlayerCanUseDispenser(IEntity playerEntity) + private bool PlayerCanUseDispenser(IEntity playerEntity, bool needsPower = true) { //Need player entity to check if they are still able to use the dispenser if (playerEntity == null) @@ -170,7 +182,7 @@ namespace Content.Server.GameObjects.Components.Chemistry if (!ActionBlockerSystem.CanInteract(playerEntity) || !ActionBlockerSystem.CanUse(playerEntity)) return false; //Check if device is powered - if (!Powered) + if (needsPower && !Powered) return false; return true; @@ -185,12 +197,12 @@ namespace Content.Server.GameObjects.Components.Chemistry var beaker = _beakerContainer.ContainedEntity; if (beaker == null) { - return new ReagentDispenserBoundUserInterfaceState(false, ReagentUnit.New(0), ReagentUnit.New(0), + return new ReagentDispenserBoundUserInterfaceState(Powered, false, ReagentUnit.New(0), ReagentUnit.New(0), "", Inventory, Owner.Name, null, _dispenseAmount); } var solution = beaker.GetComponent(); - return new ReagentDispenserBoundUserInterfaceState(true, solution.CurrentVolume, solution.MaxVolume, + return new ReagentDispenserBoundUserInterfaceState(Powered, true, solution.CurrentVolume, solution.MaxVolume, beaker.Name, Inventory, Owner.Name, solution.ReagentList.ToList(), _dispenseAmount); } @@ -263,9 +275,6 @@ namespace Content.Server.GameObjects.Components.Chemistry return; } - if (!Powered) - return; - var activeHandEntity = hands.GetActiveHand?.Owner; if (activeHandEntity == null) { diff --git a/Content.Shared/GameObjects/Components/Chemistry/ChemMaster/SharedChemMasterComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/ChemMaster/SharedChemMasterComponent.cs index 793e842886..8a4f630fb0 100644 --- a/Content.Shared/GameObjects/Components/Chemistry/ChemMaster/SharedChemMasterComponent.cs +++ b/Content.Shared/GameObjects/Components/Chemistry/ChemMaster/SharedChemMasterComponent.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Collections.Generic; using Content.Shared.Chemistry; @@ -19,6 +19,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry [Serializable, NetSerializable] public class ChemMasterBoundUserInterfaceState : BoundUserInterfaceState { + public readonly bool HasPower; public readonly bool HasBeaker; public readonly ReagentUnit BeakerCurrentVolume; public readonly ReagentUnit BeakerMaxVolume; @@ -39,9 +40,10 @@ namespace Content.Shared.GameObjects.Components.Chemistry public readonly ReagentUnit BufferCurrentVolume; public readonly ReagentUnit BufferMaxVolume; - public ChemMasterBoundUserInterfaceState(bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName, + public ChemMasterBoundUserInterfaceState(bool hasPower, bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName, string dispenserName, List containerReagents, List bufferReagents, bool bufferModeTransfer, ReagentUnit bufferCurrentVolume, ReagentUnit bufferMaxVolume) { + HasPower = hasPower; HasBeaker = hasBeaker; BeakerCurrentVolume = beakerCurrentVolume; BeakerMaxVolume = beakerMaxVolume; diff --git a/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs index d9ff0581dd..b2d094a5d0 100644 --- a/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs +++ b/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs @@ -25,6 +25,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry [Serializable, NetSerializable] public class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState { + public readonly bool HasPower; public readonly bool HasBeaker; public readonly ReagentUnit BeakerCurrentVolume; public readonly ReagentUnit BeakerMaxVolume; @@ -40,9 +41,10 @@ namespace Content.Shared.GameObjects.Components.Chemistry public readonly string DispenserName; public readonly ReagentUnit SelectedDispenseAmount; - public ReagentDispenserBoundUserInterfaceState(bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName, + public ReagentDispenserBoundUserInterfaceState(bool hasPower, bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName, List inventory, string dispenserName, List containerReagents, ReagentUnit selectedDispenseAmount) { + HasPower = hasPower; HasBeaker = hasBeaker; BeakerCurrentVolume = beakerCurrentVolume; BeakerMaxVolume = beakerMaxVolume;