diff --git a/Content.Server/Body/Behavior/LungBehavior.cs b/Content.Server/Body/Behavior/LungBehavior.cs index 9d05881698..0e027f1152 100644 --- a/Content.Server/Body/Behavior/LungBehavior.cs +++ b/Content.Server/Body/Behavior/LungBehavior.cs @@ -3,6 +3,7 @@ using Content.Server.Atmos; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Popups; using Content.Shared.Atmos; using Content.Shared.Body.Components; @@ -188,7 +189,7 @@ namespace Content.Server.Body.Behavior return; } - bloodstream.PumpToxins(Air); + EntitySystem.Get().PumpToxins(Body.OwnerUid, Air, bloodstream); var lungRemoved = Air.RemoveRatio(0.5f); EntitySystem.Get().Merge(to, lungRemoved); diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Server/Body/Components/BloodstreamComponent.cs index 603a961bbd..ebaade62d6 100644 --- a/Content.Server/Body/Components/BloodstreamComponent.cs +++ b/Content.Server/Body/Components/BloodstreamComponent.cs @@ -1,104 +1,34 @@ -using System; using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Systems; -using Content.Server.Chemistry.EntitySystems; using Content.Shared.Atmos; -using Content.Shared.Body.Components; using Content.Shared.Chemistry.Components; using Content.Shared.FixedPoint; +using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; namespace Content.Server.Body.Components { - [RegisterComponent] - [ComponentReference(typeof(SharedBloodstreamComponent))] - public class BloodstreamComponent : SharedBloodstreamComponent, IGasMixtureHolder + [RegisterComponent, Friend(typeof(BloodstreamSystem))] + public class BloodstreamComponent : Component, IGasMixtureHolder { public override string Name => "Bloodstream"; /// /// Max volume of internal solution storage /// - [DataField("maxVolume")] [ViewVariables] - private FixedPoint2 _initialMaxVolume = FixedPoint2.New(250); + [DataField("maxVolume")] + public FixedPoint2 InitialMaxVolume = FixedPoint2.New(250); /// /// Internal solution for reagent storage /// - [ViewVariables] private Solution? _internalSolution; - - /// - /// Empty volume of internal solution - /// - [ViewVariables] - public FixedPoint2 EmptyVolume => _internalSolution?.AvailableVolume ?? FixedPoint2.Zero; + [ViewVariables(VVAccess.ReadWrite)] + public Solution Solution = default!; [ViewVariables] public GasMixture Air { get; set; } = new(6) { Temperature = Atmospherics.NormalBodyTemperature }; - - protected override void Initialize() - { - base.Initialize(); - - _internalSolution = EntitySystem.Get().EnsureSolution(Owner.Uid, DefaultSolutionName); - if (_internalSolution != null) - { - _internalSolution.MaxVolume = _initialMaxVolume; - } - } - - /// - /// Attempt to transfer provided solution to internal solution. - /// Only supports complete transfers - /// - /// Solution to be transferred - /// Whether or not transfer was a success - public override bool TryTransferSolution(Solution solution) - { - // For now doesn't support partial transfers - var current = _internalSolution?.CurrentVolume ?? FixedPoint2.Zero; - var max = _internalSolution?.MaxVolume ?? FixedPoint2.Zero; - if (solution.TotalVolume + current > max) - { - return false; - } - - EntitySystem.Get().TryAddSolution(Owner.Uid, _internalSolution, solution); - return true; - } - - public void PumpToxins(GasMixture to) - { - var atmosphereSystem = EntitySystem.Get(); - var respiratorSystem = EntitySystem.Get(); - - if (!Owner.TryGetComponent(out RespiratorComponent? metabolism)) - { - atmosphereSystem.Merge(to, Air); - Air.Clear(); - return; - } - - var toxins = respiratorSystem.Clean(OwnerUid, metabolism, this); - var toOld = new float[to.Moles.Length]; - Array.Copy(to.Moles, toOld, toOld.Length); - - atmosphereSystem.Merge(to, toxins); - - for (var i = 0; i < toOld.Length; i++) - { - var newAmount = to.GetMoles(i); - var oldAmount = toOld[i]; - var delta = newAmount - oldAmount; - - toxins.AdjustMoles(i, -delta); - } - - atmosphereSystem.Merge(Air, toxins); - } } } diff --git a/Content.Server/Body/Components/MetabolizerComponent.cs b/Content.Server/Body/Components/MetabolizerComponent.cs index 28f93d6079..9581805bf3 100644 --- a/Content.Server/Body/Components/MetabolizerComponent.cs +++ b/Content.Server/Body/Components/MetabolizerComponent.cs @@ -32,7 +32,7 @@ namespace Content.Server.Body.Components /// From which solution will this metabolizer attempt to metabolize chemicals /// [DataField("solution")] - public string SolutionName { get; set; } = SharedBloodstreamComponent.DefaultSolutionName; + public string SolutionName { get; set; } = BloodstreamSystem.DefaultSolutionName; /// /// Does this component use a solution on it's parent entity (the body) or itself diff --git a/Content.Server/Body/Components/StomachComponent.cs b/Content.Server/Body/Components/StomachComponent.cs index c73de7a773..bdaaa6e9b4 100644 --- a/Content.Server/Body/Components/StomachComponent.cs +++ b/Content.Server/Body/Components/StomachComponent.cs @@ -26,7 +26,7 @@ namespace Content.Server.Body.Components /// What solution should this stomach push reagents into, on the body? /// [DataField("bodySolutionName")] - public string BodySolutionName = SharedBloodstreamComponent.DefaultSolutionName; + public string BodySolutionName = BloodstreamSystem.DefaultSolutionName; /// /// Initial internal solution storage volume @@ -36,7 +36,7 @@ namespace Content.Server.Body.Components /// /// Time in seconds between reagents being ingested and them being - /// transferred to + /// transferred to /// [DataField("digestionDelay")] public float DigestionDelay = 20; diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs new file mode 100644 index 0000000000..b6a0cd235c --- /dev/null +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -0,0 +1,77 @@ +using System; +using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Body.Components; +using Content.Server.Chemistry.EntitySystems; +using Content.Shared.Chemistry.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Server.Body.Systems; + +public class BloodstreamSystem : EntitySystem +{ + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; + [Dependency] private readonly AtmosphereSystem _atmosSystem = default!; + [Dependency] private readonly RespiratorSystem _respiratorSystem = default!; + + public static string DefaultSolutionName = "bloodstream"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnComponentInit); + } + + private void OnComponentInit(EntityUid uid, BloodstreamComponent component, ComponentInit args) + { + component.Solution = _solutionContainerSystem.EnsureSolution(uid, DefaultSolutionName); + if (component.Solution != null) + { + component.Solution.MaxVolume = component.InitialMaxVolume; + } + } + + /// + /// Attempt to transfer provided solution to internal solution. + /// + public bool TryAddToBloodstream(EntityUid uid, Solution solution, BloodstreamComponent? component=null) + { + if (!Resolve(uid, ref component, false)) + return false; + + return _solutionContainerSystem.TryAddSolution(uid, component.Solution, solution); + } + + public void PumpToxins(EntityUid uid, GasMixture to, BloodstreamComponent? blood=null, RespiratorComponent? respiration=null) + { + if (!Resolve(uid, ref blood)) + return; + + if(!Resolve(uid, ref respiration, false)) + { + _atmosSystem.Merge(to, blood.Air); + blood.Air.Clear(); + return; + } + + var toxins = _respiratorSystem.Clean(uid, respiration, blood); + var toOld = new float[to.Moles.Length]; + Array.Copy(to.Moles, toOld, toOld.Length); + + _atmosSystem.Merge(to, toxins); + + for (var i = 0; i < toOld.Length; i++) + { + var newAmount = to.GetMoles(i); + var oldAmount = toOld[i]; + var delta = newAmount - oldAmount; + + toxins.AdjustMoles(i, -delta); + } + + _atmosSystem.Merge(blood.Air, toxins); + } +} diff --git a/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs b/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs index 22e847cc0c..dfbf930a8d 100644 --- a/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs +++ b/Content.Server/Chemistry/Components/FoamSolutionAreaEffectComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; using Content.Server.Inventory.Components; using Content.Server.Items; @@ -54,12 +55,14 @@ namespace Content.Server.Chemistry.Components } } + var bloodstreamSys = EntitySystem.Get(); + var cloneSolution = solution.Clone(); var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction * (1 - protection), - bloodstream.EmptyVolume); + bloodstream.Solution.AvailableVolume); var transferSolution = cloneSolution.SplitSolution(transferAmount); - bloodstream.TryTransferSolution(transferSolution); + bloodstreamSys.TryAddToBloodstream(entity.Uid, transferSolution, bloodstream); } protected override void OnKill() diff --git a/Content.Server/Chemistry/Components/InjectorComponent.cs b/Content.Server/Chemistry/Components/InjectorComponent.cs index a67cd0a4d2..b922aabd5c 100644 --- a/Content.Server/Chemistry/Components/InjectorComponent.cs +++ b/Content.Server/Chemistry/Components/InjectorComponent.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; using Content.Shared.Body.Components; @@ -175,13 +176,8 @@ namespace Content.Server.Chemistry.Components private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user) { - if (!EntitySystem.Get() - .TryGetSolution(user.Uid, SharedBloodstreamComponent.DefaultSolutionName, out var bloodstream) - || bloodstream.CurrentVolume == 0) - return; - // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = FixedPoint2.Min(_transferAmount, targetBloodstream.EmptyVolume); + var realTransferAmount = FixedPoint2.Min(_transferAmount, targetBloodstream.Solution.AvailableVolume); if (realTransferAmount <= 0) { @@ -192,18 +188,10 @@ namespace Content.Server.Chemistry.Components // Move units from attackSolution to targetSolution var removedSolution = - EntitySystem.Get().SplitSolution(user.Uid, bloodstream, realTransferAmount); + EntitySystem.Get().SplitSolution(user.Uid, targetBloodstream.Solution, realTransferAmount); - if (!bloodstream.CanAddSolution(removedSolution)) - { - return; - } - - // TODO: Account for partial transfer. - var bloodsStreamEntity = Owner.EntityManager.GetEntity(user.Uid); - removedSolution.DoEntityReaction(bloodsStreamEntity.Uid, ReactionMethod.Injection); - - EntitySystem.Get().TryAddSolution(user.Uid, bloodstream, removedSolution); + var bloodstreamSys = EntitySystem.Get(); + bloodstreamSys.TryAddToBloodstream(targetBloodstream.OwnerUid, removedSolution, targetBloodstream); removedSolution.DoEntityReaction(targetBloodstream.Owner.Uid, ReactionMethod.Injection); diff --git a/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs b/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs index 4de92e9e4e..92e065147a 100644 --- a/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs +++ b/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Reagent; @@ -38,7 +39,7 @@ namespace Content.Server.Chemistry.Components var chemistry = EntitySystem.Get(); var cloneSolution = solution.Clone(); - var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume); + var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.Solution.AvailableVolume); var transferSolution = cloneSolution.SplitSolution(transferAmount); foreach (var reagentQuantity in transferSolution.Contents.ToArray()) @@ -47,7 +48,8 @@ namespace Content.Server.Chemistry.Components chemistry.ReactionEntity(entity.Uid, ReactionMethod.Ingestion, reagentQuantity.ReagentId, reagentQuantity.Quantity, transferSolution); } - bloodstream.TryTransferSolution(transferSolution); + var bloodstreamSys = EntitySystem.Get(); + bloodstreamSys.TryAddToBloodstream(entity.Uid, transferSolution, bloodstream); } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs index 23a4419357..04b1ec19c6 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Components.SolutionManager; using JetBrains.Annotations; @@ -12,6 +13,8 @@ namespace Content.Server.Chemistry.EntitySystems internal sealed class SolutionInjectOnCollideSystem : EntitySystem { [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + public override void Initialize() { base.Initialize(); @@ -35,7 +38,7 @@ namespace Content.Server.Chemistry.EntitySystems var solToInject = solRemoved.SplitSolution(solRemovedVol * component.TransferEfficiency); - bloodstream.TryTransferSolution(solToInject); + _bloodstreamSystem.TryAddToBloodstream(args.OtherFixture.Body.OwnerUid, solToInject, bloodstream); } } } diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs index 56bcb73e5d..fb364373f7 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; using Content.Server.Nutrition.Components; using Content.Shared.Chemistry; @@ -18,6 +19,7 @@ namespace Content.Server.Nutrition.EntitySystems { [Dependency] private readonly ReactiveSystem _reactiveSystem = default!; [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; private const float UpdateTimer = 3f; @@ -97,8 +99,8 @@ namespace Content.Server.Nutrition.EntitySystems !containerManager.Owner.TryGetComponent(out BloodstreamComponent? bloodstream)) continue; - _reactiveSystem.ReactionEntity(containerManager.Owner.Uid, ReactionMethod.Ingestion, inhaledSolution); - bloodstream.TryTransferSolution(inhaledSolution); + _reactiveSystem.ReactionEntity(containerManager.OwnerUid, ReactionMethod.Ingestion, inhaledSolution); + _bloodstreamSystem.TryAddToBloodstream(containerManager.OwnerUid, inhaledSolution, bloodstream); } _timer -= UpdateTimer; diff --git a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs index 17c6a0c100..274b05dd0b 100644 --- a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Chemistry.Components; using Content.Server.Chemistry.EntitySystems; using Content.Server.Cooldown; @@ -32,6 +33,7 @@ namespace Content.Server.Weapon.Melee [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private SolutionContainerSystem _solutionsSystem = default!; [Dependency] private readonly AdminLogSystem _logSystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; public override void Initialize() { @@ -285,7 +287,7 @@ namespace Content.Server.Weapon.Melee foreach (var bloodstream in hitBloodstreams) { var individualInjection = solutionToInject.SplitSolution(volPerBloodstream); - bloodstream.TryTransferSolution(individualInjection); + _bloodstreamSystem.TryAddToBloodstream(bloodstream.OwnerUid, individualInjection, bloodstream); } } diff --git a/Content.Shared/Body/Components/SharedBloodstreamComponent.cs b/Content.Shared/Body/Components/SharedBloodstreamComponent.cs deleted file mode 100644 index 972c592fae..0000000000 --- a/Content.Shared/Body/Components/SharedBloodstreamComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.Chemistry.Components; -using Robust.Shared.GameObjects; - -namespace Content.Shared.Body.Components -{ - public abstract class SharedBloodstreamComponent : Component - { - /// - /// Attempts to transfer the provided solution to an internal solution. - /// Only supports complete transfers. - /// - /// The solution to be transferred. - /// Whether or not transfer was successful. - public abstract bool TryTransferSolution(Solution solution); - - public const string DefaultSolutionName = "bloodstream"; - } -}