diff --git a/Content.Client/Administration/UI/ManageSolutions/AddReagentWindow.xaml.cs b/Content.Client/Administration/UI/ManageSolutions/AddReagentWindow.xaml.cs index cf7c8c5058..1ded5cebb3 100644 --- a/Content.Client/Administration/UI/ManageSolutions/AddReagentWindow.xaml.cs +++ b/Content.Client/Administration/UI/ManageSolutions/AddReagentWindow.xaml.cs @@ -4,9 +4,6 @@ using Robust.Client.Console; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; using Robust.Shared.Prototypes; namespace Content.Client.Administration.UI.ManageSolutions diff --git a/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs b/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs index d2dda0ccbd..ecc26d6026 100644 --- a/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs +++ b/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs @@ -20,7 +20,7 @@ namespace Content.Client.Administration.UI.ManageSolutions private NetEntity _target = NetEntity.Invalid; private string? _selectedSolution; private AddReagentWindow? _addReagentWindow; - private Dictionary? _solutions; + private Dictionary? _solutions; public EditSolutionsWindow() { @@ -60,9 +60,11 @@ namespace Content.Client.Administration.UI.ManageSolutions if (_selectedSolution == null || _solutions == null) return; - if (!_solutions.TryGetValue(_selectedSolution, out var solution)) + if (!_solutions.TryGetValue(_selectedSolution, out var solutionId) || + !_entityManager.TryGetComponent(solutionId, out SolutionComponent? solutionComp)) return; + var solution = solutionComp.Solution; UpdateVolumeBox(solution); UpdateThermalBox(solution); @@ -198,10 +200,13 @@ namespace Content.Client.Administration.UI.ManageSolutions /// private void SetReagent(FloatSpinBox.FloatSpinBoxEventArgs args, string prototype) { - if (_solutions == null || _selectedSolution == null) + if (_solutions == null || _selectedSolution == null || + !_solutions.TryGetValue(_selectedSolution, out var solutionId) || + !_entityManager.TryGetComponent(solutionId, out SolutionComponent? solutionComp)) return; - var current = _solutions[_selectedSolution].GetTotalPrototypeQuantity(prototype); + var solution = solutionComp.Solution; + var current = solution.GetTotalPrototypeQuantity(prototype); var delta = args.Value - current.Float(); if (MathF.Abs(delta) < 0.01) @@ -275,22 +280,38 @@ namespace Content.Client.Administration.UI.ManageSolutions /// /// Update the solution options. /// - public void UpdateSolutions(Dictionary? solutions) + public void UpdateSolutions(List<(string, NetEntity)>? solutions) { SolutionOption.Clear(); - _solutions = solutions; + + if (solutions is { Count: > 0 }) + { + if (_solutions is { Count: > 0 }) + _solutions.Clear(); + else + _solutions = new(solutions.Count); + + foreach (var (name, netSolution) in solutions) + { + if (_entityManager.TryGetEntity(netSolution, out var solution)) + _solutions.Add(name, solution.Value); + } + } + else + _solutions = null; if (_solutions == null) return; int i = 0; - foreach (var solution in _solutions.Keys) + int selectedIndex = 0; // Default to the first solution if none are found. + foreach (var (name, _) in _solutions) { - SolutionOption.AddItem(solution, i); - SolutionOption.SetItemMetadata(i, solution); + SolutionOption.AddItem(name, i); + SolutionOption.SetItemMetadata(i, name); - if (solution == _selectedSolution) - SolutionOption.Select(i); + if (name == _selectedSolution) + selectedIndex = i; i++; } @@ -300,14 +321,11 @@ namespace Content.Client.Administration.UI.ManageSolutions // No applicable solutions Close(); Dispose(); + return; } - if (_selectedSolution == null || !_solutions.ContainsKey(_selectedSolution)) - { - // the previously selected solution is no longer valid. - SolutionOption.Select(0); - _selectedSolution = (string?) SolutionOption.SelectedMetadata; - } + SolutionOption.Select(selectedIndex); + _selectedSolution = (string?) SolutionOption.SelectedMetadata; } } } diff --git a/Content.Client/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs b/Content.Client/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs new file mode 100644 index 0000000000..0c38d605d2 --- /dev/null +++ b/Content.Client/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared.Chemistry.EntitySystems; + +namespace Content.Client.Chemistry.Containers.EntitySystems; + +public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem +{ +} diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs index 1822dd7fff..6e4b7a7618 100644 --- a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs +++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs @@ -1,11 +1,9 @@ using Content.Client.UserInterface.Controls; -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Kitchen; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; @@ -15,7 +13,7 @@ namespace Content.Client.Kitchen.UI public sealed partial class GrinderMenu : FancyWindow { private readonly IEntityManager _entityManager; - private readonly IPrototypeManager _prototypeManager ; + private readonly IPrototypeManager _prototypeManager; private readonly ReagentGrinderBoundUserInterface _owner; private readonly Dictionary _chamberVisualContents = new(); @@ -122,8 +120,8 @@ namespace Content.Client.Kitchen.UI { foreach (var (reagent, quantity) in reagents) { - var reagentName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto) - ? Loc.GetString($"{quantity} {proto.LocalizedName}") + var reagentName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto) + ? Loc.GetString($"{quantity} {proto.LocalizedName}") : "???"; BeakerContentBox.BoxContents.AddItem(reagentName); } diff --git a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs index 518fbe095e..74579b2699 100644 --- a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs @@ -1,11 +1,9 @@ -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Kitchen.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.UserInterface.Controls; -using Robust.Shared.Graphics; namespace Content.Client.Kitchen.UI { diff --git a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs index 064ce46934..d96a035b2d 100644 --- a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs +++ b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs @@ -1,5 +1,5 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; @@ -51,7 +51,7 @@ public sealed class SolutionSystemTests var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); - var containerSystem = entityManager.EntitySysManager.GetEntitySystem(); + var containerSystem = entityManager.System(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; @@ -67,11 +67,11 @@ public sealed class SolutionSystemTests beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); Assert.That(containerSystem - .TryGetSolution(beaker, "beaker", out var solution)); + .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution)); solution.AddSolution(originalWater, protoMan); Assert.That(containerSystem - .TryAddSolution(beaker, solution, oilAdded)); + .TryAddSolution(solutionEnt.Value, oilAdded)); var water = solution.GetTotalPrototypeQuantity("Water"); var oil = solution.GetTotalPrototypeQuantity("Oil"); @@ -97,7 +97,7 @@ public sealed class SolutionSystemTests var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); - var containerSystem = entityManager.EntitySysManager.GetEntitySystem(); + var containerSystem = entityManager.System(); var coordinates = testMap.GridCoords; EntityUid beaker; @@ -112,11 +112,11 @@ public sealed class SolutionSystemTests beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); Assert.That(containerSystem - .TryGetSolution(beaker, "beaker", out var solution)); + .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution)); solution.AddSolution(originalWater, protoMan); Assert.That(containerSystem - .TryAddSolution(beaker, solution, oilAdded), Is.False); + .TryAddSolution(solutionEnt.Value, oilAdded), Is.False); var water = solution.GetTotalPrototypeQuantity("Water"); var oil = solution.GetTotalPrototypeQuantity("Oil"); @@ -141,7 +141,7 @@ public sealed class SolutionSystemTests var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); var testMap = await pair.CreateTestMap(); - var containerSystem = entityManager.EntitySysManager.GetEntitySystem(); + var containerSystem = entityManager.System(); var coordinates = testMap.GridCoords; EntityUid beaker; @@ -158,11 +158,11 @@ public sealed class SolutionSystemTests beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); Assert.That(containerSystem - .TryGetSolution(beaker, "beaker", out var solution)); + .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution)); solution.AddSolution(originalWater, protoMan); Assert.That(containerSystem - .TryMixAndOverflow(beaker, solution, oilAdded, threshold, out var overflowingSolution)); + .TryMixAndOverflow(solutionEnt.Value, oilAdded, threshold, out var overflowingSolution)); Assert.Multiple(() => { @@ -194,7 +194,7 @@ public sealed class SolutionSystemTests var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); - var containerSystem = entityManager.EntitySysManager.GetEntitySystem(); + var containerSystem = entityManager.System(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; @@ -212,11 +212,11 @@ public sealed class SolutionSystemTests beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); Assert.That(containerSystem - .TryGetSolution(beaker, "beaker", out var solution)); + .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution)); solution.AddSolution(originalWater, protoMan); Assert.That(containerSystem - .TryMixAndOverflow(beaker, solution, oilAdded, threshold, out _), + .TryMixAndOverflow(solutionEnt.Value, oilAdded, threshold, out _), Is.False); }); diff --git a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs index 5213747588..ddfe7b3481 100644 --- a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs @@ -1,11 +1,11 @@ -using System.Linq; -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Components; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Utility; +using System.Linq; namespace Content.IntegrationTests.Tests.Chemistry { @@ -34,8 +34,7 @@ namespace Content.IntegrationTests.Tests.Chemistry var prototypeManager = server.ResolveDependency(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; - var solutionSystem = server.ResolveDependency() - .GetEntitySystem(); + var solutionContainerSystem = entityManager.System(); foreach (var reactionPrototype in prototypeManager.EnumeratePrototypes()) { @@ -43,30 +42,31 @@ namespace Content.IntegrationTests.Tests.Chemistry Console.WriteLine($"Testing {reactionPrototype.ID}"); EntityUid beaker = default; - Solution component = null; + Entity? solutionEnt = default!; + Solution solution = null; await server.WaitAssertion(() => { beaker = entityManager.SpawnEntity("TestSolutionContainer", coordinates); - Assert.That(solutionSystem - .TryGetSolution(beaker, "beaker", out component)); + Assert.That(solutionContainerSystem + .TryGetSolution(beaker, "beaker", out solutionEnt, out solution)); foreach (var (id, reactant) in reactionPrototype.Reactants) { #pragma warning disable NUnit2045 - Assert.That(solutionSystem - .TryAddReagent(beaker, component, id, reactant.Amount, out var quantity)); + Assert.That(solutionContainerSystem + .TryAddReagent(solutionEnt.Value, id, reactant.Amount, out var quantity)); Assert.That(reactant.Amount, Is.EqualTo(quantity)); #pragma warning restore NUnit2045 } - solutionSystem.SetTemperature(beaker, component, reactionPrototype.MinimumTemperature); + solutionContainerSystem.SetTemperature(solutionEnt.Value, reactionPrototype.MinimumTemperature); if (reactionPrototype.MixingCategories != null) { var dummyEntity = entityManager.SpawnEntity(null, MapCoordinates.Nullspace); var mixerComponent = entityManager.AddComponent(dummyEntity); mixerComponent.ReactionTypes = reactionPrototype.MixingCategories; - solutionSystem.UpdateChemicals(beaker, component, true, mixerComponent); + solutionContainerSystem.UpdateChemicals(solutionEnt.Value, true, mixerComponent); } }); @@ -79,7 +79,7 @@ namespace Content.IntegrationTests.Tests.Chemistry var foundProductsMap = reactionPrototype.Products .Concat(reactionPrototype.Reactants.Where(x => x.Value.Catalyst).ToDictionary(x => x.Key, x => x.Value.Amount)) .ToDictionary(x => x, _ => false); - foreach (var (reagent, quantity) in component.Contents) + foreach (var (reagent, quantity) in solution.Contents) { Assert.That(foundProductsMap.TryFirstOrNull(x => x.Key.Key == reagent.Prototype && x.Key.Value == quantity, out var foundProduct)); foundProductsMap[foundProduct.Value.Key] = true; diff --git a/Content.IntegrationTests/Tests/Fluids/AbsorbentTest.cs b/Content.IntegrationTests/Tests/Fluids/AbsorbentTest.cs index de5226202c..87ef41fe96 100644 --- a/Content.IntegrationTests/Tests/Fluids/AbsorbentTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/AbsorbentTest.cs @@ -80,7 +80,7 @@ public sealed class AbsorbentTest var entityManager = server.ResolveDependency(); var absorbentSystem = entityManager.System(); - var solutionContainerSystem = entityManager.System(); + var solutionContainerSystem = entityManager.System(); var prototypeManager = server.ResolveDependency(); EntityUid user = default; @@ -94,19 +94,19 @@ public sealed class AbsorbentTest refillable = entityManager.SpawnEntity(RefillableDummyId, coordinates); entityManager.TryGetComponent(absorbent, out component); - solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSolution); - solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSolution); + solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSoln, out var absorbentSolution); + solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSoln, out var refillableSolution); // Arrange if (testCase.InitialAbsorbentSolution.VolumeOfEvaporable > FixedPoint2.Zero) - solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable)); + solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable)); if (testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable > FixedPoint2.Zero) - solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable)); + solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable)); if (testCase.InitialRefillableSolution.VolumeOfEvaporable > FixedPoint2.Zero) - solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable)); + solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable)); if (testCase.InitialRefillableSolution.VolumeOfNonEvaporable > FixedPoint2.Zero) - solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable)); + solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable)); // Act absorbentSystem.Mop(user, refillable, absorbent, component); @@ -138,7 +138,7 @@ public sealed class AbsorbentTest var entityManager = server.ResolveDependency(); var absorbentSystem = entityManager.System(); - var solutionContainerSystem = entityManager.System(); + var solutionContainerSystem = entityManager.System(); var prototypeManager = server.ResolveDependency(); EntityUid user = default; @@ -152,18 +152,18 @@ public sealed class AbsorbentTest refillable = entityManager.SpawnEntity(SmallRefillableDummyId, coordinates); entityManager.TryGetComponent(absorbent, out component); - solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSolution); - solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSolution); + solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSoln, out var absorbentSolution); + solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSoln, out var refillableSolution); // Arrange - solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable)); + solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable)); if (testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable > FixedPoint2.Zero) - solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable)); + solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable)); if (testCase.InitialRefillableSolution.VolumeOfEvaporable > FixedPoint2.Zero) - solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable)); + solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable)); if (testCase.InitialRefillableSolution.VolumeOfNonEvaporable > FixedPoint2.Zero) - solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable)); + solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable)); // Act absorbentSystem.Mop(user, refillable, absorbent, component); diff --git a/Content.Server/Administration/Commands/AddReagent.cs b/Content.Server/Administration/Commands/AddReagent.cs index b75e46ad90..46e8e8c35e 100644 --- a/Content.Server/Administration/Commands/AddReagent.cs +++ b/Content.Server/Administration/Commands/AddReagent.cs @@ -1,10 +1,11 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Administration; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Console; using Robust.Shared.Prototypes; +using System.Linq; namespace Content.Server.Administration.Commands { @@ -41,13 +42,13 @@ namespace Content.Server.Administration.Commands return; } - if (!man.Solutions.ContainsKey(args[1])) + var solutionContainerSystem = _entManager.System(); + if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solution)) { - var validSolutions = string.Join(", ", man.Solutions.Keys); + var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name)); shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}"); return; } - var solution = man.Solutions[args[1]]; if (!_protomanager.HasIndex(args[2])) { @@ -63,9 +64,9 @@ namespace Content.Server.Administration.Commands var quantity = FixedPoint2.New(MathF.Abs(quantityFloat)); if (quantityFloat > 0) - _entManager.System().TryAddReagent(uid.Value, solution, args[2], quantity, out _); + solutionContainerSystem.TryAddReagent(solution.Value, args[2], quantity, out _); else - _entManager.System().RemoveReagent(uid.Value, solution, args[2], quantity); + solutionContainerSystem.RemoveReagent(solution.Value, args[2], quantity); } } } diff --git a/Content.Server/Administration/Commands/SetSolutionCapacity.cs b/Content.Server/Administration/Commands/SetSolutionCapacity.cs index e1e644f84f..19900d488b 100644 --- a/Content.Server/Administration/Commands/SetSolutionCapacity.cs +++ b/Content.Server/Administration/Commands/SetSolutionCapacity.cs @@ -1,8 +1,9 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Administration; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.Console; +using System.Linq; namespace Content.Server.Administration.Commands { @@ -35,13 +36,13 @@ namespace Content.Server.Administration.Commands return; } - if (!man.Solutions.ContainsKey(args[1])) + var solutionContainerSystem = _entManager.System(); + if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solution)) { - var validSolutions = string.Join(", ", man.Solutions.Keys); + var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name)); shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}"); return; } - var solution = man.Solutions[args[1]]; if (!float.TryParse(args[2], out var quantityFloat)) { @@ -49,14 +50,14 @@ namespace Content.Server.Administration.Commands return; } - if(quantityFloat < 0.0f) + if (quantityFloat < 0.0f) { shell.WriteLine($"Cannot set the maximum volume of a solution to a negative number."); return; } var quantity = FixedPoint2.New(quantityFloat); - _entManager.System().SetCapacity(uid.Value, solution, quantity); + solutionContainerSystem.SetCapacity(solution.Value, quantity); } } } diff --git a/Content.Server/Administration/Commands/SetSolutionTemperature.cs b/Content.Server/Administration/Commands/SetSolutionTemperature.cs index e8f58a50cf..5ebd39880b 100644 --- a/Content.Server/Administration/Commands/SetSolutionTemperature.cs +++ b/Content.Server/Administration/Commands/SetSolutionTemperature.cs @@ -1,7 +1,8 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Administration; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Robust.Shared.Console; +using System.Linq; namespace Content.Server.Administration.Commands { @@ -34,13 +35,13 @@ namespace Content.Server.Administration.Commands return; } - if (!man.Solutions.ContainsKey(args[1])) + var solutionContainerSystem = _entManager.System(); + if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solution)) { - var validSolutions = string.Join(", ", man.Solutions.Keys); + var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name)); shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}"); return; } - var solution = man.Solutions[args[1]]; if (!float.TryParse(args[2], out var quantity)) { @@ -54,7 +55,7 @@ namespace Content.Server.Administration.Commands return; } - _entManager.System().SetTemperature(uid.Value, solution, quantity); + solutionContainerSystem.SetTemperature(solution.Value, quantity); } } } diff --git a/Content.Server/Administration/Commands/SetSolutionThermalEnergy.cs b/Content.Server/Administration/Commands/SetSolutionThermalEnergy.cs index c2b7f9d25c..6442f1141a 100644 --- a/Content.Server/Administration/Commands/SetSolutionThermalEnergy.cs +++ b/Content.Server/Administration/Commands/SetSolutionThermalEnergy.cs @@ -1,7 +1,8 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Administration; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Robust.Shared.Console; +using System.Linq; namespace Content.Server.Administration.Commands { @@ -34,13 +35,13 @@ namespace Content.Server.Administration.Commands return; } - if (!man.Solutions.ContainsKey(args[1])) + var solutionContainerSystem = _entManager.System(); + if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solutionEnt, out var solution)) { - var validSolutions = string.Join(", ", man.Solutions.Keys); + var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name)); shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}"); return; } - var solution = man.Solutions[args[1]]; if (!float.TryParse(args[2], out var quantity)) { @@ -50,19 +51,19 @@ namespace Content.Server.Administration.Commands if (solution.GetHeatCapacity(null) <= 0.0f) { - if(quantity != 0.0f) + if (quantity != 0.0f) { shell.WriteLine($"Cannot set the thermal energy of a solution with 0 heat capacity to a non-zero number."); return; } } - else if(quantity <= 0.0f) + else if (quantity <= 0.0f) { shell.WriteLine($"Cannot set the thermal energy of a solution with heat capacity to a non-positive number."); return; } - _entManager.System().SetThermalEnergy(uid.Value, solution, quantity); + solutionContainerSystem.SetThermalEnergy(solutionEnt.Value, quantity); } } } diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.cs b/Content.Server/Administration/Systems/AdminVerbSystem.cs index 2637004565..cfd8311d8e 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; using Content.Server.Administration.UI; @@ -34,6 +33,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Toolshed; using Robust.Shared.Utility; +using System.Linq; using static Content.Shared.Configurable.ConfigurationComponent; namespace Content.Server.Administration.Systems @@ -71,7 +71,7 @@ namespace Content.Server.Administration.Systems { SubscribeLocalEvent>(GetVerbs); SubscribeLocalEvent(Reset); - SubscribeLocalEvent(OnSolutionChanged); + SubscribeLocalEvent(OnSolutionChanged); } private void GetVerbs(GetVerbsEvent ev) @@ -470,11 +470,11 @@ namespace Content.Server.Administration.Systems } #region SolutionsEui - private void OnSolutionChanged(EntityUid uid, SolutionContainerManagerComponent component, SolutionChangedEvent args) + private void OnSolutionChanged(Entity entity, ref SolutionContainerChangedEvent args) { foreach (var eui in _openSolutionUis.Values) { - if (eui.Target == uid) + if (eui.Target == entity.Owner) eui.StateDirty(); } } diff --git a/Content.Server/Administration/Toolshed/SolutionCommand.cs b/Content.Server/Administration/Toolshed/SolutionCommand.cs index 1edf958c95..e81e9aa323 100644 --- a/Content.Server/Administration/Toolshed/SolutionCommand.cs +++ b/Content.Server/Administration/Toolshed/SolutionCommand.cs @@ -1,12 +1,12 @@ -using System.Linq; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Administration; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Toolshed; using Robust.Shared.Toolshed.Syntax; using Robust.Shared.Toolshed.TypeParsers; +using System.Linq; namespace Content.Server.Administration.Toolshed; @@ -24,10 +24,8 @@ public sealed class SolutionCommand : ToolshedCommand { _solutionContainer ??= GetSys(); - _solutionContainer.TryGetSolution(input, name.Evaluate(ctx)!, out var solution); - - if (solution is not null) - return new SolutionRef(input, solution); + if (_solutionContainer.TryGetSolution(input, name.Evaluate(ctx)!, out var solution)) + return new SolutionRef(solution.Value); return null; } @@ -55,11 +53,11 @@ public sealed class SolutionCommand : ToolshedCommand var amount = amountRef.Evaluate(ctx); if (amount > 0) { - _solutionContainer.TryAddReagent(input.Owner, input.Solution, name.Value.ID, amount, out _); + _solutionContainer.TryAddReagent(input.Solution, name.Value.ID, amount, out _); } else if (amount < 0) { - _solutionContainer.RemoveReagent(input.Owner, input.Solution, name.Value.ID, -amount); + _solutionContainer.RemoveReagent(input.Solution, name.Value.ID, -amount); } return input; @@ -75,10 +73,10 @@ public sealed class SolutionCommand : ToolshedCommand => input.Select(x => AdjReagent(ctx, x, name, amountRef)); } -public readonly record struct SolutionRef(EntityUid Owner, Solution Solution) +public readonly record struct SolutionRef(Entity Solution) { public override string ToString() { - return $"{Owner} {Solution}"; + return $"{Solution.Owner} {Solution.Comp.Solution}"; } } diff --git a/Content.Server/Administration/UI/EditSolutionsEui.cs b/Content.Server/Administration/UI/EditSolutionsEui.cs index 5136b347a2..228463d5ce 100644 --- a/Content.Server/Administration/UI/EditSolutionsEui.cs +++ b/Content.Server/Administration/UI/EditSolutionsEui.cs @@ -1,4 +1,5 @@ using Content.Server.Administration.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.EUI; using Content.Shared.Administration; using Content.Shared.Chemistry.Components.SolutionManager; @@ -14,11 +15,13 @@ namespace Content.Server.Administration.UI public sealed class EditSolutionsEui : BaseEui { [Dependency] private readonly IEntityManager _entityManager = default!; + private readonly SolutionContainerSystem _solutionContainerSystem = default!; public readonly EntityUid Target; public EditSolutionsEui(EntityUid entity) { IoCManager.InjectDependencies(this); + _solutionContainerSystem = _entityManager.System(); Target = entity; } @@ -36,8 +39,23 @@ namespace Content.Server.Administration.UI public override EuiStateBase GetNewState() { - var solutions = _entityManager.GetComponentOrNull(Target)?.Solutions; - return new EditSolutionsEuiState(_entityManager.GetNetEntity(Target), solutions); + List<(string Name, NetEntity Solution)>? netSolutions; + + if (_entityManager.TryGetComponent(Target, out SolutionContainerManagerComponent? container) && container.Containers.Count > 0) + { + netSolutions = new(); + foreach (var (name, solution) in _solutionContainerSystem.EnumerateSolutions((Target, container))) + { + if (name is null || !_entityManager.TryGetNetEntity(solution, out var netSolution)) + continue; + + netSolutions.Add((name, netSolution.Value)); + } + } + else + netSolutions = null; + + return new EditSolutionsEuiState(_entityManager.GetNetEntity(Target), netSolutions); } } } diff --git a/Content.Server/Animals/Components/UdderComponent.cs b/Content.Server/Animals/Components/UdderComponent.cs index 3895a8ba24..620f4572a7 100644 --- a/Content.Server/Animals/Components/UdderComponent.cs +++ b/Content.Server/Animals/Components/UdderComponent.cs @@ -1,10 +1,10 @@ using Content.Server.Animals.Systems; +using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - namespace Content.Server.Animals.Components /// @@ -21,10 +21,16 @@ namespace Content.Server.Animals.Components public ProtoId ReagentId = "Milk"; /// - /// The solution to add reagent to. + /// The name of . /// [DataField, ViewVariables(VVAccess.ReadOnly)] - public string Solution = "udder"; + public string SolutionName = "udder"; + + /// + /// The solution to add reagent to. + /// + [DataField] + public Entity? Solution = null; /// /// The amount of reagent to be generated on update. diff --git a/Content.Server/Animals/Components/WoolyComponent.cs b/Content.Server/Animals/Components/WoolyComponent.cs index e700fd76f6..c09c6f5e08 100644 --- a/Content.Server/Animals/Components/WoolyComponent.cs +++ b/Content.Server/Animals/Components/WoolyComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Animals.Systems; +using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; @@ -20,10 +21,16 @@ public sealed partial class WoolyComponent : Component public ProtoId ReagentId = "Fiber"; /// - /// The solution to add reagent to. + /// The name of . /// [DataField, ViewVariables(VVAccess.ReadOnly)] - public string Solution = "wool"; + public string SolutionName = "wool"; + + /// + /// The solution to add reagent to. + /// + [DataField] + public Entity? Solution; /// /// The amount of reagent to be generated on update. diff --git a/Content.Server/Animals/Systems/UdderSystem.cs b/Content.Server/Animals/Systems/UdderSystem.cs index c07ba12dd5..ef43c2c89d 100644 --- a/Content.Server/Animals/Systems/UdderSystem.cs +++ b/Content.Server/Animals/Systems/UdderSystem.cs @@ -1,7 +1,7 @@ using Content.Server.Animals.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Popups; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.DoAfter; using Content.Shared.IdentityManagement; using Content.Shared.Mobs.Systems; @@ -61,11 +61,11 @@ internal sealed class UdderSystem : EntitySystem _hunger.ModifyHunger(uid, -udder.HungerUsage, hunger); } - if (!_solutionContainerSystem.TryGetSolution(uid, udder.Solution, out var solution)) + if (!_solutionContainerSystem.ResolveSolution(uid, udder.SolutionName, ref udder.Solution)) continue; //TODO: toxins from bloodstream !? - _solutionContainerSystem.TryAddReagent(uid, solution, udder.ReagentId, udder.QuantityPerUpdate, out _); + _solutionContainerSystem.TryAddReagent(udder.Solution.Value, udder.ReagentId, udder.QuantityPerUpdate, out _); } } @@ -85,47 +85,50 @@ internal sealed class UdderSystem : EntitySystem _doAfterSystem.TryStartDoAfter(doargs); } - private void OnDoAfter(EntityUid uid, UdderComponent component, MilkingDoAfterEvent args) + private void OnDoAfter(Entity entity, ref MilkingDoAfterEvent args) { if (args.Cancelled || args.Handled || args.Args.Used == null) return; - if (!_solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution)) + if (!_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution)) return; - if (!_solutionContainerSystem.TryGetRefillableSolution(args.Args.Used.Value, out var targetSolution)) + if (!_solutionContainerSystem.TryGetRefillableSolution(args.Args.Used.Value, out var targetSoln, out var targetSolution)) return; args.Handled = true; var quantity = solution.Volume; if (quantity == 0) { - _popupSystem.PopupEntity(Loc.GetString("udder-system-dry"), uid, args.Args.User); + _popupSystem.PopupEntity(Loc.GetString("udder-system-dry"), entity.Owner, args.Args.User); return; } if (quantity > targetSolution.AvailableVolume) quantity = targetSolution.AvailableVolume; - var split = _solutionContainerSystem.SplitSolution(uid, solution, quantity); - _solutionContainerSystem.TryAddSolution(args.Args.Used.Value, targetSolution, split); + var split = _solutionContainerSystem.SplitSolution(entity.Comp.Solution.Value, quantity); + _solutionContainerSystem.TryAddSolution(targetSoln.Value, split); - _popupSystem.PopupEntity(Loc.GetString("udder-system-success", ("amount", quantity), ("target", Identity.Entity(args.Args.Used.Value, EntityManager))), uid, + _popupSystem.PopupEntity(Loc.GetString("udder-system-success", ("amount", quantity), ("target", Identity.Entity(args.Args.Used.Value, EntityManager))), entity.Owner, args.Args.User, PopupType.Medium); } - private void AddMilkVerb(EntityUid uid, UdderComponent component, GetVerbsEvent args) + private void AddMilkVerb(Entity entity, ref GetVerbsEvent args) { if (args.Using == null || !args.CanInteract || !EntityManager.HasComponent(args.Using.Value)) return; + var uid = entity.Owner; + var user = args.User; + var used = args.Using.Value; AlternativeVerb verb = new() { Act = () => { - AttemptMilk(uid, args.User, args.Using.Value); + AttemptMilk(uid, user, used); }, Text = Loc.GetString("udder-system-verb-milk"), Priority = 2 diff --git a/Content.Server/Animals/Systems/WoolySystem.cs b/Content.Server/Animals/Systems/WoolySystem.cs index 6cf8d8c88f..cbe959fb56 100644 --- a/Content.Server/Animals/Systems/WoolySystem.cs +++ b/Content.Server/Animals/Systems/WoolySystem.cs @@ -1,6 +1,6 @@ using Content.Server.Animals.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Mobs.Systems; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; @@ -52,10 +52,10 @@ public sealed class WoolySystem : EntitySystem _hunger.ModifyHunger(uid, -wooly.HungerUsage, hunger); } - if (!_solutionContainer.TryGetSolution(uid, wooly.Solution, out var solution)) + if (!_solutionContainer.ResolveSolution(uid, wooly.SolutionName, ref wooly.Solution)) continue; - _solutionContainer.TryAddReagent(uid, solution, wooly.ReagentId, wooly.Quantity, out _); + _solutionContainer.TryAddReagent(wooly.Solution.Value, wooly.ReagentId, wooly.Quantity, out _); } } diff --git a/Content.Server/Anomaly/Components/ReagentProducerAnomalyComponent.cs b/Content.Server/Anomaly/Components/ReagentProducerAnomalyComponent.cs index aa860c1713..49c62aec81 100644 --- a/Content.Server/Anomaly/Components/ReagentProducerAnomalyComponent.cs +++ b/Content.Server/Anomaly/Components/ReagentProducerAnomalyComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Anomaly.Effects; +using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Robust.Shared.Audio; using Robust.Shared.Prototypes; @@ -85,10 +86,17 @@ public sealed partial class ReagentProducerAnomalyComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public ProtoId ProducingReagent = "Water"; + /// /// Solution name where the substance is generated /// [ViewVariables(VVAccess.ReadWrite)] [DataField("solution")] - public string Solution = "default"; + public string SolutionName = "default"; + + /// + /// Solution where the substance is generated + /// + [DataField("solutionRef")] + public Entity? Solution = null; } diff --git a/Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs b/Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs index 05f1c5c61c..2bef32e322 100644 --- a/Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs @@ -1,8 +1,8 @@ -using System.Linq; using Content.Server.Anomaly.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Anomaly.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; +using System.Linq; namespace Content.Server.Anomaly.Effects; /// @@ -27,41 +27,40 @@ public sealed class InjectionAnomalySystem : EntitySystem _injectableQuery = GetEntityQuery(); } - private void OnPulse(EntityUid uid, InjectionAnomalyComponent component, ref AnomalyPulseEvent args) + private void OnPulse(Entity entity, ref AnomalyPulseEvent args) { - PulseScalableEffect(uid, component, component.InjectRadius, component.MaxSolutionInjection * args.Severity); + PulseScalableEffect(entity, entity.Comp.InjectRadius, entity.Comp.MaxSolutionInjection * args.Severity); } - private void OnSupercritical(EntityUid uid, InjectionAnomalyComponent component, ref AnomalySupercriticalEvent args) + private void OnSupercritical(Entity entity, ref AnomalySupercriticalEvent args) { - PulseScalableEffect(uid, component, component.SuperCriticalInjectRadius, component.SuperCriticalSolutionInjection); + PulseScalableEffect(entity, entity.Comp.SuperCriticalInjectRadius, entity.Comp.SuperCriticalSolutionInjection); } - private void PulseScalableEffect(EntityUid uid, InjectionAnomalyComponent component, float injectRadius, float maxInject) + private void PulseScalableEffect(Entity entity, float injectRadius, float maxInject) { - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol)) + if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var sol)) return; + //We get all the entity in the radius into which the reagent will be injected. var xformQuery = GetEntityQuery(); - var xform = xformQuery.GetComponent(uid); + var xform = xformQuery.GetComponent(entity); var allEnts = _lookup.GetEntitiesInRange(xform.MapPosition, injectRadius) .Select(x => x.Owner).ToList(); //for each matching entity found foreach (var ent in allEnts) { - if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable)) + if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable, out _)) continue; if (_injectableQuery.TryGetComponent(ent, out var injEnt)) { - var buffer = sol; - _solutionContainer.TryTransferSolution(ent, injectable, buffer, maxInject); + _solutionContainer.TryTransferSolution(injectable.Value, sol, maxInject); //Spawn Effect var uidXform = Transform(ent); - Spawn(component.VisualEffectPrototype, uidXform.Coordinates); + Spawn(entity.Comp.VisualEffectPrototype, uidXform.Coordinates); } } } - } diff --git a/Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs b/Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs index 9855e66cfe..90177bae8e 100644 --- a/Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs @@ -1,7 +1,7 @@ using Content.Server.Anomaly.Components; -using Content.Shared.Anomaly.Components; -using Content.Shared.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; +using Content.Shared.Anomaly.Components; namespace Content.Server.Anomaly.Effects; @@ -19,21 +19,21 @@ public sealed class PuddleCreateAnomalySystem : EntitySystem SubscribeLocalEvent(OnSupercritical, before: new[] { typeof(InjectionAnomalySystem) }); } - private void OnPulse(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalyPulseEvent args) + private void OnPulse(Entity entity, ref AnomalyPulseEvent args) { - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol)) + if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out var sol, out _)) return; - var xform = Transform(uid); - var puddleSol = _solutionContainer.SplitSolution(uid, sol, component.MaxPuddleSize * args.Severity); - _puddle.TrySplashSpillAt(uid, xform.Coordinates, puddleSol, out _); + var xform = Transform(entity.Owner); + var puddleSol = _solutionContainer.SplitSolution(sol.Value, entity.Comp.MaxPuddleSize * args.Severity); + _puddle.TrySplashSpillAt(entity.Owner, xform.Coordinates, puddleSol, out _); } - private void OnSupercritical(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalySupercriticalEvent args) + private void OnSupercritical(Entity entity, ref AnomalySupercriticalEvent args) { - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol)) + if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var sol)) return; - var buffer = sol; - var xform = Transform(uid); - _puddle.TrySpillAt(xform.Coordinates, buffer, out _); + + var xform = Transform(entity.Owner); + _puddle.TrySpillAt(xform.Coordinates, sol, out _); } } diff --git a/Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs b/Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs index 487d20f43f..0e49c5ee56 100644 --- a/Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs @@ -1,12 +1,12 @@ using Content.Server.Anomaly.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Anomaly.Components; -using Robust.Shared.Random; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; -using Robust.Shared.Prototypes; using Content.Shared.Sprite; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; namespace Content.Server.Anomaly.Effects; @@ -42,17 +42,17 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem SubscribeLocalEvent(OnMapInit); } - private void OnPulse(EntityUid uid, ReagentProducerAnomalyComponent component, ref AnomalyPulseEvent args) + private void OnPulse(Entity entity, ref AnomalyPulseEvent args) { if (_random.NextFloat(0.0f, 1.0f) > args.Stability) - ChangeReagent(uid, component, args.Severity); + ChangeReagent(entity, args.Severity); } - private void ChangeReagent(EntityUid uid, ReagentProducerAnomalyComponent component, float severity) + private void ChangeReagent(Entity entity, float severity) { - var reagent = GetRandomReagentType(uid, component, severity); - component.ProducingReagent = reagent; - _audio.PlayPvs(component.ChangeSound, uid); + var reagent = GetRandomReagentType(entity, severity); + entity.Comp.ProducingReagent = reagent; + _audio.PlayPvs(entity.Comp.ChangeSound, entity); } //reagent realtime generation @@ -68,7 +68,7 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem if (component.AccumulatedFrametime < component.UpdateInterval) continue; - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var producerSol)) + if (!_solutionContainer.ResolveSolution(uid, component.SolutionName, ref component.Solution, out var producerSolution)) continue; Solution newSol = new(); @@ -76,7 +76,7 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem if (anomaly.Severity >= 0.97) reagentProducingAmount *= component.SupercriticalReagentProducingModifier; newSol.AddReagent(component.ProducingReagent, reagentProducingAmount); - _solutionContainer.TryAddSolution(uid, producerSol, newSol); //TO DO - the container is not fully filled. + _solutionContainer.TryAddSolution(component.Solution.Value, newSol); //TO DO - the container is not fully filled. component.AccumulatedFrametime = 0; @@ -87,7 +87,7 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem // and nothing worked out for me. So for now it will be like this. if (component.NeedRecolor) { - var color = producerSol.GetColor(_prototypeManager); + var color = producerSolution.GetColor(_prototypeManager); _light.SetColor(uid, color); if (TryComp(uid, out var randomSprite)) { @@ -103,9 +103,9 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem } } - private void OnMapInit(EntityUid uid, ReagentProducerAnomalyComponent component, MapInitEvent args) + private void OnMapInit(Entity entity, ref MapInitEvent args) { - ChangeReagent(uid, component, 0.1f); //MapInit Reagent 100% change + ChangeReagent(entity, 0.1f); //MapInit Reagent 100% change } // returns a random reagent based on a system of random weights. @@ -117,33 +117,33 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem // After that, a random reagent in the selected category is selected. // // Such a system is made to control the danger and interest of the anomaly more. - private string GetRandomReagentType(EntityUid uid, ReagentProducerAnomalyComponent component, float severity) + private string GetRandomReagentType(Entity entity, float severity) { //Category Weight Randomization - var currentWeightDangerous = MathHelper.Lerp(component.WeightSpreadDangerous.X, component.WeightSpreadDangerous.Y, severity); - var currentWeightFun = MathHelper.Lerp(component.WeightSpreadFun.X, component.WeightSpreadFun.Y, severity); - var currentWeightUseful = MathHelper.Lerp(component.WeightSpreadUseful.X, component.WeightSpreadUseful.Y, severity); + var currentWeightDangerous = MathHelper.Lerp(entity.Comp.WeightSpreadDangerous.X, entity.Comp.WeightSpreadDangerous.Y, severity); + var currentWeightFun = MathHelper.Lerp(entity.Comp.WeightSpreadFun.X, entity.Comp.WeightSpreadFun.Y, severity); + var currentWeightUseful = MathHelper.Lerp(entity.Comp.WeightSpreadUseful.X, entity.Comp.WeightSpreadUseful.Y, severity); var sumWeight = currentWeightDangerous + currentWeightFun + currentWeightUseful; var rnd = _random.NextFloat(0f, sumWeight); //Dangerous - if (rnd <= currentWeightDangerous && component.DangerousChemicals.Count > 0) + if (rnd <= currentWeightDangerous && entity.Comp.DangerousChemicals.Count > 0) { - var reagent = _random.Pick(component.DangerousChemicals); + var reagent = _random.Pick(entity.Comp.DangerousChemicals); return reagent; } else rnd -= currentWeightDangerous; //Fun - if (rnd <= currentWeightFun && component.FunChemicals.Count > 0) + if (rnd <= currentWeightFun && entity.Comp.FunChemicals.Count > 0) { - var reagent = _random.Pick(component.FunChemicals); + var reagent = _random.Pick(entity.Comp.FunChemicals); return reagent; } else rnd -= currentWeightFun; //Useful - if (rnd <= currentWeightUseful && component.UsefulChemicals.Count > 0) + if (rnd <= currentWeightUseful && entity.Comp.UsefulChemicals.Count > 0) { - var reagent = _random.Pick(component.UsefulChemicals); + var reagent = _random.Pick(entity.Comp.UsefulChemicals); return reagent; } //We should never end up here. diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasCondenserComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasCondenserComponent.cs index 1db0b524bb..c25c010708 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasCondenserComponent.cs +++ b/Content.Server/Atmos/Piping/Unary/Components/GasCondenserComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos.Piping.Unary.EntitySystems; +using Content.Shared.Chemistry.Components; namespace Content.Server.Atmos.Piping.Unary.Components; @@ -21,6 +22,12 @@ public sealed partial class GasCondenserComponent : Component [DataField] public string SolutionId = "tank"; + /// + /// The solution that gases are condensed into. + /// + [DataField] + public Entity? Solution = null; + /// /// For a condenser, how many U of reagents are given per each mole of gas. /// diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs index f9ed614d9c..491bf60062 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs @@ -5,10 +5,11 @@ using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; -using Content.Shared.Atmos; -using JetBrains.Annotations; using Content.Server.Power.EntitySystems; +using Content.Shared.Atmos; using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; namespace Content.Server.Atmos.Piping.Unary.EntitySystems; @@ -18,7 +19,7 @@ public sealed class GasCondenserSystem : EntitySystem [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly PowerReceiverSystem _power = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; - [Dependency] private readonly SolutionContainerSystem _solution = default!; + [Dependency] private readonly SharedSolutionContainerSystem _solution = default!; public override void Initialize() { @@ -27,12 +28,12 @@ public sealed class GasCondenserSystem : EntitySystem SubscribeLocalEvent(OnCondenserUpdated); } - private void OnCondenserUpdated(EntityUid uid, GasCondenserComponent component, ref AtmosDeviceUpdateEvent args) + private void OnCondenserUpdated(Entity entity, ref AtmosDeviceUpdateEvent args) { - if (!(_power.IsPowered(uid) && TryComp(uid, out var receiver)) - || !TryComp(uid, out var nodeContainer) - || !_nodeContainer.TryGetNode(nodeContainer, component.Inlet, out PipeNode? inlet) - || !_solution.TryGetSolution(uid, component.SolutionId, out var solution)) + if (!(_power.IsPowered(entity) && TryComp(entity, out var receiver)) + || !TryComp(entity, out var nodeContainer) + || !_nodeContainer.TryGetNode(nodeContainer, entity.Comp.Inlet, out PipeNode? inlet) + || !_solution.ResolveSolution(entity.Owner, entity.Comp.SolutionId, ref entity.Comp.Solution, out var solution)) { return; } @@ -48,18 +49,21 @@ public sealed class GasCondenserSystem : EntitySystem if (moles <= 0) continue; - if (_atmosphereSystem.GetGas(i).Reagent is not {} gasReagent) + if (_atmosphereSystem.GetGas(i).Reagent is not { } gasReagent) continue; - var moleToReagentMultiplier = component.MolesToReagentMultiplier; - var amount = moles * moleToReagentMultiplier; - - if (_solution.TryAddReagent(uid, solution, gasReagent, amount, out var remaining)) + var moleToReagentMultiplier = entity.Comp.MolesToReagentMultiplier; + var amount = FixedPoint2.Min(FixedPoint2.New(moles * moleToReagentMultiplier), solution.AvailableVolume); + if (amount <= 0) continue; + solution.AddReagent(gasReagent, amount); + // if we have leftover reagent, then convert it back to moles and put it back in the mixture. - inlet.Air.AdjustMoles(i, remaining.Float() / moleToReagentMultiplier); + inlet.Air.AdjustMoles(i, moles - (amount.Float() / moleToReagentMultiplier)); } + + _solution.UpdateChemicals(entity.Comp.Solution.Value); } public float NumberOfMolesToConvert(ApcPowerReceiverComponent comp, GasMixture mix, float dt) diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Server/Body/Components/BloodstreamComponent.cs index 33db12157e..3ee8fe4d17 100644 --- a/Content.Server/Body/Components/BloodstreamComponent.cs +++ b/Content.Server/Body/Components/BloodstreamComponent.cs @@ -34,52 +34,52 @@ namespace Content.Server.Body.Components /// /// How much should bleeding should be reduced every update interval? /// - [DataField("bleedReductionAmount")] + [DataField] public float BleedReductionAmount = 1.0f; /// /// How high can go? /// - [DataField("maxBleedAmount")] + [DataField] public float MaxBleedAmount = 10.0f; /// /// What percentage of current blood is necessary to avoid dealing blood loss damage? /// - [DataField("bloodlossThreshold")] + [DataField] public float BloodlossThreshold = 0.9f; /// /// The base bloodloss damage to be incurred if below /// The default values are defined per mob/species in YML. /// - [DataField("bloodlossDamage", required: true)] + [DataField(required: true)] public DamageSpecifier BloodlossDamage = new(); /// /// The base bloodloss damage to be healed if above /// The default values are defined per mob/species in YML. /// - [DataField("bloodlossHealDamage", required: true)] + [DataField(required: true)] public DamageSpecifier BloodlossHealDamage = new(); /// /// How frequently should this bloodstream update, in seconds? /// - [DataField("updateInterval")] + [DataField] public float UpdateInterval = 3.0f; // TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth. /// /// How much reagent of blood should be restored each update interval? /// - [DataField("bloodRefreshAmount")] + [DataField] public float BloodRefreshAmount = 1.0f; /// /// How much blood needs to be in the temporary solution in order to create a puddle? /// - [DataField("bleedPuddleThreshold")] + [DataField] public FixedPoint2 BleedPuddleThreshold = 1.0f; /// @@ -89,19 +89,19 @@ namespace Content.Server.Body.Components /// /// For example, piercing damage is increased while poison damage is nullified entirely. /// - [DataField("damageBleedModifiers", customTypeSerializer:typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer:typeof(PrototypeIdSerializer))] public string DamageBleedModifiers = "BloodlossHuman"; /// /// The sound to be played when a weapon instantly deals blood loss damage. /// - [DataField("instantBloodSound")] + [DataField] public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood"); /// /// The sound to be played when some damage actually heals bleeding rather than starting it. /// - [DataField("bloodHealedSound")] + [DataField] public SoundSpecifier BloodHealedSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); // TODO probably damage bleed thresholds. @@ -109,14 +109,14 @@ namespace Content.Server.Body.Components /// /// Max volume of internal chemical solution storage /// - [DataField("chemicalMaxVolume")] + [DataField] public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250); /// /// Max volume of internal blood storage, /// and starting level of blood. /// - [DataField("bloodMaxVolume")] + [DataField] public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300); /// @@ -125,29 +125,40 @@ namespace Content.Server.Body.Components /// /// Slime-people might use slime as their blood or something like that. /// - [DataField("bloodReagent")] + [DataField] public string BloodReagent = "Blood"; - /// - /// Internal solution for reagent storage - /// - [ViewVariables(VVAccess.ReadWrite)] - [Access(typeof(BloodstreamSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public Solution ChemicalSolution = default!; + /// Name/Key that is indexed by. + [DataField] + public string BloodSolutionName = DefaultBloodSolutionName; + + /// Name/Key that is indexed by. + [DataField] + public string ChemicalSolutionName = DefaultChemicalsSolutionName; + + /// Name/Key that is indexed by. + [DataField] + public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName; /// /// Internal solution for blood storage /// - [ViewVariables(VVAccess.ReadWrite)] - public Solution BloodSolution = default!; + [DataField] + public Entity? BloodSolution = null; + + /// + /// Internal solution for reagent storage + /// + [DataField] + public Entity? ChemicalSolution = null; /// /// Temporary blood solution. /// When blood is lost, it goes to this solution, and when this /// solution hits a certain cap, the blood is actually spilled as a puddle. /// - [ViewVariables(VVAccess.ReadWrite)] - public Solution BloodTemporarySolution = default!; + [DataField] + public Entity? TemporarySolution = null; /// /// Variable that stores the amount of status time added by having a low blood level. diff --git a/Content.Server/Body/Components/LungComponent.cs b/Content.Server/Body/Components/LungComponent.cs index 434286a5c6..1d997a9950 100644 --- a/Content.Server/Body/Components/LungComponent.cs +++ b/Content.Server/Body/Components/LungComponent.cs @@ -8,7 +8,7 @@ namespace Content.Server.Body.Components; [RegisterComponent, Access(typeof(LungSystem))] public sealed partial class LungComponent : Component { - [DataField("air")] + [DataField] [Access(typeof(LungSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends public GasMixture Air { get; set; } = new() { @@ -16,7 +16,15 @@ public sealed partial class LungComponent : Component Temperature = Atmospherics.NormalBodyTemperature }; - [ViewVariables] - [Access(typeof(LungSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public Solution LungSolution = default!; + /// + /// The name/key of the solution on this entity which these lungs act on. + /// + [DataField] + public string SolutionName = LungSystem.LungSolutionName; + + /// + /// The solution on this entity that these lungs act on. + /// + [DataField] + public Entity? Solution = null; } diff --git a/Content.Server/Body/Components/MetabolizerComponent.cs b/Content.Server/Body/Components/MetabolizerComponent.cs index 21a0be25d2..a8c82f3d36 100644 --- a/Content.Server/Body/Components/MetabolizerComponent.cs +++ b/Content.Server/Body/Components/MetabolizerComponent.cs @@ -18,7 +18,7 @@ namespace Content.Server.Body.Components /// How often to metabolize reagents, in seconds. /// /// - [DataField("updateFrequency")] + [DataField] public float UpdateFrequency = 1.0f; /// @@ -33,13 +33,13 @@ namespace Content.Server.Body.Components /// /// Most things will use the parent entity (bloodstream). /// - [DataField("solutionOnBody")] + [DataField] public bool SolutionOnBody = true; /// /// List of metabolizer types that this organ is. ex. Human, Slime, Felinid, w/e. /// - [DataField("metabolizerTypes", customTypeSerializer:typeof(PrototypeIdHashSetSerializer))] + [DataField(customTypeSerializer:typeof(PrototypeIdHashSetSerializer))] [Access(typeof(MetabolizerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends public HashSet? MetabolizerTypes = null; @@ -47,7 +47,7 @@ namespace Content.Server.Body.Components /// Should this metabolizer remove chemicals that have no metabolisms defined? /// As a stop-gap, basically. /// - [DataField("removeEmpty")] + [DataField] public bool RemoveEmpty = false; /// @@ -72,7 +72,7 @@ namespace Content.Server.Body.Components [DataDefinition] public sealed partial class MetabolismGroupEntry { - [DataField("id", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] + [DataField(required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] public string Id = default!; [DataField("rateModifier")] diff --git a/Content.Server/Body/Components/StomachComponent.cs b/Content.Server/Body/Components/StomachComponent.cs index 30f9791525..fe93468f74 100644 --- a/Content.Server/Body/Components/StomachComponent.cs +++ b/Content.Server/Body/Components/StomachComponent.cs @@ -2,7 +2,6 @@ using Content.Server.Nutrition.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; -using Content.Shared.FixedPoint; using Content.Shared.Whitelist; namespace Content.Server.Body.Components @@ -15,26 +14,32 @@ namespace Content.Server.Body.Components /// /// How fast should this component update, in seconds? /// - [DataField("updateInterval")] + [DataField] public float UpdateInterval = 1.0f; + /// + /// The solution inside of this stomach this transfers reagents to the body. + /// + [DataField] + public Entity? Solution = null; + /// /// What solution should this stomach push reagents into, on the body? /// - [DataField("bodySolutionName")] + [DataField] public string BodySolutionName = BloodstreamComponent.DefaultChemicalsSolutionName; /// /// Time in seconds between reagents being ingested and them being /// transferred to /// - [DataField("digestionDelay")] + [DataField] public float DigestionDelay = 20; /// /// A whitelist for what special-digestible-required foods this stomach is capable of eating. /// - [DataField("specialDigestible")] + [DataField] public EntityWhitelist? SpecialDigestible = null; /// diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index cb83625615..21dc2f4526 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -1,6 +1,8 @@ using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Chemistry.ReactionEffects; using Content.Server.Fluids.EntitySystems; +using Content.Server.Forensics; using Content.Server.HealthExaminable; using Content.Server.Popups; using Content.Shared.Alert; @@ -16,13 +18,9 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Rejuvenate; using Content.Shared.Speech.EntitySystems; -using Robust.Server.GameObjects; +using Robust.Server.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Content.Shared.Speech.EntitySystems; -using Robust.Server.Audio; -using Robust.Shared.GameObjects; -using Content.Server.Forensics; namespace Content.Server.Body.Systems; @@ -51,14 +49,13 @@ public sealed class BloodstreamSystem : EntitySystem SubscribeLocalEvent(OnBeingGibbed); SubscribeLocalEvent(OnApplyMetabolicMultiplier); SubscribeLocalEvent(OnReactionAttempt); + SubscribeLocalEvent>(OnReactionAttempt); SubscribeLocalEvent(OnRejuvenate); } - private void OnReactionAttempt(EntityUid uid, BloodstreamComponent component, ReactionAttemptEvent args) + private void OnReactionAttempt(Entity entity, ref ReactionAttemptEvent args) { - if (args.Solution.Name != BloodstreamComponent.DefaultBloodSolutionName - && args.Solution.Name != BloodstreamComponent.DefaultChemicalsSolutionName - && args.Solution.Name != BloodstreamComponent.DefaultBloodTemporarySolutionName) + if (args.Cancelled) return; foreach (var effect in args.Reaction.Effects) @@ -67,7 +64,7 @@ public sealed class BloodstreamSystem : EntitySystem { case CreateEntityReactionEffect: // Prevent entities from spawning in the bloodstream case AreaReactionEffect: // No spontaneous smoke or foam leaking out of blood vessels. - args.Cancel(); + args.Cancelled = true; return; } } @@ -81,6 +78,16 @@ public sealed class BloodstreamSystem : EntitySystem // Having cheese-clots form in your veins can't be good for you. } + private void OnReactionAttempt(Entity entity, ref SolutionRelayEvent args) + { + if (args.Name != entity.Comp.BloodSolutionName + && args.Name != entity.Comp.ChemicalSolutionName + && args.Name != entity.Comp.BloodTemporarySolutionName) + return; + + OnReactionAttempt(entity, ref args.Event); + } + public override void Update(float frameTime) { base.Update(frameTime); @@ -95,8 +102,11 @@ public sealed class BloodstreamSystem : EntitySystem bloodstream.AccumulatedFrametime -= bloodstream.UpdateInterval; + if (!_solutionContainerSystem.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)) + continue; + // Adds blood to their blood level if it is below the maximum; Blood regeneration. Must be alive. - if (bloodstream.BloodSolution.Volume < bloodstream.BloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid)) + if (bloodSolution.Volume < bloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid)) { TryModifyBloodLevel(uid, bloodstream.BloodRefreshAmount, bloodstream); } @@ -143,19 +153,18 @@ public sealed class BloodstreamSystem : EntitySystem } } - private void OnComponentInit(EntityUid uid, BloodstreamComponent component, ComponentInit args) + private void OnComponentInit(Entity entity, ref ComponentInit args) { - component.ChemicalSolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultChemicalsSolutionName); - component.BloodSolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodSolutionName); - component.BloodTemporarySolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodTemporarySolutionName); + var chemicalSolution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.ChemicalSolutionName); + var bloodSolution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.BloodSolutionName); + var tempSolution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.BloodTemporarySolutionName); - component.ChemicalSolution.MaxVolume = component.ChemicalMaxVolume; - component.BloodSolution.MaxVolume = component.BloodMaxVolume; - component.BloodTemporarySolution.MaxVolume = component.BleedPuddleThreshold * 4; // give some leeway, for chemstream as well + chemicalSolution.MaxVolume = entity.Comp.ChemicalMaxVolume; + bloodSolution.MaxVolume = entity.Comp.BloodMaxVolume; + tempSolution.MaxVolume = entity.Comp.BleedPuddleThreshold * 4; // give some leeway, for chemstream as well // Fill blood solution with BLOOD - _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent, - component.BloodMaxVolume, out _); + bloodSolution.AddReagent(entity.Comp.BloodReagent, entity.Comp.BloodMaxVolume - bloodSolution.Volume); } private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, DamageChangedEvent args) @@ -250,34 +259,45 @@ public sealed class BloodstreamSystem : EntitySystem component.AccumulatedFrametime = component.UpdateInterval; } - private void OnRejuvenate(EntityUid uid, BloodstreamComponent component, RejuvenateEvent args) + private void OnRejuvenate(Entity entity, ref RejuvenateEvent args) { - TryModifyBleedAmount(uid, -component.BleedAmount, component); - TryModifyBloodLevel(uid, component.BloodSolution.AvailableVolume, component); - _solutionContainerSystem.RemoveAllSolution(uid, component.ChemicalSolution); + TryModifyBleedAmount(entity.Owner, -entity.Comp.BleedAmount, entity.Comp); + + if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution)) + TryModifyBloodLevel(entity.Owner, bloodSolution.AvailableVolume, entity.Comp); + + if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.ChemicalSolutionName, ref entity.Comp.ChemicalSolution)) + _solutionContainerSystem.RemoveAllSolution(entity.Comp.ChemicalSolution.Value); } /// /// Attempt to transfer provided solution to internal solution. /// - public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component=null) + public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component = null) { if (!Resolve(uid, ref component, false)) return false; - return _solutionContainerSystem.TryAddSolution(uid, component.ChemicalSolution, solution); + if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution)) + return false; + + return _solutionContainerSystem.TryAddSolution(component.ChemicalSolution.Value, solution); } - public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 quantity, BloodstreamComponent? component = null) { + public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 quantity, BloodstreamComponent? component = null) + { if (!Resolve(uid, ref component, false)) return false; - for (var i = component.ChemicalSolution.Contents.Count - 1; i >= 0; i--) + if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution)) + return false; + + for (var i = chemSolution.Contents.Count - 1; i >= 0; i--) { - var (reagentId, _) = component.ChemicalSolution.Contents[i]; + var (reagentId, _) = chemSolution.Contents[i]; if (reagentId.Prototype != excludedReagentID) { - _solutionContainerSystem.RemoveReagent(uid, component.ChemicalSolution, reagentId, quantity); + _solutionContainerSystem.RemoveReagent(component.ChemicalSolution.Value, reagentId, quantity); } } @@ -289,7 +309,10 @@ public sealed class BloodstreamSystem : EntitySystem if (!Resolve(uid, ref component)) return 0.0f; - return component.BloodSolution.FillFraction; + if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) + return 0.0f; + + return bloodSolution.FillFraction; } public void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamComponent? comp = null) @@ -308,28 +331,41 @@ public sealed class BloodstreamSystem : EntitySystem if (!Resolve(uid, ref component, false)) return false; + if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution)) + return false; + if (amount >= 0) - return _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent, amount, out _); + return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, out _); // Removal is more involved, // since we also wanna handle moving it to the temporary solution // and then spilling it if necessary. - var newSol = component.BloodSolution.SplitSolution(-amount); - component.BloodTemporarySolution.AddSolution(newSol, _prototypeManager); + var newSol = _solutionContainerSystem.SplitSolution(component.BloodSolution.Value, -amount); - if (component.BloodTemporarySolution.Volume > component.BleedPuddleThreshold) + if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution)) + return true; + + tempSolution.AddSolution(newSol, _prototypeManager); + + if (tempSolution.Volume > component.BleedPuddleThreshold) { // Pass some of the chemstream into the spilled blood. - var temp = component.ChemicalSolution.SplitSolution(component.BloodTemporarySolution.Volume / 10); - component.BloodTemporarySolution.AddSolution(temp, _prototypeManager); - if (_puddleSystem.TrySpillAt(uid, component.BloodTemporarySolution, out var puddleUid, false)) + if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution)) + { + var temp = _solutionContainerSystem.SplitSolution(component.ChemicalSolution.Value, tempSolution.Volume / 10); + tempSolution.AddSolution(temp, _prototypeManager); + } + + if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, false)) { _forensicsSystem.TransferDna(puddleUid, uid, false); } - component.BloodTemporarySolution.RemoveAllSolution(); + tempSolution.RemoveAllSolution(); } + _solutionContainerSystem.UpdateChemicals(component.TemporarySolution.Value); + return true; } @@ -363,16 +399,28 @@ public sealed class BloodstreamSystem : EntitySystem if (!Resolve(uid, ref component)) return; - var max = component.BloodSolution.MaxVolume + component.BloodTemporarySolution.MaxVolume + - component.ChemicalSolution.MaxVolume; - var tempSol = new Solution() { MaxVolume = max }; + var tempSol = new Solution(); - tempSol.AddSolution(component.BloodSolution, _prototypeManager); - component.BloodSolution.RemoveAllSolution(); - tempSol.AddSolution(component.BloodTemporarySolution, _prototypeManager); - component.BloodTemporarySolution.RemoveAllSolution(); - tempSol.AddSolution(component.ChemicalSolution, _prototypeManager); - component.ChemicalSolution.RemoveAllSolution(); + if (_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) + { + tempSol.MaxVolume += bloodSolution.MaxVolume; + tempSol.AddSolution(bloodSolution, _prototypeManager); + _solutionContainerSystem.RemoveAllSolution(component.BloodSolution.Value); + } + + if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution)) + { + tempSol.MaxVolume += chemSolution.MaxVolume; + tempSol.AddSolution(chemSolution, _prototypeManager); + _solutionContainerSystem.RemoveAllSolution(component.ChemicalSolution.Value); + } + + if (_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution)) + { + tempSol.MaxVolume += tempSolution.MaxVolume; + tempSol.AddSolution(tempSolution, _prototypeManager); + _solutionContainerSystem.RemoveAllSolution(component.TemporarySolution.Value); + } if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid)) { @@ -388,13 +436,20 @@ public sealed class BloodstreamSystem : EntitySystem if (!Resolve(uid, ref component, false)) return; - if(reagent == component.BloodReagent) + if (reagent == component.BloodReagent) return; - var currentVolume = component.BloodSolution.Volume; + if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) + { + component.BloodReagent = reagent; + return; + } + + var currentVolume = bloodSolution.RemoveReagent(component.BloodReagent, bloodSolution.Volume); component.BloodReagent = reagent; - component.BloodSolution.RemoveAllSolution(); - _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent, currentVolume, out _); + + if (currentVolume > 0) + _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, out _); } } diff --git a/Content.Server/Body/Systems/LungSystem.cs b/Content.Server/Body/Systems/LungSystem.cs index 3aef2486e7..b5bac50739 100644 --- a/Content.Server/Body/Systems/LungSystem.cs +++ b/Content.Server/Body/Systems/LungSystem.cs @@ -1,8 +1,8 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Atmos; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Clothing; using Content.Shared.Inventory.Events; @@ -44,11 +44,11 @@ public sealed class LungSystem : EntitySystem } } - private void OnComponentInit(EntityUid uid, LungComponent component, ComponentInit args) + private void OnComponentInit(Entity entity, ref ComponentInit args) { - component.LungSolution = _solutionContainerSystem.EnsureSolution(uid, LungSolutionName); - component.LungSolution.MaxVolume = 100.0f; - component.LungSolution.CanReact = false; // No dexalin lungs + var solution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName); + solution.MaxVolume = 100.0f; + solution.CanReact = false; // No dexalin lungs } private void OnMaskToggled(Entity ent, ref ItemMaskToggledEvent args) @@ -71,6 +71,9 @@ public sealed class LungSystem : EntitySystem public void GasToReagent(EntityUid uid, LungComponent lung) { + if (!_solutionContainerSystem.ResolveSolution(uid, lung.SolutionName, ref lung.Solution, out var solution)) + return; + foreach (var gas in Enum.GetValues()) { var i = (int) gas; @@ -81,11 +84,13 @@ public sealed class LungSystem : EntitySystem if (reagent == null) continue; var amount = moles * Atmospherics.BreathMolesToReagentMultiplier; - _solutionContainerSystem.TryAddReagent(uid, lung.LungSolution, reagent, amount, out _); + solution.AddReagent(reagent, amount); // We don't remove the gas from the lung mix, // that's the responsibility of whatever gas is being metabolized. // Most things will just want to exhale again. } + + _solutionContainerSystem.UpdateChemicals(lung.Solution.Value); } } diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs index c8851b49ac..d05e6c7f79 100644 --- a/Content.Server/Body/Systems/MetabolizerSystem.cs +++ b/Content.Server/Body/Systems/MetabolizerSystem.cs @@ -1,9 +1,9 @@ using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Administration.Logs; using Content.Shared.Body.Organ; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.FixedPoint; @@ -37,15 +37,15 @@ namespace Content.Server.Body.Systems SubscribeLocalEvent(OnApplyMetabolicMultiplier); } - private void OnMetabolizerInit(EntityUid uid, MetabolizerComponent component, ComponentInit args) + private void OnMetabolizerInit(Entity entity, ref ComponentInit args) { - if (!component.SolutionOnBody) + if (!entity.Comp.SolutionOnBody) { - _solutionContainerSystem.EnsureSolution(uid, component.SolutionName); + _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName); } - else if (_organQuery.CompOrNull(uid)?.Body is { } body) + else if (_organQuery.CompOrNull(entity)?.Body is { } body) { - _solutionContainerSystem.EnsureSolution(body, component.SolutionName); + _solutionContainerSystem.EnsureSolution(body, entity.Comp.SolutionName); } } @@ -95,6 +95,7 @@ namespace Content.Server.Body.Systems // First step is get the solution we actually care about Solution? solution = null; + Entity? soln = default!; EntityUid? solutionEntityUid = null; SolutionContainerManagerComponent? manager = null; @@ -106,7 +107,7 @@ namespace Content.Server.Body.Systems if (!_solutionQuery.Resolve(body, ref manager, false)) return; - _solutionContainerSystem.TryGetSolution(body, meta.SolutionName, out solution, manager); + _solutionContainerSystem.TryGetSolution((body, manager), meta.SolutionName, out soln, out solution); solutionEntityUid = body; } } @@ -115,11 +116,11 @@ namespace Content.Server.Body.Systems if (!_solutionQuery.Resolve(uid, ref manager, false)) return; - _solutionContainerSystem.TryGetSolution(uid, meta.SolutionName, out solution, manager); + _solutionContainerSystem.TryGetSolution((uid, manager), meta.SolutionName, out soln, out solution); solutionEntityUid = uid; } - if (solutionEntityUid == null || solution == null || solution.Contents.Count == 0) + if (solutionEntityUid == null || soln is null || solution is null || solution.Contents.Count == 0) return; // randomize the reagent list so we don't have any weird quirks @@ -138,8 +139,7 @@ namespace Content.Server.Body.Systems { if (meta.RemoveEmpty) { - _solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent, - FixedPoint2.New(1)); + solution.RemoveReagent(reagent, FixedPoint2.New(1)); } continue; @@ -198,12 +198,14 @@ namespace Content.Server.Body.Systems // remove a certain amount of reagent if (mostToRemove > FixedPoint2.Zero) { - _solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent, mostToRemove); + solution.RemoveReagent(reagent, mostToRemove); // We have processed a reagant, so count it towards the cap reagents += 1; } } + + _solutionContainerSystem.UpdateChemicals(soln.Value); } } diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index 3fa8f59a1d..b814422181 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Administration.Logs; using Content.Server.Atmos; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Popups; using Content.Shared.Alert; using Content.Shared.Atmos; @@ -26,6 +27,7 @@ namespace Content.Server.Body.Systems [Dependency] private readonly LungSystem _lungSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; public override void Initialize() { @@ -144,7 +146,9 @@ namespace Content.Server.Body.Systems { _atmosSys.Merge(outGas, lung.Air); lung.Air.Clear(); - lung.LungSolution.RemoveAllSolution(); + + if (_solutionContainerSystem.ResolveSolution(lung.Owner, lung.SolutionName, ref lung.Solution)) + _solutionContainerSystem.RemoveAllSolution(lung.Solution.Value); } _atmosSys.Merge(ev.Gas, outGas); diff --git a/Content.Server/Body/Systems/StomachSystem.cs b/Content.Server/Body/Systems/StomachSystem.cs index 5a3f6cf31a..4c11244c37 100644 --- a/Content.Server/Body/Systems/StomachSystem.cs +++ b/Content.Server/Body/Systems/StomachSystem.cs @@ -1,8 +1,8 @@ using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Body.Organ; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Robust.Shared.Utility; namespace Content.Server.Body.Systems @@ -31,8 +31,7 @@ namespace Content.Server.Body.Systems stomach.AccumulatedFrameTime -= stomach.UpdateInterval; // Get our solutions - if (!_solutionContainerSystem.TryGetSolution(uid, DefaultSolutionName, - out var stomachSolution, sol)) + if (!_solutionContainerSystem.ResolveSolution((uid, sol), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)) continue; if (organ.Body is not { } body || !_solutionContainerSystem.TryGetSolution(body, stomach.BodySolutionName, out var bodySolution)) @@ -51,7 +50,7 @@ namespace Content.Server.Body.Systems if (reagent.Quantity > delta.ReagentQuantity.Quantity) reagent = new(reagent.Reagent, delta.ReagentQuantity.Quantity); - _solutionContainerSystem.RemoveReagent(uid, stomachSolution, reagent); + stomachSolution.RemoveReagent(reagent); transferSolution.AddReagent(reagent); } @@ -64,8 +63,10 @@ namespace Content.Server.Body.Systems stomach.ReagentDeltas.Remove(item); } + _solutionContainerSystem.UpdateChemicals(stomach.Solution.Value); + // Transfer everything to the body solution! - _solutionContainerSystem.TryAddSolution(body, bodySolution, transferSolution); + _solutionContainerSystem.TryAddSolution(bodySolution.Value, transferSolution); } } @@ -86,12 +87,13 @@ namespace Content.Server.Body.Systems } public bool CanTransferSolution(EntityUid uid, Solution solution, + StomachComponent? stomach = null, SolutionContainerManagerComponent? solutions = null) { - if (!Resolve(uid, ref solutions, false)) + if (!Resolve(uid, ref stomach, ref solutions, false)) return false; - if (!_solutionContainerSystem.TryGetSolution(uid, DefaultSolutionName, out var stomachSolution, solutions)) + if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)) return false; // TODO: For now no partial transfers. Potentially change by design @@ -108,11 +110,11 @@ namespace Content.Server.Body.Systems if (!Resolve(uid, ref stomach, ref solutions, false)) return false; - if (!_solutionContainerSystem.TryGetSolution(uid, DefaultSolutionName, out var stomachSolution, solutions) - || !CanTransferSolution(uid, solution, solutions)) + if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution) + || !CanTransferSolution(uid, solution, stomach, solutions)) return false; - _solutionContainerSystem.TryAddSolution(uid, stomachSolution, solution); + _solutionContainerSystem.TryAddSolution(stomach.Solution.Value, solution); // Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach foreach (var reagent in solution.Contents) { diff --git a/Content.Server/Botany/Components/PlantHolderComponent.cs b/Content.Server/Botany/Components/PlantHolderComponent.cs index 9825167ca2..809af737ac 100644 --- a/Content.Server/Botany/Components/PlantHolderComponent.cs +++ b/Content.Server/Botany/Components/PlantHolderComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Chemistry.Components; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Botany.Components; @@ -90,4 +91,7 @@ public sealed partial class PlantHolderComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("solution")] public string SoilSolutionName = "soil"; + + [DataField] + public Entity? SoilSolution = null; } diff --git a/Content.Server/Botany/Systems/BotanySystem.Produce.cs b/Content.Server/Botany/Systems/BotanySystem.Produce.cs index 3cfb21f3c4..788c09821b 100644 --- a/Content.Server/Botany/Systems/BotanySystem.Produce.cs +++ b/Content.Server/Botany/Systems/BotanySystem.Produce.cs @@ -1,6 +1,5 @@ using Content.Server.Botany.Components; using Content.Shared.FixedPoint; -using Robust.Server.GameObjects; namespace Content.Server.Botany.Systems; @@ -11,7 +10,7 @@ public sealed partial class BotanySystem if (!TryGetSeed(produce, out var seed)) return; - var solutionContainer = _solutionContainerSystem.EnsureSolution(uid, produce.SolutionName); + var solutionContainer = _solutionContainerSystem.EnsureSolution(uid, produce.SolutionName, FixedPoint2.Zero, out _); solutionContainer.RemoveAllSolution(); foreach (var (chem, quantity) in seed.Chemicals) diff --git a/Content.Server/Botany/Systems/BotanySystem.Seed.cs b/Content.Server/Botany/Systems/BotanySystem.Seed.cs index 02fb1060f3..1fb6952e91 100644 --- a/Content.Server/Botany/Systems/BotanySystem.Seed.cs +++ b/Content.Server/Botany/Systems/BotanySystem.Seed.cs @@ -1,10 +1,8 @@ -using System.Diagnostics.CodeAnalysis; -using System.Linq; using Content.Server.Botany.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Kitchen.Components; using Content.Server.Popups; using Content.Shared.Botany; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Examine; using Content.Shared.Hands.EntitySystems; using Content.Shared.Physics; @@ -20,6 +18,8 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using System.Diagnostics.CodeAnalysis; +using System.Linq; namespace Content.Server.Botany.Systems; diff --git a/Content.Server/Botany/Systems/PlantHolderSystem.cs b/Content.Server/Botany/Systems/PlantHolderSystem.cs index 027ca9b038..96fde08118 100644 --- a/Content.Server/Botany/Systems/PlantHolderSystem.cs +++ b/Content.Server/Botany/Systems/PlantHolderSystem.cs @@ -1,12 +1,12 @@ using Content.Server.Atmos; using Content.Server.Atmos.EntitySystems; using Content.Server.Botany.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.Components; using Content.Server.Ghost.Roles.Components; using Content.Server.Kitchen.Components; using Content.Server.Popups; using Content.Shared.Botany; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Coordinates.Helpers; using Content.Shared.Examine; @@ -38,7 +38,7 @@ public sealed class PlantHolderSystem : EntitySystem [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SharedPointLightSystem _pointLight = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly RandomHelperSystem _randomHelper = default!; [Dependency] private readonly IRobustRandom _random = default!; @@ -70,11 +70,13 @@ public sealed class PlantHolderSystem : EntitySystem } } - private void OnExamine(EntityUid uid, PlantHolderComponent component, ExaminedEvent args) + private void OnExamine(Entity entity, ref ExaminedEvent args) { if (!args.IsInDetailsRange) return; + var (_, component) = entity; + if (component.Seed == null) { args.PushMarkup(Loc.GetString("plant-holder-component-nothing-planted-message")); @@ -131,8 +133,10 @@ public sealed class PlantHolderSystem : EntitySystem } } - private void OnInteractUsing(EntityUid uid, PlantHolderComponent component, InteractUsingEvent args) + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { + var (uid, component) = entity; + if (TryComp(args.Used, out SeedComponent? seeds)) { if (component.Seed == null) @@ -203,8 +207,8 @@ public sealed class PlantHolderSystem : EntitySystem return; } - if (_solutionSystem.TryGetDrainableSolution(args.Used, out var solution) - && _solutionSystem.TryGetSolution(uid, component.SoilSolutionName, out var targetSolution) + if (_solutionContainerSystem.TryGetDrainableSolution(args.Used, out var solution, out _) + && _solutionContainerSystem.ResolveSolution(uid, component.SoilSolutionName, ref component.SoilSolution) && TryComp(args.Used, out SprayComponent? spray)) { var amount = FixedPoint2.New(1); @@ -214,7 +218,7 @@ public sealed class PlantHolderSystem : EntitySystem _audio.PlayPvs(spray.SpraySound, args.Used, AudioParams.Default.WithVariation(0.125f)); - var split = _solutionSystem.Drain(solutionEntity, solution, amount); + var split = _solutionContainerSystem.Drain(solutionEntity, solution.Value, amount); if (split.Volume == 0) { @@ -227,7 +231,7 @@ public sealed class PlantHolderSystem : EntitySystem ("owner", uid), ("amount", split.Volume)), args.User, PopupType.Medium); - _solutionSystem.TryAddSolution(targetEntity, targetSolution, split); + _solutionContainerSystem.TryAddSolution(component.SoilSolution.Value, split); ForceUpdateByExternalCause(uid, component); @@ -290,16 +294,15 @@ public sealed class PlantHolderSystem : EntitySystem ("usingItem", args.Used), ("owner", uid)), uid, Filter.PvsExcept(args.User), true); - if (_solutionSystem.TryGetSolution(args.Used, produce.SolutionName, out var solution2)) + if (_solutionContainerSystem.TryGetSolution(args.Used, produce.SolutionName, out var soln2, out var solution2)) { - if (_solutionSystem.TryGetSolution(uid, component.SoilSolutionName, out var solution1)) + if (_solutionContainerSystem.ResolveSolution(uid, component.SoilSolutionName, ref component.SoilSolution, out var solution1)) { // We try to fit as much of the composted plant's contained solution into the hydroponics tray as we can, // since the plant will be consumed anyway. var fillAmount = FixedPoint2.Min(solution2.Volume, solution1.AvailableVolume); - _solutionSystem.TryAddSolution(uid, solution1, - _solutionSystem.SplitSolution(args.Used, solution2, fillAmount)); + _solutionContainerSystem.TryAddSolution(component.SoilSolution.Value, _solutionContainerSystem.SplitSolution(soln2.Value, fillAmount)); ForceUpdateByExternalCause(uid, component); } @@ -314,9 +317,9 @@ public sealed class PlantHolderSystem : EntitySystem } } - private void OnInteractHand(EntityUid uid, PlantHolderComponent component, InteractHandEvent args) + private void OnInteractHand(Entity entity, ref InteractHandEvent args) { - DoHarvest(uid, args.User, component); + DoHarvest(entity, args.User, entity.Comp); } public void WeedInvasion() @@ -819,13 +822,13 @@ public sealed class PlantHolderSystem : EntitySystem if (!Resolve(uid, ref component)) return; - if (!_solutionSystem.TryGetSolution(uid, component.SoilSolutionName, out var solution)) + if (!_solutionContainerSystem.ResolveSolution(uid, component.SoilSolutionName, ref component.SoilSolution, out var solution)) return; if (solution.Volume > 0 && component.MutationLevel < 25) { var amt = FixedPoint2.New(1); - foreach (var entry in _solutionSystem.RemoveEachReagent(uid, solution, amt)) + foreach (var entry in _solutionContainerSystem.RemoveEachReagent(component.SoilSolution.Value, amt)) { var reagentProto = _prototype.Index(entry.Reagent.Prototype); reagentProto.ReactionPlant(uid, entry, solution); diff --git a/Content.Server/Cargo/Systems/PricingSystem.cs b/Content.Server/Cargo/Systems/PricingSystem.cs index 5bbe1e5a6d..6fb36c9608 100644 --- a/Content.Server/Cargo/Systems/PricingSystem.cs +++ b/Content.Server/Cargo/Systems/PricingSystem.cs @@ -1,7 +1,7 @@ -using System.Linq; -using Content.Server.Administration; +using Content.Server.Administration; using Content.Server.Body.Systems; using Content.Server.Cargo.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Administration; using Content.Shared.Body.Components; using Content.Shared.Chemistry.Components.SolutionManager; @@ -16,6 +16,7 @@ using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; using Robust.Shared.Utility; +using System.Linq; namespace Content.Server.Cargo.Systems; @@ -30,6 +31,7 @@ public sealed class PricingSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; /// public override void Initialize() @@ -106,13 +108,36 @@ public sealed class PricingSystem : EntitySystem args.Price += (component.Price - partPenalty) * (_mobStateSystem.IsAlive(uid, state) ? 1.0 : component.DeathPenalty); } + private double GetSolutionPrice(Entity entity) + { + if (Comp(entity).EntityLifeStage < EntityLifeStage.MapInitialized) + return GetSolutionPrice(entity.Comp); + + var price = 0.0; + + foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((entity.Owner, entity.Comp))) + { + var solution = soln.Comp.Solution; + foreach (var (reagent, quantity) in solution.Contents) + { + if (!_prototypeManager.TryIndex(reagent.Prototype, out var reagentProto)) + continue; + + // TODO check ReagentData for price information? + price += (float) quantity * reagentProto.PricePerUnit; + } + } + + return price; + } + private double GetSolutionPrice(SolutionContainerManagerComponent component) { var price = 0.0; - foreach (var solution in component.Solutions.Values) + foreach (var (_, prototype) in _solutionContainerSystem.EnumerateSolutions(component)) { - foreach (var (reagent, quantity) in solution.Contents) + foreach (var (reagent, quantity) in prototype.Contents) { if (!_prototypeManager.TryIndex(reagent.Prototype, out var reagentProto)) continue; @@ -257,7 +282,7 @@ public sealed class PricingSystem : EntitySystem if (TryComp(uid, out var solComp)) { - price += GetSolutionPrice(solComp); + price += GetSolutionPrice((uid, solComp)); } return price; diff --git a/Content.Server/Chemistry/Components/HyposprayComponent.cs b/Content.Server/Chemistry/Components/HyposprayComponent.cs index 76bb0e8d41..2a80cec801 100644 --- a/Content.Server/Chemistry/Components/HyposprayComponent.cs +++ b/Content.Server/Chemistry/Components/HyposprayComponent.cs @@ -1,4 +1,3 @@ -using Content.Server.Chemistry.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.FixedPoint; using Robust.Shared.Audio; diff --git a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs index 1fc5772d4e..7fe2dacb67 100644 --- a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs @@ -1,8 +1,6 @@ using Content.Server.Chemistry.EntitySystems; using Content.Shared.Chemistry.Components; -using Content.Shared.FixedPoint; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Chemistry.Components; @@ -17,7 +15,13 @@ public sealed partial class SolutionRegenerationComponent : Component /// The name of the solution to add to. /// [DataField("solution", required: true), ViewVariables(VVAccess.ReadWrite)] - public string Solution = string.Empty; + public string SolutionName = string.Empty; + + /// + /// The solution to add reagents to. + /// + [DataField("solutionRef")] + public Entity? Solution = null; /// /// The reagent(s) to be regenerated in the solution. diff --git a/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs new file mode 100644 index 0000000000..fcf68013fa --- /dev/null +++ b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs @@ -0,0 +1,186 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.FixedPoint; +using Robust.Shared.Containers; +using Robust.Shared.Map; +using Robust.Shared.Network; +using Robust.Shared.Utility; +using System.Numerics; + +namespace Content.Server.Chemistry.Containers.EntitySystems; + +public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem +{ + [Dependency] private readonly INetManager _netManager = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnComponentShutdown); + SubscribeLocalEvent(OnComponentShutdown); + } + + + public Solution EnsureSolution(Entity entity, string name) + => EnsureSolution(entity, name, out _); + + public Solution EnsureSolution(Entity entity, string name, out bool existed) + => EnsureSolution(entity, name, FixedPoint2.Zero, out existed); + + public Solution EnsureSolution(Entity entity, string name, FixedPoint2 minVol, out bool existed) + => EnsureSolution(entity, name, minVol, null, out existed); + + public Solution EnsureSolution(Entity entity, string name, FixedPoint2 minVol, Solution? prototype, out bool existed) + { + var (uid, meta) = entity; + if (!Resolve(uid, ref meta)) + throw new InvalidOperationException("Attempted to ensure solution on invalid entity."); + + var manager = EnsureComp(uid); + if (meta.EntityLifeStage >= EntityLifeStage.MapInitialized) + return EnsureSolutionEntity((uid, manager), name, minVol, prototype, out existed).Comp.Solution; + else + return EnsureSolutionPrototype((uid, manager), name, minVol, prototype, out existed); + } + + public Entity EnsureSolutionEntity(Entity entity, string name, FixedPoint2 minVol, Solution? prototype, out bool existed) + { + existed = true; + + var (uid, container) = entity; + + var solutionSlot = ContainerSystem.EnsureContainer(uid, $"solution@{name}", out existed); + if (!Resolve(uid, ref container, logMissing: false)) + { + existed = false; + container = AddComp(uid); + container.Containers.Add(name); + } + else if (!existed) + { + container.Containers.Add(name); + Dirty(uid, container); + } + + var needsInit = false; + SolutionComponent solutionComp; + if (solutionSlot.ContainedEntity is not { } solutionId) + { + prototype ??= new() { MaxVolume = minVol }; + prototype.Name = name; + (solutionId, solutionComp, _) = SpawnSolutionUninitialized(solutionSlot, name, minVol, prototype); + existed = false; + needsInit = true; + Dirty(uid, container); + } + else + { + solutionComp = Comp(solutionId); + DebugTools.Assert(TryComp(solutionId, out ContainedSolutionComponent? relation) && relation.Container == uid && relation.ContainerName == name); + DebugTools.Assert(solutionComp.Solution.Name == name); + + var solution = solutionComp.Solution; + solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, minVol); + + // Depending on MapInitEvent order some systems can ensure solution empty solutions and conflict with the prototype solutions. + // We want the reagents from the prototype to exist even if something else already created the solution. + if (prototype is { Volume.Value: > 0 }) + solution.AddSolution(prototype, PrototypeManager); + + Dirty(solutionId, solutionComp); + } + + if (needsInit) + EntityManager.InitializeAndStartEntity(solutionId, Transform(solutionId).MapID); + + return (solutionId, solutionComp); + } + + private Solution EnsureSolutionPrototype(Entity entity, string name, FixedPoint2 minVol, Solution? prototype, out bool existed) + { + existed = true; + + var (uid, container) = entity; + if (!Resolve(uid, ref container, logMissing: false)) + { + container = AddComp(uid); + existed = false; + } + + if (container.Solutions is null) + container.Solutions = new(SolutionContainerManagerComponent.DefaultCapacity); + + if (!container.Solutions.TryGetValue(name, out var solution)) + { + solution = prototype ?? new() { Name = name, MaxVolume = minVol }; + container.Solutions.Add(name, solution); + existed = false; + } + else + solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, minVol); + + Dirty(uid, container); + return solution; + } + + + private Entity SpawnSolutionUninitialized(ContainerSlot container, string name, FixedPoint2 minVol, Solution prototype) + { + var coords = new EntityCoordinates(container.Owner, Vector2.Zero); + var uid = EntityManager.CreateEntityUninitialized(null, coords, null); + + var solution = new SolutionComponent() { Solution = prototype }; + AddComp(uid, solution); + + var relation = new ContainedSolutionComponent() { Container = container.Owner, ContainerName = name }; + AddComp(uid, relation); + + ContainerSystem.Insert(uid, container, force: true); + + return (uid, solution, relation); + } + + + #region Event Handlers + + private void OnMapInit(Entity entity, ref MapInitEvent args) + { + if (entity.Comp.Solutions is not { } prototypes) + return; + + foreach (var (name, prototype) in prototypes) + { + EnsureSolutionEntity((entity.Owner, entity.Comp), name, prototype.MaxVolume, prototype, out _); + } + + entity.Comp.Solutions = null; + Dirty(entity); + } + + private void OnComponentShutdown(Entity entity, ref ComponentShutdown args) + { + foreach (var name in entity.Comp.Containers) + { + if (ContainerSystem.TryGetContainer(entity, $"solution@{name}", out var solutionContainer)) + ContainerSystem.ShutdownContainer(solutionContainer); + } + entity.Comp.Containers.Clear(); + } + + private void OnComponentShutdown(Entity entity, ref ComponentShutdown args) + { + if (TryComp(entity.Comp.Container, out SolutionContainerManagerComponent? container)) + { + container.Containers.Remove(entity.Comp.ContainerName); + Dirty(entity.Comp.Container, container); + } + + if (ContainerSystem.TryGetContainer(entity, $"solution@{entity.Comp.ContainerName}", out var solutionContainer)) + ContainerSystem.ShutdownContainer(solutionContainer); + } + + #endregion Event Handlers +} diff --git a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs index cbb84be83c..2cc0f3d055 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs @@ -1,6 +1,5 @@ -using System.Diagnostics.CodeAnalysis; -using System.Linq; using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Labels; using Content.Server.Popups; using Content.Server.Storage.EntitySystems; @@ -19,6 +18,8 @@ using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.Prototypes; +using System.Diagnostics.CodeAnalysis; +using System.Linq; namespace Content.Server.Chemistry.EntitySystems { @@ -47,7 +48,7 @@ namespace Content.Server.Chemistry.EntitySystems base.Initialize(); SubscribeLocalEvent(SubscribeUpdateUiState); - SubscribeLocalEvent(SubscribeUpdateUiState); + SubscribeLocalEvent(SubscribeUpdateUiState); SubscribeLocalEvent(SubscribeUpdateUiState); SubscribeLocalEvent(SubscribeUpdateUiState); SubscribeLocalEvent(SubscribeUpdateUiState); @@ -67,7 +68,7 @@ namespace Content.Server.Chemistry.EntitySystems private void UpdateUiState(Entity ent, bool updateLabel = false) { var (owner, chemMaster) = ent; - if (!_solutionContainerSystem.TryGetSolution(owner, SharedChemMaster.BufferSolutionName, out var bufferSolution)) + if (!_solutionContainerSystem.TryGetSolution(owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution)) return; var inputContainer = _itemSlotsSystem.GetItemOrNull(owner, SharedChemMaster.InputSlotName); var outputContainer = _itemSlotsSystem.GetItemOrNull(owner, SharedChemMaster.OutputSlotName); @@ -130,8 +131,8 @@ namespace Content.Server.Chemistry.EntitySystems { var container = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.InputSlotName); if (container is null || - !_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution) || - !_solutionContainerSystem.TryGetSolution(chemMaster, SharedChemMaster.BufferSolutionName, out var bufferSolution)) + !_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSoln, out var containerSolution) || + !_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution)) { return; } @@ -140,12 +141,12 @@ namespace Content.Server.Chemistry.EntitySystems { amount = FixedPoint2.Min(amount, containerSolution.AvailableVolume); amount = bufferSolution.RemoveReagent(id, amount); - _solutionContainerSystem.TryAddReagent(container.Value, containerSolution, id, amount, out var _); + _solutionContainerSystem.TryAddReagent(containerSoln.Value, id, amount, out var _); } else // Container to buffer { amount = FixedPoint2.Min(amount, containerSolution.GetReagentQuantity(id)); - _solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount); + _solutionContainerSystem.RemoveReagent(containerSoln.Value, id, amount); bufferSolution.AddReagent(id, amount); } @@ -156,7 +157,7 @@ namespace Content.Server.Chemistry.EntitySystems { if (fromBuffer) { - if (_solutionContainerSystem.TryGetSolution(chemMaster, SharedChemMaster.BufferSolutionName, out var bufferSolution)) + if (_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution)) bufferSolution.RemoveReagent(id, amount); else return; @@ -165,9 +166,9 @@ namespace Content.Server.Chemistry.EntitySystems { var container = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.InputSlotName); if (container is not null && - _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution)) + _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution, out _)) { - _solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount); + _solutionContainerSystem.RemoveReagent(containerSolution.Value, id, amount); } else return; @@ -210,10 +211,8 @@ namespace Content.Server.Chemistry.EntitySystems _storageSystem.Insert(container, item, out _, user: user, storage); _labelSystem.Label(item, message.Label); - var itemSolution = _solutionContainerSystem.EnsureSolution(item, SharedChemMaster.PillSolutionName); - - _solutionContainerSystem.TryAddSolution( - item, itemSolution, withdrawal.SplitSolution(message.Dosage)); + var itemSolution = _solutionContainerSystem.EnsureSolutionEntity(item, SharedChemMaster.PillSolutionName, message.Dosage, null, out _); + _solutionContainerSystem.TryAddSolution(itemSolution, withdrawal.SplitSolution(message.Dosage)); var pill = EnsureComp(item); pill.PillType = chemMaster.Comp.PillType; @@ -223,13 +222,13 @@ namespace Content.Server.Chemistry.EntitySystems { // Log pill creation by a user _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(user.Value):user} printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution)}"); + $"{ToPrettyString(user.Value):user} printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution.Comp.Solution)}"); } else { // Log pill creation by magic? This should never happen... right? _adminLogger.Add(LogType.Action, LogImpact.Low, - $"Unknown printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution)}"); + $"Unknown printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution.Comp.Solution)}"); } } @@ -242,8 +241,7 @@ namespace Content.Server.Chemistry.EntitySystems var user = message.Session.AttachedEntity; var maybeContainer = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.OutputSlotName); if (maybeContainer is not { Valid: true } container - || !_solutionContainerSystem.TryGetSolution( - container, SharedChemMaster.BottleSolutionName, out var solution)) + || !_solutionContainerSystem.TryGetSolution(container, SharedChemMaster.BottleSolutionName, out var soln, out var solution)) { return; // output can't fit reagents } @@ -260,8 +258,7 @@ namespace Content.Server.Chemistry.EntitySystems return; _labelSystem.Label(container, message.Label); - _solutionContainerSystem.TryAddSolution( - container, solution, withdrawal); + _solutionContainerSystem.TryAddSolution(soln.Value, withdrawal); if (user.HasValue) { @@ -287,8 +284,7 @@ namespace Content.Server.Chemistry.EntitySystems { outputSolution = null; - if (!_solutionContainerSystem.TryGetSolution( - chemMaster, SharedChemMaster.BufferSolutionName, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var solution)) { return false; } @@ -323,7 +319,7 @@ namespace Content.Server.Chemistry.EntitySystems return null; if (!TryComp(container, out FitsInDispenserComponent? fits) - || !_solutionContainerSystem.TryGetSolution(container.Value, fits.Solution, out var solution)) + || !_solutionContainerSystem.TryGetSolution(container.Value, fits.Solution, out _, out var solution)) { return null; } @@ -339,7 +335,7 @@ namespace Content.Server.Chemistry.EntitySystems var name = Name(container.Value); { if (_solutionContainerSystem.TryGetSolution( - container.Value, SharedChemMaster.BottleSolutionName, out var solution)) + container.Value, SharedChemMaster.BottleSolutionName, out _, out var solution)) { return BuildContainerInfo(name, solution); } @@ -350,7 +346,7 @@ namespace Content.Server.Chemistry.EntitySystems var pills = storage.Container.ContainedEntities.Select((Func) (pill => { - _solutionContainerSystem.TryGetSolution(pill, SharedChemMaster.PillSolutionName, out var solution); + _solutionContainerSystem.TryGetSolution(pill, SharedChemMaster.PillSolutionName, out _, out var solution); var quantity = solution?.Volume ?? FixedPoint2.Zero; return (Name(pill), quantity); })).ToList(); diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs index c618094d1b..5f7427eacc 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs @@ -1,21 +1,22 @@ using Content.Server.Body.Components; using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; +using Content.Shared.DoAfter; using Content.Shared.FixedPoint; +using Content.Shared.Forensics; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; -using Robust.Shared.GameStates; -using Content.Shared.DoAfter; using Content.Shared.Mobs.Components; -using Content.Shared.Verbs; using Content.Shared.Stacks; +using Content.Shared.Verbs; +using Robust.Shared.GameStates; using Robust.Shared.Player; -using Content.Shared.Forensics; namespace Content.Server.Chemistry.EntitySystems; @@ -25,11 +26,11 @@ public sealed partial class ChemistrySystem /// /// Default transfer amounts for the set-transfer verb. /// - public static readonly List TransferAmounts = new() {1, 5, 10, 15}; + public static readonly List TransferAmounts = new() { 1, 5, 10, 15 }; private void InitializeInjector() { SubscribeLocalEvent>(AddSetTransferVerbs); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); SubscribeLocalEvent(OnInjectDoAfter); SubscribeLocalEvent(OnInjectorStartup); SubscribeLocalEvent(OnInjectorUse); @@ -37,7 +38,7 @@ public sealed partial class ChemistrySystem SubscribeLocalEvent(OnInjectorGetState); } - private void AddSetTransferVerbs(EntityUid uid, InjectorComponent component, GetVerbsEvent args) + private void AddSetTransferVerbs(Entity entity, ref GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || args.Hands == null) return; @@ -45,11 +46,14 @@ public sealed partial class ChemistrySystem if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) return; + var (uid, component) = entity; + // Add specific transfer verbs according to the container's size var priority = 0; + var user = args.User; foreach (var amount in TransferAmounts) { - if ( amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int()) + if (amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int()) continue; AlternativeVerb verb = new(); @@ -58,7 +62,7 @@ public sealed partial class ChemistrySystem verb.Act = () => { component.TransferAmount = FixedPoint2.New(amount); - _popup.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), args.User, args.User); + _popup.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), user, user); }; // we want to sort by size, not alphabetically by the verb text. @@ -69,22 +73,22 @@ public sealed partial class ChemistrySystem } } - private void UseInjector(EntityUid target, EntityUid user, EntityUid injector, InjectorComponent component) + private void UseInjector(Entity injector, EntityUid target, EntityUid user) { // Handle injecting/drawing for solutions - if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) + if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) { - if (_solutions.TryGetInjectableSolution(target, out var injectableSolution)) + if (_solutionContainers.TryGetInjectableSolution(target, out var injectableSolution, out _)) { - TryInject(component, injector, target, injectableSolution, user, false); + TryInject(injector, target, injectableSolution.Value, user, false); } - else if (_solutions.TryGetRefillableSolution(target, out var refillableSolution)) + else if (_solutionContainers.TryGetRefillableSolution(target, out var refillableSolution, out _)) { - TryInject(component, injector, target, refillableSolution, user, true); + TryInject(injector, target, refillableSolution.Value, user, true); } else if (TryComp(target, out var bloodstream)) { - TryInjectIntoBloodstream(component, injector, target, bloodstream, user); + TryInjectIntoBloodstream(injector, (target, bloodstream), user); } else { @@ -92,111 +96,112 @@ public sealed partial class ChemistrySystem ("target", Identity.Entity(target, EntityManager))), injector, user); } } - else if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Draw) + else if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Draw) { // Draw from a bloodstream, if the target has that - if (TryComp(target, out var stream)) + if (TryComp(target, out var stream) && + _solutionContainers.ResolveSolution(target, stream.BloodSolutionName, ref stream.BloodSolution)) { - TryDraw(component, injector, target, stream.BloodSolution, user, stream); + TryDraw(injector, (target, stream), stream.BloodSolution.Value, user); return; } // Draw from an object (food, beaker, etc) - if (_solutions.TryGetDrawableSolution(target, out var drawableSolution)) + if (_solutionContainers.TryGetDrawableSolution(target, out var drawableSolution, out _)) { - TryDraw(component, injector, target, drawableSolution, user); + TryDraw(injector, target, drawableSolution.Value, user); } else { _popup.PopupEntity(Loc.GetString("injector-component-cannot-draw-message", - ("target", Identity.Entity(target, EntityManager))), injector, user); + ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); } } } - private void OnSolutionChange(EntityUid uid, InjectorComponent component, SolutionChangedEvent args) + private void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { - Dirty(component); + Dirty(entity); } - private void OnInjectorGetState(EntityUid uid, InjectorComponent component, ref ComponentGetState args) + private void OnInjectorGetState(Entity entity, ref ComponentGetState args) { - _solutions.TryGetSolution(uid, InjectorComponent.SolutionName, out var solution); + _solutionContainers.TryGetSolution(entity.Owner, InjectorComponent.SolutionName, out _, out var solution); var currentVolume = solution?.Volume ?? FixedPoint2.Zero; var maxVolume = solution?.MaxVolume ?? FixedPoint2.Zero; - args.State = new SharedInjectorComponent.InjectorComponentState(currentVolume, maxVolume, component.ToggleState); + args.State = new SharedInjectorComponent.InjectorComponentState(currentVolume, maxVolume, entity.Comp.ToggleState); } - private void OnInjectDoAfter(EntityUid uid, InjectorComponent component, DoAfterEvent args) + private void OnInjectDoAfter(Entity entity, ref InjectorDoAfterEvent args) { if (args.Cancelled || args.Handled || args.Args.Target == null) return; - UseInjector(args.Args.Target.Value, args.Args.User, uid, component); + UseInjector(entity, args.Args.Target.Value, args.Args.User); args.Handled = true; } - private void OnInjectorAfterInteract(EntityUid uid, InjectorComponent component, AfterInteractEvent args) + private void OnInjectorAfterInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled || !args.CanReach) return; //Make sure we have the attacking entity - if (args.Target is not { Valid: true } target || !HasComp(uid)) + if (args.Target is not { Valid: true } target || !HasComp(entity)) return; // Is the target a mob? If yes, use a do-after to give them time to respond. if (HasComp(target) || HasComp(target)) { // Are use using an injector capible of targeting a mob? - if (component.IgnoreMobs) + if (entity.Comp.IgnoreMobs) return; - InjectDoAfter(component, args.User, target, uid); + InjectDoAfter(entity, target, args.User); args.Handled = true; return; } - UseInjector(target, args.User, uid, component); + UseInjector(entity, target, args.User); args.Handled = true; } - private void OnInjectorStartup(EntityUid uid, InjectorComponent component, ComponentStartup args) + private void OnInjectorStartup(Entity entity, ref ComponentStartup args) { // ???? why ????? - Dirty(component); + Dirty(entity); } - private void OnInjectorUse(EntityUid uid, InjectorComponent component, UseInHandEvent args) + private void OnInjectorUse(Entity entity, ref UseInHandEvent args) { if (args.Handled) return; - Toggle(component, args.User, uid); + Toggle(entity, args.User); args.Handled = true; } /// /// Toggle between draw/inject state if applicable /// - private void Toggle(InjectorComponent component, EntityUid user, EntityUid injector) + private void Toggle(Entity injector, EntityUid user) { - if (component.InjectOnly) + if (injector.Comp.InjectOnly) { return; } string msg; - switch (component.ToggleState) + switch (injector.Comp.ToggleState) { case SharedInjectorComponent.InjectorToggleMode.Inject: - component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw; + injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw; msg = "injector-component-drawing-text"; break; case SharedInjectorComponent.InjectorToggleMode.Draw: - component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject; + injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject; msg = "injector-component-injecting-text"; break; default: @@ -209,18 +214,18 @@ public sealed partial class ChemistrySystem /// /// Send informative pop-up messages and wait for a do-after to complete. /// - private void InjectDoAfter(InjectorComponent component, EntityUid user, EntityUid target, EntityUid injector) + private void InjectDoAfter(Entity injector, EntityUid target, EntityUid user) { // Create a pop-up for the user _popup.PopupEntity(Loc.GetString("injector-component-injecting-user"), target, user); - if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)) + if (!_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, out var solution)) return; - var actualDelay = MathF.Max(component.Delay, 1f); + var actualDelay = MathF.Max(injector.Comp.Delay, 1f); // Injections take 0.5 seconds longer per additional 5u - actualDelay += (float) component.TransferAmount / component.Delay - 0.5f; + actualDelay += (float) injector.Comp.TransferAmount / injector.Comp.Delay - 0.5f; var isTarget = user != target; @@ -244,7 +249,7 @@ public sealed partial class ChemistrySystem } // Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same. - if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) + if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) { _adminLogger.Add(LogType.ForceFeed, $"{EntityManager.ToPrettyString(user):user} is attempting to inject {EntityManager.ToPrettyString(target):target} with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}"); @@ -255,11 +260,11 @@ public sealed partial class ChemistrySystem // Self-injections take half as long. actualDelay /= 2; - if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) + if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) _adminLogger.Add(LogType.Ingestion, $"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}."); } - _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, actualDelay, new InjectorDoAfterEvent(), injector, target: target, used: injector) + _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, actualDelay, new InjectorDoAfterEvent(), injector.Owner, target: target, used: injector.Owner) { BreakOnUserMove = true, BreakOnDamage = true, @@ -268,77 +273,80 @@ public sealed partial class ChemistrySystem }); } - private void TryInjectIntoBloodstream(InjectorComponent component, EntityUid injector, EntityUid target, BloodstreamComponent targetBloodstream, EntityUid user) + private void TryInjectIntoBloodstream(Entity injector, Entity target, EntityUid user) { // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetBloodstream.ChemicalSolution.AvailableVolume); + if (!_solutionContainers.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, ref target.Comp.ChemicalSolution, out var chemSolution)) + { + _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); + return; + } + var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, chemSolution.AvailableVolume); if (realTransferAmount <= 0) { - _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", Identity.Entity(target, EntityManager))), injector, user); + _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); return; } // Move units from attackSolution to targetSolution - var removedSolution = _solutions.SplitSolution(user, targetBloodstream.ChemicalSolution, realTransferAmount); + var removedSolution = _solutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, realTransferAmount); - _blood.TryAddToChemicals(target, removedSolution, targetBloodstream); + _blood.TryAddToChemicals(target, removedSolution, target.Comp); _reactiveSystem.DoEntityReaction(target, removedSolution, ReactionMethod.Injection); _popup.PopupEntity(Loc.GetString("injector-component-inject-success-message", ("amount", removedSolution.Volume), - ("target", Identity.Entity(target, EntityManager))), injector, user); + ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - Dirty(component); - AfterInject(component, injector, target); + Dirty(injector); + AfterInject(injector, target); } - private void TryInject(InjectorComponent component, EntityUid injector, EntityUid targetEntity, Solution targetSolution, EntityUid user, bool asRefill) + private void TryInject(Entity injector, EntityUid targetEntity, Entity targetSolution, EntityUid user, bool asRefill) { - if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution) - || solution.Volume == 0) + if (!_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out var soln, out var solution) || solution.Volume == 0) return; // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetSolution.AvailableVolume); + var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, targetSolution.Comp.Solution.AvailableVolume); if (realTransferAmount <= 0) { _popup.PopupEntity(Loc.GetString("injector-component-target-already-full-message", ("target", Identity.Entity(targetEntity, EntityManager))), - injector, user); + injector.Owner, user); return; } // Move units from attackSolution to targetSolution Solution removedSolution; if (TryComp(targetEntity, out var stack)) - removedSolution = _solutions.SplitStackSolution(injector, solution, realTransferAmount, stack.Count); + removedSolution = _solutionContainers.SplitStackSolution(soln.Value, realTransferAmount, stack.Count); else - removedSolution = _solutions.SplitSolution(injector, solution, realTransferAmount); + removedSolution = _solutionContainers.SplitSolution(soln.Value, realTransferAmount); _reactiveSystem.DoEntityReaction(targetEntity, removedSolution, ReactionMethod.Injection); if (!asRefill) - _solutions.Inject(targetEntity, targetSolution, removedSolution); + _solutionContainers.Inject(targetEntity, targetSolution, removedSolution); else - _solutions.Refill(targetEntity, targetSolution, removedSolution); + _solutionContainers.Refill(targetEntity, targetSolution, removedSolution); _popup.PopupEntity(Loc.GetString("injector-component-transfer-success-message", ("amount", removedSolution.Volume), - ("target", Identity.Entity(targetEntity, EntityManager))), injector, user); + ("target", Identity.Entity(targetEntity, EntityManager))), injector.Owner, user); - Dirty(component); - AfterInject(component, injector, targetEntity); + Dirty(injector); + AfterInject(injector, targetEntity); } - private void AfterInject(InjectorComponent component, EntityUid injector, EntityUid target) + private void AfterInject(Entity injector, EntityUid target) { // Automatically set syringe to draw after completely draining it. - if (_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution) - && solution.Volume == 0) + if (_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, out var solution) && solution.Volume == 0) { - component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw; + injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw; } // Leave some DNA from the injectee on it @@ -346,13 +354,12 @@ public sealed partial class ChemistrySystem RaiseLocalEvent(target, ref ev); } - private void AfterDraw(InjectorComponent component, EntityUid injector, EntityUid target) + private void AfterDraw(Entity injector, EntityUid target) { // Automatically set syringe to inject after completely filling it. - if (_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution) - && solution.AvailableVolume == 0) + if (_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, out var solution) && solution.AvailableVolume == 0) { - component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject; + injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject; } // Leave some DNA from the drawee on it @@ -360,70 +367,68 @@ public sealed partial class ChemistrySystem RaiseLocalEvent(target, ref ev); } - private void TryDraw(InjectorComponent component, EntityUid injector, EntityUid targetEntity, Solution targetSolution, EntityUid user, BloodstreamComponent? stream = null) + private void TryDraw(Entity injector, Entity target, Entity targetSolution, EntityUid user) { - if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution) - || solution.AvailableVolume == 0) + if (!_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out var soln, out var solution) || solution.AvailableVolume == 0) { return; } // Get transfer amount. May be smaller than _transferAmount if not enough room, also make sure there's room in the injector - var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetSolution.Volume, solution.AvailableVolume); + var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, targetSolution.Comp.Solution.Volume, solution.AvailableVolume); if (realTransferAmount <= 0) { - _popup.PopupEntity(Loc.GetString("injector-component-target-is-empty-message", ("target", Identity.Entity(targetEntity, EntityManager))), - injector, user); + _popup.PopupEntity(Loc.GetString("injector-component-target-is-empty-message", ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); return; } // We have some snowflaked behavior for streams. - if (stream != null) + if (target.Comp != null) { - DrawFromBlood(user, injector, targetEntity, component, solution, stream, realTransferAmount); + DrawFromBlood(injector, (target.Owner, target.Comp), soln.Value, realTransferAmount, user); return; } // Move units from attackSolution to targetSolution - var removedSolution = _solutions.Draw(targetEntity, targetSolution, realTransferAmount); + var removedSolution = _solutionContainers.Draw(target.Owner, targetSolution, realTransferAmount); - if (!_solutions.TryAddSolution(injector, solution, removedSolution)) + if (!_solutionContainers.TryAddSolution(soln.Value, removedSolution)) { return; } _popup.PopupEntity(Loc.GetString("injector-component-draw-success-message", ("amount", removedSolution.Volume), - ("target", Identity.Entity(targetEntity, EntityManager))), injector, user); + ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - Dirty(component); - AfterDraw(component, injector, targetEntity); + Dirty(injector); + AfterDraw(injector, target); } - private void DrawFromBlood(EntityUid user, EntityUid injector, EntityUid target, InjectorComponent component, Solution injectorSolution, BloodstreamComponent stream, FixedPoint2 transferAmount) + private void DrawFromBlood(Entity injector, Entity target, Entity injectorSolution, FixedPoint2 transferAmount, EntityUid user) { var drawAmount = (float) transferAmount; - var bloodAmount = drawAmount; - var chemAmount = 0f; - if (stream.ChemicalSolution.Volume > 0f) // If they have stuff in their chem stream, we'll draw some of that + + if (_solutionContainers.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, ref target.Comp.ChemicalSolution)) { - bloodAmount = drawAmount * 0.85f; - chemAmount = drawAmount * 0.15f; + var chemTemp = _solutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, drawAmount * 0.15f); + _solutionContainers.TryAddSolution(injectorSolution, chemTemp); + drawAmount -= (float) chemTemp.Volume; } - var bloodTemp = stream.BloodSolution.SplitSolution(bloodAmount); - var chemTemp = stream.ChemicalSolution.SplitSolution(chemAmount); - - _solutions.TryAddSolution(injector, injectorSolution, bloodTemp); - _solutions.TryAddSolution(injector, injectorSolution, chemTemp); + if (_solutionContainers.ResolveSolution(target.Owner, target.Comp.BloodSolutionName, ref target.Comp.BloodSolution)) + { + var bloodTemp = _solutionContainers.SplitSolution(target.Comp.BloodSolution.Value, drawAmount); + _solutionContainers.TryAddSolution(injectorSolution, bloodTemp); + } _popup.PopupEntity(Loc.GetString("injector-component-draw-success-message", ("amount", transferAmount), - ("target", Identity.Entity(target, EntityManager))), injector, user); + ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - Dirty(component); - AfterDraw(component, injector, target); + Dirty(injector); + AfterDraw(injector, target); } - } diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs index 759d403ace..a2b4f399e2 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs @@ -1,13 +1,12 @@ using Content.Server.Administration.Logs; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Interaction; using Content.Server.Popups; -using Content.Shared.CombatMode; using Content.Shared.Chemistry; -using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.CombatMode; using Content.Shared.DoAfter; using Content.Shared.Mobs.Systems; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; namespace Content.Server.Chemistry.EntitySystems; @@ -24,7 +23,7 @@ public sealed partial class ChemistrySystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedCombatModeSystem _combat = default!; - [Dependency] private readonly SolutionContainerSystem _solutions = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainers = default!; public override void Initialize() { diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs index cb4feb8064..9c1b5130a2 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs @@ -1,20 +1,21 @@ -using System.Linq; -using System.Diagnostics.CodeAnalysis; using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.FixedPoint; +using Content.Shared.Forensics; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Mobs.Components; -using Content.Shared.Weapons.Melee.Events; using Content.Shared.Timing; +using Content.Shared.Weapons.Melee.Events; using Robust.Shared.GameStates; -using Content.Shared.Forensics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; namespace Content.Server.Chemistry.EntitySystems { @@ -26,33 +27,33 @@ namespace Content.Server.Chemistry.EntitySystems { SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnAttack); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent(OnHypoGetState); } - private void OnHypoGetState(EntityUid uid, HyposprayComponent component, ref ComponentGetState args) + private void OnHypoGetState(Entity entity, ref ComponentGetState args) { - args.State = _solutions.TryGetSolution(uid, component.SolutionName, out var solution) + args.State = _solutionContainers.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out _, out var solution) ? new HyposprayComponentState(solution.Volume, solution.MaxVolume) : new HyposprayComponentState(FixedPoint2.Zero, FixedPoint2.Zero); } - private void OnUseInHand(EntityUid uid, HyposprayComponent component, UseInHandEvent args) + private void OnUseInHand(Entity entity, ref UseInHandEvent args) { if (args.Handled) return; - TryDoInject(uid, args.User, args.User); + TryDoInject(entity, args.User, args.User); args.Handled = true; } - private void OnSolutionChange(EntityUid uid, HyposprayComponent component, SolutionChangedEvent args) + private void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { - Dirty(component); + Dirty(entity); } - public void OnAfterInteract(EntityUid uid, HyposprayComponent component, AfterInteractEvent args) + public void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { if (!args.CanReach) return; @@ -60,21 +61,20 @@ namespace Content.Server.Chemistry.EntitySystems var target = args.Target; var user = args.User; - TryDoInject(uid, target, user); + TryDoInject(entity, target, user); } - public void OnAttack(EntityUid uid, HyposprayComponent component, MeleeHitEvent args) + public void OnAttack(Entity entity, ref MeleeHitEvent args) { if (!args.HitEntities.Any()) return; - TryDoInject(uid, args.HitEntities.First(), args.User); + TryDoInject(entity, args.HitEntities.First(), args.User); } - public bool TryDoInject(EntityUid uid, EntityUid? target, EntityUid user, HyposprayComponent? component=null) + public bool TryDoInject(Entity hypo, EntityUid? target, EntityUid user) { - if (!Resolve(uid, ref component)) - return false; + var (uid, component) = hypo; if (!EligibleEntity(target, _entMan, component)) return false; @@ -92,15 +92,13 @@ namespace Content.Server.Chemistry.EntitySystems target = user; } - _solutions.TryGetSolution(uid, component.SolutionName, out var hypoSpraySolution); - - if (hypoSpraySolution == null || hypoSpraySolution.Volume == 0) + if (!_solutionContainers.TryGetSolution(uid, component.SolutionName, out var hypoSpraySoln, out var hypoSpraySolution) || hypoSpraySolution.Volume == 0) { _popup.PopupCursor(Loc.GetString("hypospray-component-empty-message"), user); return true; } - if (!_solutions.TryGetInjectableSolution(target.Value, out var targetSolution)) + if (!_solutionContainers.TryGetInjectableSolution(target.Value, out var targetSoln, out var targetSolution)) { _popup.PopupCursor(Loc.GetString("hypospray-cant-inject", ("target", Identity.Entity(target.Value, _entMan))), user); return false; @@ -127,17 +125,17 @@ namespace Content.Server.Chemistry.EntitySystems if (realTransferAmount <= 0) { - _popup.PopupCursor(Loc.GetString("hypospray-component-transfer-already-full-message",("owner", target)), user); + _popup.PopupCursor(Loc.GetString("hypospray-component-transfer-already-full-message", ("owner", target)), user); return true; } // Move units from attackSolution to targetSolution - var removedSolution = _solutions.SplitSolution(uid, hypoSpraySolution, realTransferAmount); + var removedSolution = _solutionContainers.SplitSolution(hypoSpraySoln.Value, realTransferAmount); if (!targetSolution.CanAddSolution(removedSolution)) return true; _reactiveSystem.DoEntityReaction(target.Value, removedSolution, ReactionMethod.Injection); - _solutions.TryAddSolution(target.Value, targetSolution, removedSolution); + _solutionContainers.TryAddSolution(targetSoln.Value, removedSolution); var ev = new TransferDnaEvent { Donor = target.Value, Recipient = uid }; RaiseLocalEvent(target.Value, ref ev); diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystemMixer.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystemMixer.cs index 207282421d..0230671ec9 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistrySystemMixer.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystemMixer.cs @@ -1,10 +1,6 @@ -using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reaction; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Robust.Shared.Player; namespace Content.Server.Chemistry.EntitySystems; @@ -15,27 +11,26 @@ public sealed partial class ChemistrySystem SubscribeLocalEvent(OnAfterInteract); } - private void OnAfterInteract(EntityUid uid, ReactionMixerComponent component, AfterInteractEvent args) + private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { if (!args.Target.HasValue || !args.CanReach) return; - var mixAttemptEvent = new MixingAttemptEvent(uid); - RaiseLocalEvent(uid, ref mixAttemptEvent); - if(mixAttemptEvent.Cancelled) + var mixAttemptEvent = new MixingAttemptEvent(entity); + RaiseLocalEvent(entity, ref mixAttemptEvent); + if (mixAttemptEvent.Cancelled) { return; } - Solution? solution = null; - if (!_solutions.TryGetMixableSolution(args.Target.Value, out solution)) - return; + if (!_solutionContainers.TryGetMixableSolution(args.Target.Value, out var solution)) + return; - _popup.PopupEntity(Loc.GetString(component.MixMessage, ("mixed", Identity.Entity(args.Target.Value, EntityManager)), ("mixer", Identity.Entity(uid, EntityManager))), args.User, args.User); + _popup.PopupEntity(Loc.GetString(entity.Comp.MixMessage, ("mixed", Identity.Entity(args.Target.Value, EntityManager)), ("mixer", Identity.Entity(entity.Owner, EntityManager))), args.User, args.User); - _solutions.UpdateChemicals(args.Target.Value, solution, true, component); + _solutionContainers.UpdateChemicals(solution.Value, true, entity.Comp); - var afterMixingEvent = new AfterMixingEvent(uid, args.Target.Value); - RaiseLocalEvent(uid, afterMixingEvent); + var afterMixingEvent = new AfterMixingEvent(entity, args.Target.Value); + RaiseLocalEvent(entity, afterMixingEvent); } } diff --git a/Content.Server/Chemistry/EntitySystems/DeleteOnSolutionEmptySystem.cs b/Content.Server/Chemistry/EntitySystems/DeleteOnSolutionEmptySystem.cs index fd7933e66a..cfc6ba988a 100644 --- a/Content.Server/Chemistry/EntitySystems/DeleteOnSolutionEmptySystem.cs +++ b/Content.Server/Chemistry/EntitySystems/DeleteOnSolutionEmptySystem.cs @@ -1,4 +1,5 @@ using Content.Server.Chemistry.Components.DeleteOnSolutionEmptyComponent; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; @@ -12,27 +13,27 @@ namespace Content.Server.Chemistry.EntitySystems.DeleteOnSolutionEmptySystem { base.Initialize(); SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); } - public void OnStartup(EntityUid uid, DeleteOnSolutionEmptyComponent component, ComponentStartup args) + public void OnStartup(Entity entity, ref ComponentStartup args) { - CheckSolutions(uid, component); + CheckSolutions(entity); } - public void OnSolutionChange(EntityUid uid, DeleteOnSolutionEmptyComponent component, SolutionChangedEvent args) + public void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { - CheckSolutions(uid, component); + CheckSolutions(entity); } - public void CheckSolutions(EntityUid uid, DeleteOnSolutionEmptyComponent component) + public void CheckSolutions(Entity entity) { - if (!EntityManager.HasComponent(uid)) + if (!TryComp(entity, out SolutionContainerManagerComponent? solutions)) return; - if (_solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution)) + if (_solutionContainerSystem.TryGetSolution((entity.Owner, solutions), entity.Comp.Solution, out _, out var solution)) if (solution.Volume <= 0) - EntityManager.QueueDeleteEntity(uid); + EntityManager.QueueDeleteEntity(entity); } } } diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs index 3768ee1051..aeb141fe35 100644 --- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs @@ -1,6 +1,6 @@ -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Dispenser; using Content.Shared.Chemistry.EntitySystems; @@ -15,6 +15,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.Prototypes; +using System.Linq; namespace Content.Server.Chemistry.EntitySystems { @@ -36,7 +37,7 @@ namespace Content.Server.Chemistry.EntitySystems base.Initialize(); SubscribeLocalEvent(SubscribeUpdateUiState); - SubscribeLocalEvent(SubscribeUpdateUiState); + SubscribeLocalEvent(SubscribeUpdateUiState); SubscribeLocalEvent(SubscribeUpdateUiState); SubscribeLocalEvent(SubscribeUpdateUiState); SubscribeLocalEvent(SubscribeUpdateUiState); @@ -68,7 +69,7 @@ namespace Content.Server.Chemistry.EntitySystems if (container is not { Valid: true }) return null; - if (_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var solution)) + if (_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var solution)) { return new ContainerInfo(Name(container.Value), solution.Volume, solution.MaxVolume) { @@ -122,10 +123,10 @@ namespace Content.Server.Chemistry.EntitySystems return; var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName); - if (outputContainer is not {Valid: true} || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution)) + if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _)) return; - if (_solutionContainerSystem.TryAddReagent(outputContainer.Value, solution, message.ReagentId, (int)reagentDispenser.Comp.DispenseAmount, out var dispensedAmount) + if (_solutionContainerSystem.TryAddReagent(solution.Value, message.ReagentId, (int) reagentDispenser.Comp.DispenseAmount, out var dispensedAmount) && message.Session.AttachedEntity is not null) { _adminLogger.Add(LogType.ChemicalReaction, LogImpact.Medium, @@ -139,10 +140,10 @@ namespace Content.Server.Chemistry.EntitySystems private void OnClearContainerSolutionMessage(Entity reagentDispenser, ref ReagentDispenserClearContainerSolutionMessage message) { var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName); - if (outputContainer is not {Valid: true} || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution)) + if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _)) return; - _solutionContainerSystem.RemoveAllSolution(outputContainer.Value, solution); + _solutionContainerSystem.RemoveAllSolution(solution.Value); UpdateUiState(reagentDispenser); ClickSound(reagentDispenser); } diff --git a/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs b/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs index b75aa311e3..e1cdfd2066 100644 --- a/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; using Content.Shared.Popups; @@ -16,21 +17,23 @@ public sealed class RehydratableSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); } - private void OnSolutionChange(EntityUid uid, RehydratableComponent comp, SolutionChangedEvent args) + private void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { - var quantity = _solutions.GetTotalPrototypeQuantity(uid, comp.CatalystPrototype); - if (quantity != FixedPoint2.Zero && quantity >= comp.CatalystMinimum) + var quantity = _solutions.GetTotalPrototypeQuantity(entity, entity.Comp.CatalystPrototype); + if (quantity != FixedPoint2.Zero && quantity >= entity.Comp.CatalystMinimum) { - Expand(uid, comp); + Expand(entity); } } // Try not to make this public if you can help it. - private void Expand(EntityUid uid, RehydratableComponent comp) + private void Expand(Entity entity) { + var (uid, comp) = entity; + _popups.PopupEntity(Loc.GetString("rehydratable-component-expands-message", ("owner", uid)), uid); var randomMob = _random.Pick(comp.PossibleSpawns); diff --git a/Content.Server/Chemistry/EntitySystems/SolutionHeaterSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionHeaterSystem.cs index 3e839bee50..1ef589ab5c 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionHeaterSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionHeaterSystem.cs @@ -1,10 +1,10 @@ using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Construction; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Placeable; namespace Content.Server.Chemistry.EntitySystems; @@ -13,7 +13,7 @@ public sealed class SolutionHeaterSystem : EntitySystem { [Dependency] private readonly PowerReceiverSystem _powerReceiver = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SolutionContainerSystem _solution = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; /// public override void Initialize() @@ -51,41 +51,41 @@ public sealed class SolutionHeaterSystem : EntitySystem RemComp(uid); } - private void OnPowerChanged(EntityUid uid, SolutionHeaterComponent component, ref PowerChangedEvent args) + private void OnPowerChanged(Entity entity, ref PowerChangedEvent args) { - var placer = Comp(uid); + var placer = Comp(entity); if (args.Powered && placer.PlacedEntities.Count > 0) { - TurnOn(uid); + TurnOn(entity); } else { - TurnOff(uid); + TurnOff(entity); } } - private void OnRefreshParts(EntityUid uid, SolutionHeaterComponent component, RefreshPartsEvent args) + private void OnRefreshParts(Entity entity, ref RefreshPartsEvent args) { - var heatRating = args.PartRatings[component.MachinePartHeatMultiplier] - 1; + var heatRating = args.PartRatings[entity.Comp.MachinePartHeatMultiplier] - 1; - component.HeatPerSecond = component.BaseHeatPerSecond * MathF.Pow(component.PartRatingHeatMultiplier, heatRating); + entity.Comp.HeatPerSecond = entity.Comp.BaseHeatPerSecond * MathF.Pow(entity.Comp.PartRatingHeatMultiplier, heatRating); } - private void OnUpgradeExamine(EntityUid uid, SolutionHeaterComponent component, UpgradeExamineEvent args) + private void OnUpgradeExamine(Entity entity, ref UpgradeExamineEvent args) { - args.AddPercentageUpgrade("solution-heater-upgrade-heat", component.HeatPerSecond / component.BaseHeatPerSecond); + args.AddPercentageUpgrade("solution-heater-upgrade-heat", entity.Comp.HeatPerSecond / entity.Comp.BaseHeatPerSecond); } - private void OnItemPlaced(EntityUid uid, SolutionHeaterComponent comp, ref ItemPlacedEvent args) + private void OnItemPlaced(Entity entity, ref ItemPlacedEvent args) { - TryTurnOn(uid); + TryTurnOn(entity); } - private void OnItemRemoved(EntityUid uid, SolutionHeaterComponent component, ref ItemRemovedEvent args) + private void OnItemRemoved(Entity entity, ref ItemRemovedEvent args) { - var placer = Comp(uid); + var placer = Comp(entity); if (placer.PlacedEntities.Count == 0) // Last entity was removed - TurnOff(uid); + TurnOff(entity); } public override void Update(float frameTime) @@ -97,13 +97,13 @@ public sealed class SolutionHeaterSystem : EntitySystem { foreach (var heatingEntity in placer.PlacedEntities) { - if (!TryComp(heatingEntity, out var solution)) + if (!TryComp(heatingEntity, out var container)) continue; var energy = heater.HeatPerSecond * frameTime; - foreach (var s in solution.Solutions.Values) + foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((heatingEntity, container))) { - _solution.AddThermalEnergy(heatingEntity, s, energy); + _solutionContainer.AddThermalEnergy(soln, energy); } } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs index e053ce9720..f881240a09 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs @@ -1,19 +1,17 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Inventory; using JetBrains.Annotations; using Robust.Shared.Physics.Events; -using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.EntitySystems { [UsedImplicitly] internal sealed class SolutionInjectOnCollideSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _protoManager = default!; - [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainersSystem = default!; [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; @@ -30,7 +28,7 @@ namespace Content.Server.Chemistry.EntitySystems if (!args.OtherBody.Hard || !EntityManager.TryGetComponent(target, out var bloodstream) || - !_solutionsSystem.TryGetInjectableSolution(ent, out var solution)) + !_solutionContainersSystem.TryGetInjectableSolution(ent.Owner, out var solution, out _)) { return; } @@ -44,7 +42,7 @@ namespace Content.Server.Chemistry.EntitySystems return; } - var solRemoved = solution.SplitSolution(component.TransferAmount); + var solRemoved = _solutionContainersSystem.SplitSolution(solution.Value, component.TransferAmount); var solRemovedVol = solRemoved.Volume; var solToInject = solRemoved.SplitSolution(solRemovedVol * component.TransferEfficiency); diff --git a/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs index c918fa929c..e6e003a7f5 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionPurgeSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; -using Content.Shared.FixedPoint; using Robust.Shared.Timing; namespace Content.Server.Chemistry.EntitySystems; @@ -30,13 +29,13 @@ public sealed class SolutionPurgeSystem : EntitySystem // timer ignores if it's empty, it's just a fixed cycle purge.NextPurgeTime += purge.Duration; - if (_solutionContainer.TryGetSolution(uid, purge.Solution, out var solution, manager)) - _solutionContainer.SplitSolutionWithout(uid, solution, purge.Quantity, purge.Preserve.ToArray()); + if (_solutionContainer.TryGetSolution((uid, manager), purge.Solution, out var solution)) + _solutionContainer.SplitSolutionWithout(solution.Value, purge.Quantity, purge.Preserve.ToArray()); } } - private void OnUnpaused(EntityUid uid, SolutionPurgeComponent comp, ref EntityUnpausedEvent args) + private void OnUnpaused(Entity entity, ref EntityUnpausedEvent args) { - comp.NextPurgeTime += args.PausedTime; + entity.Comp.NextPurgeTime += args.PausedTime; } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs index c2b8efac6f..6685fb485f 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Random; using Content.Shared.Random.Helpers; @@ -21,13 +21,12 @@ public sealed class SolutionRandomFillSystem : EntitySystem SubscribeLocalEvent(OnRandomSolutionFillMapInit); } - private void OnRandomSolutionFillMapInit(EntityUid uid, RandomFillSolutionComponent component, MapInitEvent args) + private void OnRandomSolutionFillMapInit(Entity entity, ref MapInitEvent args) { - if (component.WeightedRandomId == null) + if (entity.Comp.WeightedRandomId == null) return; - var target = _solutionsSystem.EnsureSolution(uid, component.Solution); - var pick = _proto.Index(component.WeightedRandomId).Pick(_random); + var pick = _proto.Index(entity.Comp.WeightedRandomId).Pick(_random); var reagent = pick.reagent; var quantity = pick.quantity; @@ -38,6 +37,7 @@ public sealed class SolutionRandomFillSystem : EntitySystem return; } - target.AddReagent(reagent, quantity); + var target = _solutionsSystem.EnsureSolutionEntity(entity.Owner, entity.Comp.Solution, pick.quantity, null, out _); + _solutionsSystem.TryAddReagent(target, reagent, quantity, out _); } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs index 95908dd703..37458846e3 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs @@ -1,7 +1,7 @@ using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.Timing; @@ -31,7 +31,7 @@ public sealed class SolutionRegenerationSystem : EntitySystem // timer ignores if its full, it's just a fixed cycle regen.NextRegenTime = _timing.CurTime + regen.Duration; - if (_solutionContainer.TryGetSolution(uid, regen.Solution, out var solution, manager)) + if (_solutionContainer.ResolveSolution((uid, manager), regen.SolutionName, ref regen.Solution, out var solution)) { var amount = FixedPoint2.Min(solution.AvailableVolume, regen.Generated.Volume); if (amount <= FixedPoint2.Zero) @@ -48,13 +48,13 @@ public sealed class SolutionRegenerationSystem : EntitySystem generated = regen.Generated.Clone().SplitSolution(amount); } - _solutionContainer.TryAddSolution(uid, solution, generated); + _solutionContainer.TryAddSolution(regen.Solution.Value, generated); } } } - private void OnUnpaused(EntityUid uid, SolutionRegenerationComponent comp, ref EntityUnpausedEvent args) + private void OnUnpaused(Entity entity, ref EntityUnpausedEvent args) { - comp.NextRegenTime += args.PausedTime; + entity.Comp.NextRegenTime += args.PausedTime; } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs index 04aa6546a9..7518b45a8b 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs @@ -1,12 +1,10 @@ using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Explosion.EntitySystems; using Content.Server.Popups; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; -using Content.Shared.FixedPoint; using Content.Shared.Interaction; -using Robust.Shared.Player; namespace Content.Server.Chemistry.EntitySystems; @@ -21,7 +19,7 @@ namespace Content.Server.Chemistry.EntitySystems; /// public sealed class SolutionSpikableSystem : EntitySystem { - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly TriggerSystem _triggerSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; @@ -30,9 +28,9 @@ public sealed class SolutionSpikableSystem : EntitySystem SubscribeLocalEvent(OnInteractUsing); } - private void OnInteractUsing(EntityUid uid, RefillableSolutionComponent target, InteractUsingEvent args) + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { - TrySpike(args.Used, args.Target, args.User, target); + TrySpike(args.Used, args.Target, args.User, entity.Comp); } /// @@ -49,8 +47,8 @@ public sealed class SolutionSpikableSystem : EntitySystem { if (!Resolve(source, ref spikableSource, ref managerSource, false) || !Resolve(target, ref spikableTarget, ref managerTarget, false) - || !_solutionSystem.TryGetRefillableSolution(target, out var targetSolution, managerTarget, spikableTarget) - || !managerSource.Solutions.TryGetValue(spikableSource.SourceSolution, out var sourceSolution)) + || !_solutionContainerSystem.TryGetRefillableSolution((target, spikableTarget, managerTarget), out var targetSoln, out var targetSolution) + || !_solutionContainerSystem.TryGetSolution((source, managerSource), spikableSource.SourceSolution, out _, out var sourceSolution)) { return; } @@ -61,7 +59,7 @@ public sealed class SolutionSpikableSystem : EntitySystem return; } - if (!_solutionSystem.ForceAddSolution(target, targetSolution, sourceSolution)) + if (!_solutionContainerSystem.ForceAddSolution(targetSoln.Value, sourceSolution)) return; _popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user); diff --git a/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs index d2666417cf..1ed5cec8dd 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs @@ -1,14 +1,14 @@ using Content.Server.Administration.Logs; -using Content.Shared.Verbs; -using JetBrains.Annotations; -using Robust.Server.GameObjects; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Popups; +using Content.Shared.Verbs; +using JetBrains.Annotations; +using Robust.Server.GameObjects; using Robust.Shared.Player; namespace Content.Server.Chemistry.EntitySystems @@ -24,7 +24,7 @@ namespace Content.Server.Chemistry.EntitySystems /// /// Default transfer amounts for the set-transfer verb. /// - public static readonly List DefaultTransferAmounts = new() { 1, 5, 10, 25, 50, 100, 250, 500, 1000}; + public static readonly List DefaultTransferAmounts = new() { 1, 5, 10, 25, 50, 100, 250, 500, 1000 }; public override void Initialize() { @@ -35,17 +35,19 @@ namespace Content.Server.Chemistry.EntitySystems SubscribeLocalEvent(OnTransferAmountSetValueMessage); } - private void OnTransferAmountSetValueMessage(EntityUid uid, SolutionTransferComponent solutionTransfer, TransferAmountSetValueMessage message) + private void OnTransferAmountSetValueMessage(Entity entity, ref TransferAmountSetValueMessage message) { - var newTransferAmount = FixedPoint2.Clamp(message.Value, solutionTransfer.MinimumTransferAmount, solutionTransfer.MaximumTransferAmount); - solutionTransfer.TransferAmount = newTransferAmount; + var newTransferAmount = FixedPoint2.Clamp(message.Value, entity.Comp.MinimumTransferAmount, entity.Comp.MaximumTransferAmount); + entity.Comp.TransferAmount = newTransferAmount; - if (message.Session.AttachedEntity is {Valid: true} user) - _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", newTransferAmount)), uid, user); + if (message.Session.AttachedEntity is { Valid: true } user) + _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", newTransferAmount)), entity.Owner, user); } - private void AddSetTransferVerbs(EntityUid uid, SolutionTransferComponent component, GetVerbsEvent args) + private void AddSetTransferVerbs(Entity entity, ref GetVerbsEvent args) { + var (uid, component) = entity; + if (!args.CanAccess || !args.CanInteract || !component.CanChangeTransferAmount || args.Hands == null) return; @@ -56,15 +58,16 @@ namespace Content.Server.Chemistry.EntitySystems AlternativeVerb custom = new(); custom.Text = Loc.GetString("comp-solution-transfer-verb-custom-amount"); custom.Category = VerbCategory.SetTransferAmount; - custom.Act = () => _userInterfaceSystem.TryOpen(args.Target, TransferAmountUiKey.Key, actor.PlayerSession); + custom.Act = () => _userInterfaceSystem.TryOpen(uid, TransferAmountUiKey.Key, actor.PlayerSession); custom.Priority = 1; args.Verbs.Add(custom); // Add specific transfer verbs according to the container's size var priority = 0; + var user = args.User; foreach (var amount in DefaultTransferAmounts) { - if ( amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int()) + if (amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int()) continue; AlternativeVerb verb = new(); @@ -73,7 +76,7 @@ namespace Content.Server.Chemistry.EntitySystems verb.Act = () => { component.TransferAmount = FixedPoint2.New(amount); - _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), uid, args.User); + _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), uid, user); }; // we want to sort by size, not alphabetically by the verb text. @@ -84,18 +87,19 @@ namespace Content.Server.Chemistry.EntitySystems } } - private void OnAfterInteract(EntityUid uid, SolutionTransferComponent component, AfterInteractEvent args) + private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { if (!args.CanReach || args.Target == null) return; var target = args.Target!.Value; + var (uid, component) = entity; //Special case for reagent tanks, because normally clicking another container will give solution, not take it. - if (component.CanReceive && !EntityManager.HasComponent(target) // target must not be refillable (e.g. Reagent Tanks) - && _solutionContainerSystem.TryGetDrainableSolution(target, out var targetDrain) // target must be drainable - && EntityManager.TryGetComponent(uid, out RefillableSolutionComponent? refillComp) - && _solutionContainerSystem.TryGetRefillableSolution(uid, out var ownerRefill, refillable: refillComp)) + if (component.CanReceive && !EntityManager.HasComponent(target) // target must not be refillable (e.g. Reagent Tanks) + && _solutionContainerSystem.TryGetDrainableSolution(target, out var targetSoln, out _) // target must be drainable + && EntityManager.TryGetComponent(uid, out RefillableSolutionComponent? refillComp) + && _solutionContainerSystem.TryGetRefillableSolution((uid, refillComp, null), out var ownerSoln, out var ownerRefill)) { @@ -106,7 +110,7 @@ namespace Content.Server.Chemistry.EntitySystems transferAmount = FixedPoint2.Min(transferAmount, (FixedPoint2) refill.MaxRefill); // if the receiver has a smaller transfer limit, use that instead } - var transferred = Transfer(args.User, target, targetDrain, uid, ownerRefill, transferAmount); + var transferred = Transfer(args.User, target, targetSoln.Value, uid, ownerSoln.Value, transferAmount); if (transferred > 0) { var toTheBrim = ownerRefill.AvailableVolume == 0; @@ -122,8 +126,8 @@ namespace Content.Server.Chemistry.EntitySystems } // if target is refillable, and owner is drainable - if (component.CanSend && _solutionContainerSystem.TryGetRefillableSolution(target, out var targetRefill) - && _solutionContainerSystem.TryGetDrainableSolution(uid, out var ownerDrain)) + if (component.CanSend && _solutionContainerSystem.TryGetRefillableSolution(target, out targetSoln, out var targetRefill) + && _solutionContainerSystem.TryGetDrainableSolution(uid, out ownerSoln, out var ownerDrain)) { var transferAmount = component.TransferAmount; @@ -132,7 +136,7 @@ namespace Content.Server.Chemistry.EntitySystems transferAmount = FixedPoint2.Min(transferAmount, (FixedPoint2) refill.MaxRefill); } - var transferred = Transfer(args.User, uid, ownerDrain, target, targetRefill, transferAmount); + var transferred = Transfer(args.User, uid, ownerSoln.Value, target, targetSoln.Value, transferAmount); if (transferred > 0) { @@ -150,9 +154,9 @@ namespace Content.Server.Chemistry.EntitySystems /// The actual amount transferred. public FixedPoint2 Transfer(EntityUid user, EntityUid sourceEntity, - Solution source, + Entity source, EntityUid targetEntity, - Solution target, + Entity target, FixedPoint2 amount) { var transferAttempt = new SolutionTransferAttemptEvent(sourceEntity, targetEntity); @@ -165,7 +169,8 @@ namespace Content.Server.Chemistry.EntitySystems return FixedPoint2.Zero; } - if (source.Volume == 0) + var sourceSolution = source.Comp.Solution; + if (sourceSolution.Volume == 0) { _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-is-empty", ("target", sourceEntity)), sourceEntity, user); return FixedPoint2.Zero; @@ -179,19 +184,20 @@ namespace Content.Server.Chemistry.EntitySystems return FixedPoint2.Zero; } - if (target.AvailableVolume == 0) + var targetSolution = target.Comp.Solution; + if (targetSolution.AvailableVolume == 0) { _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-is-full", ("target", targetEntity)), targetEntity, user); return FixedPoint2.Zero; } - var actualAmount = FixedPoint2.Min(amount, FixedPoint2.Min(source.Volume, target.AvailableVolume)); + var actualAmount = FixedPoint2.Min(amount, FixedPoint2.Min(sourceSolution.Volume, targetSolution.AvailableVolume)); var solution = _solutionContainerSystem.Drain(sourceEntity, source, actualAmount); _solutionContainerSystem.Refill(targetEntity, target, solution); _adminLogger.Add(LogType.Action, LogImpact.Medium, - $"{EntityManager.ToPrettyString(user):player} transferred {string.Join(", ", solution.Contents)} to {EntityManager.ToPrettyString(targetEntity):entity}, which now contains {string.Join(", ", target.Contents)}"); + $"{EntityManager.ToPrettyString(user):player} transferred {string.Join(", ", solution.Contents)} to {EntityManager.ToPrettyString(targetEntity):entity}, which now contains {SolutionContainerSystem.ToPrettyString(targetSolution)}"); return actualAmount; } diff --git a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs index ac1cc1edd5..94a3fe2186 100644 --- a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Robust.Shared.Prototypes; @@ -16,38 +17,38 @@ public sealed class TransformableContainerSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); } - private void OnMapInit(EntityUid uid, TransformableContainerComponent component, MapInitEvent args) + private void OnMapInit(Entity entity, ref MapInitEvent args) { - var meta = MetaData(uid); - if (string.IsNullOrEmpty(component.InitialName)) + var meta = MetaData(entity.Owner); + if (string.IsNullOrEmpty(entity.Comp.InitialName)) { - component.InitialName = meta.EntityName; + entity.Comp.InitialName = meta.EntityName; } - if (string.IsNullOrEmpty(component.InitialDescription)) + if (string.IsNullOrEmpty(entity.Comp.InitialDescription)) { - component.InitialDescription = meta.EntityDescription; + entity.Comp.InitialDescription = meta.EntityDescription; } } - private void OnSolutionChange(EntityUid owner, TransformableContainerComponent component, - SolutionChangedEvent args) + private void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { - if (!_solutionsSystem.TryGetFitsInDispenser(owner, out var solution)) + if (!_solutionsSystem.TryGetFitsInDispenser(entity.Owner, out _, out var solution)) return; + //Transform container into initial state when emptied - if (component.CurrentReagent != null && solution.Contents.Count == 0) + if (entity.Comp.CurrentReagent != null && solution.Contents.Count == 0) { - CancelTransformation(owner, component); + CancelTransformation(entity); } //the biggest reagent in the solution decides the appearance var reagentId = solution.GetPrimaryReagentId(); //If biggest reagent didn't changed - don't change anything at all - if (component.CurrentReagent != null && component.CurrentReagent.ID == reagentId?.Prototype) + if (entity.Comp.CurrentReagent != null && entity.Comp.CurrentReagent.ID == reagentId?.Prototype) { return; } @@ -56,29 +57,29 @@ public sealed class TransformableContainerSystem : EntitySystem if (!string.IsNullOrWhiteSpace(reagentId?.Prototype) && _prototypeManager.TryIndex(reagentId.Value.Prototype, out ReagentPrototype? proto)) { - var metadata = MetaData(owner); + var metadata = MetaData(entity.Owner); var val = Loc.GetString("transformable-container-component-glass", ("name", proto.LocalizedName)); - _metadataSystem.SetEntityName(owner, val, metadata); - _metadataSystem.SetEntityDescription(owner, proto.LocalizedDescription, metadata); - component.CurrentReagent = proto; - component.Transformed = true; + _metadataSystem.SetEntityName(entity.Owner, val, metadata); + _metadataSystem.SetEntityDescription(entity.Owner, proto.LocalizedDescription, metadata); + entity.Comp.CurrentReagent = proto; + entity.Comp.Transformed = true; } } - private void CancelTransformation(EntityUid owner, TransformableContainerComponent component) + private void CancelTransformation(Entity entity) { - component.CurrentReagent = null; - component.Transformed = false; + entity.Comp.CurrentReagent = null; + entity.Comp.Transformed = false; - var metadata = MetaData(owner); + var metadata = MetaData(entity); - if (!string.IsNullOrEmpty(component.InitialName)) + if (!string.IsNullOrEmpty(entity.Comp.InitialName)) { - _metadataSystem.SetEntityName(owner, component.InitialName, metadata); + _metadataSystem.SetEntityName(entity.Owner, entity.Comp.InitialName, metadata); } - if (!string.IsNullOrEmpty(component.InitialDescription)) + if (!string.IsNullOrEmpty(entity.Comp.InitialDescription)) { - _metadataSystem.SetEntityDescription(owner, component.InitialDescription, metadata); + _metadataSystem.SetEntityDescription(entity.Owner, entity.Comp.InitialDescription, metadata); } } } diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs index 02788d5a47..2c23b8f039 100644 --- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs @@ -1,9 +1,8 @@ -using System.Numerics; using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Content.Shared.Physics; @@ -16,6 +15,7 @@ using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Spawners; +using System.Numerics; namespace Content.Server.Chemistry.EntitySystems { @@ -40,19 +40,20 @@ namespace Content.Server.Chemistry.EntitySystems SubscribeLocalEvent(HandleCollide); } - private void HandleCollide(EntityUid uid, VaporComponent component, ref StartCollideEvent args) + private void HandleCollide(Entity entity, ref StartCollideEvent args) { - if (!EntityManager.TryGetComponent(uid, out SolutionContainerManagerComponent? contents)) return; + if (!EntityManager.TryGetComponent(entity.Owner, out SolutionContainerManagerComponent? contents)) return; - foreach (var value in contents.Solutions.Values) + foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((entity.Owner, contents))) { - _reactive.DoEntityReaction(args.OtherEntity, value, ReactionMethod.Touch); + var solution = soln.Comp.Solution; + _reactive.DoEntityReaction(args.OtherEntity, solution, ReactionMethod.Touch); } // Check for collision with a impassable object (e.g. wall) and stop if ((args.OtherFixture.CollisionLayer & (int) CollisionGroup.Impassable) != 0 && args.OtherFixture.Hard) { - EntityManager.QueueDeleteEntity(uid); + EntityManager.QueueDeleteEntity(entity); } } @@ -83,28 +84,27 @@ namespace Content.Server.Chemistry.EntitySystems return false; } - if (!_solutionContainerSystem.TryGetSolution(vapor, VaporComponent.SolutionName, - out var vaporSolution)) + if (!_solutionContainerSystem.TryGetSolution(vapor.Owner, VaporComponent.SolutionName, out var vaporSolution)) { return false; } - return _solutionContainerSystem.TryAddSolution(vapor, vaporSolution, solution); + return _solutionContainerSystem.TryAddSolution(vaporSolution.Value, solution); } public override void Update(float frameTime) { var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var vaporComp, out var solution, out var xform)) + while (query.MoveNext(out var uid, out var vaporComp, out var container, out var xform)) { - foreach (var (_, value) in solution.Solutions) + foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((uid, container))) { - Update(frameTime, (uid, vaporComp), value, xform); + Update(frameTime, (uid, vaporComp), soln, xform); } } } - private void Update(float frameTime, Entity ent, Solution contents, TransformComponent xform) + private void Update(float frameTime, Entity ent, Entity soln, TransformComponent xform) { var (entity, vapor) = ent; if (!vapor.Active) @@ -112,6 +112,7 @@ namespace Content.Server.Chemistry.EntitySystems vapor.ReactTimer += frameTime; + var contents = soln.Comp.Solution; if (vapor.ReactTimer >= ReactTime && TryComp(xform.GridUid, out MapGridComponent? gridComp)) { vapor.ReactTimer = 0; @@ -131,7 +132,7 @@ namespace Content.Server.Chemistry.EntitySystems reaction = reagentQuantity.Quantity; } - _solutionContainerSystem.RemoveReagent(entity, contents, reagentQuantity.Reagent, reaction); + _solutionContainerSystem.RemoveReagent(soln, reagentQuantity.Reagent, reaction); } } diff --git a/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs index fc807069f7..024558f8de 100644 --- a/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs @@ -1,6 +1,5 @@ using Content.Server.Fluids.EntitySystems; using Content.Shared.Audio; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Coordinates.Helpers; using Content.Shared.Database; @@ -30,7 +29,7 @@ namespace Content.Server.Chemistry.ReactionEffects /// /// How many units of reaction for 1 smoke entity. /// - [DataField("overflowThreshold")] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5); + [DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5); /// /// The entity prototype that will be spawned as the effect. @@ -56,7 +55,7 @@ namespace Content.Server.Chemistry.ReactionEffects return; var spreadAmount = (int) Math.Max(0, Math.Ceiling((args.Quantity / OverflowThreshold).Float())); - var splitSolution = args.EntityManager.System().SplitSolution(args.SolutionEntity, args.Source, args.Source.Volume); + var splitSolution = args.Source.SplitSolution(args.Source.Volume); var transform = args.EntityManager.GetComponent(args.SolutionEntity); var mapManager = IoCManager.Resolve(); diff --git a/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs index 53c4f676a8..f8c0378452 100644 --- a/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs @@ -11,13 +11,13 @@ public sealed partial class CreateEntityReactionEffect : ReagentEffect /// /// What entity to create. /// - [DataField("entity", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] public string Entity = default!; /// /// How many entities to create per unit reaction. /// - [DataField("number")] + [DataField] public uint Number = 1; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReactionEffects/EmpReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/EmpReactionEffect.cs index 2efdff93af..b6714ca28d 100644 --- a/Content.Server/Chemistry/ReactionEffects/EmpReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/EmpReactionEffect.cs @@ -23,7 +23,7 @@ public sealed partial class EmpReactionEffect : ReagentEffect /// /// How much energy will be drain from sources /// - [DataField("energyConsumption")] + [DataField] public float EnergyConsumption = 12500; /// diff --git a/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs index 41a389ee2f..8a558a3ffd 100644 --- a/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs @@ -1,10 +1,10 @@ -using System.Text.Json.Serialization; using Content.Server.Explosion.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.Explosion; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using System.Text.Json.Serialization; namespace Content.Server.Chemistry.ReactionEffects { @@ -14,7 +14,7 @@ namespace Content.Server.Chemistry.ReactionEffects /// /// The type of explosion. Determines damage types and tile break chance scaling. /// - [DataField("explosionType", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] [JsonIgnore] public string ExplosionType = default!; @@ -22,14 +22,14 @@ namespace Content.Server.Chemistry.ReactionEffects /// The max intensity the explosion can have at a given tile. Places an upper limit of damage and tile break /// chance. /// - [DataField("maxIntensity")] + [DataField] [JsonIgnore] public float MaxIntensity = 5; /// /// How quickly intensity drops off as you move away from the epicenter /// - [DataField("intensitySlope")] + [DataField] [JsonIgnore] public float IntensitySlope = 1; @@ -40,14 +40,14 @@ namespace Content.Server.Chemistry.ReactionEffects /// /// A slope of 1 and MaxTotalIntensity of 100 corresponds to a radius of around 4.5 tiles. /// - [DataField("maxTotalIntensity")] + [DataField] [JsonIgnore] public float MaxTotalIntensity = 100; /// /// The intensity of the explosion per unit reaction. /// - [DataField("intensityPerUnit")] + [DataField] [JsonIgnore] public float IntensityPerUnit = 1; diff --git a/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs deleted file mode 100644 index 5f282702bb..0000000000 --- a/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs b/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs index 6117132831..ec58754883 100644 --- a/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs +++ b/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs @@ -1,7 +1,5 @@ -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Robust.Shared.Prototypes; -using static Robust.Shared.Physics.DynamicTree; namespace Content.Server.Chemistry.ReactionEffects { @@ -121,5 +119,3 @@ namespace Content.Server.Chemistry.ReactionEffects } } - - diff --git a/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs b/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs index fbb1894813..9c47bb58ab 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs @@ -10,10 +10,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions /// public sealed partial class Temperature : ReagentEffectCondition { - [DataField("min")] + [DataField] public float Min = 0; - [DataField("max")] + [DataField] public float Max = float.PositiveInfinity; public override bool Condition(ReagentEffectArgs args) { diff --git a/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs b/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs index e2f4ca0968..52d4d00eb3 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs @@ -9,10 +9,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions; [UsedImplicitly] public sealed partial class HasTag : ReagentEffectCondition { - [DataField("tag", customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string Tag = default!; - [DataField("invert")] + [DataField] public bool Invert = false; public override bool Condition(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs b/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs index 4585cc6d8a..377eb7d906 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs @@ -7,16 +7,14 @@ namespace Content.Server.Chemistry.ReagentEffectConditions { public sealed partial class MobStateCondition : ReagentEffectCondition { - - - [DataField("mobstate")] - public MobState mobstate = MobState.Alive; + [DataField] + public MobState Mobstate = MobState.Alive; public override bool Condition(ReagentEffectArgs args) { if (args.EntityManager.TryGetComponent(args.SolutionEntity, out MobStateComponent? mobState)) { - if (mobState.CurrentState == mobstate) + if (mobState.CurrentState == Mobstate) return true; } @@ -25,7 +23,7 @@ namespace Content.Server.Chemistry.ReagentEffectConditions public override string GuidebookExplanation(IPrototypeManager prototype) { - return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", mobstate)); + return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", Mobstate)); } } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs b/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs index a8e9e3077b..3b7bffb9cf 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs @@ -11,13 +11,13 @@ namespace Content.Server.Chemistry.ReagentEffectConditions /// public sealed partial class OrganType : ReagentEffectCondition { - [DataField("type", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] public string Type = default!; /// /// Does this condition pass when the organ has the type, or when it doesn't have the type? /// - [DataField("shouldHave")] + [DataField] public bool ShouldHave = true; public override bool Condition(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs index 203656be73..664569d7be 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs @@ -13,14 +13,14 @@ namespace Content.Server.Chemistry.ReagentEffectConditions /// public sealed partial class ReagentThreshold : ReagentEffectCondition { - [DataField("min")] + [DataField] public FixedPoint2 Min = FixedPoint2.Zero; - [DataField("max")] + [DataField] public FixedPoint2 Max = FixedPoint2.MaxValue; // TODO use ReagentId - [DataField("reagent")] + [DataField] public string? Reagent; public override bool Condition(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs b/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs index 974f2fb81a..4387f2ba93 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs @@ -9,10 +9,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions /// public sealed partial class SolutionTemperature : ReagentEffectCondition { - [DataField("min")] + [DataField] public float Min = 0.0f; - [DataField("max")] + [DataField] public float Max = float.PositiveInfinity; public override bool Condition(ReagentEffectArgs args) { diff --git a/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs b/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs index 81f6475449..49630ef9ab 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs @@ -7,10 +7,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions { public sealed partial class TotalDamage : ReagentEffectCondition { - [DataField("max")] + [DataField] public FixedPoint2 Max = FixedPoint2.MaxValue; - [DataField("min")] + [DataField] public FixedPoint2 Min = FixedPoint2.Zero; public override bool Condition(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs b/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs index d150854e1e..6a43739b0e 100644 --- a/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs +++ b/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs @@ -1,4 +1,4 @@ -using Content.Shared.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; using Robust.Shared.Prototypes; @@ -17,12 +17,11 @@ namespace Content.Server.Chemistry.ReagentEffects return; // TODO see if this is correct - if (!EntitySystem.Get() - .TryGetSolution(args.SolutionEntity, _solution, out var solutionContainer)) + var solutionContainerSystem = args.EntityManager.System(); + if (!solutionContainerSystem.TryGetSolution(args.SolutionEntity, _solution, out var solutionContainer)) return; - if (EntitySystem.Get() - .TryAddReagent(args.SolutionEntity, solutionContainer, args.Reagent.ID, args.Quantity, out var accepted)) + if (solutionContainerSystem.TryAddReagent(solutionContainer.Value, args.Reagent.ID, args.Quantity, out var accepted)) args.Source?.RemoveReagent(args.Reagent.ID, accepted); } diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs b/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs index ee384a2834..cf3d71405b 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs @@ -10,13 +10,13 @@ public sealed partial class AdjustAlert : ReagentEffect [DataField("alertType", required: true)] public AlertType Type; - [DataField("clear")] + [DataField] public bool Clear; - [DataField("cooldown")] + [DataField] public bool Cooldown; - [DataField("time")] + [DataField] public float Time; //JUSTIFICATION: This just changes some visuals, doesn't need to be documented. diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs index 5a216b9753..e70626f1d3 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs @@ -1,5 +1,4 @@ using Content.Shared.Body.Prototypes; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using JetBrains.Annotations; @@ -14,7 +13,7 @@ namespace Content.Server.Chemistry.ReagentEffects /// /// The reagent ID to remove. Only one of this and should be active. /// - [DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string? Reagent = null; // TODO use ReagentId @@ -22,41 +21,39 @@ namespace Content.Server.Chemistry.ReagentEffects /// The metabolism group to remove, if the reagent satisfies any. /// Only one of this and should be active. /// - [DataField("group", customTypeSerializer:typeof(PrototypeIdSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] public string? Group = null; - [DataField("amount", required: true)] + [DataField(required: true)] public FixedPoint2 Amount = default!; public override void Effect(ReagentEffectArgs args) { - if (args.Source != null) + if (args.Source == null) + return; + + var amount = Amount; + amount *= args.Scale; + + if (Reagent != null) { - var solutionSys = args.EntityManager.EntitySysManager.GetEntitySystem(); - var amount = Amount; - - amount *= args.Scale; - - if (Reagent != null) + if (amount < 0 && args.Source.ContainsPrototype(Reagent)) + args.Source.RemoveReagent(Reagent, -amount); + if (amount > 0) + args.Source.AddReagent(Reagent, amount); + } + else if (Group != null) + { + var prototypeMan = IoCManager.Resolve(); + foreach (var quant in args.Source.Contents.ToArray()) { - if (amount < 0 && args.Source.ContainsPrototype(Reagent)) - solutionSys.RemoveReagent(args.SolutionEntity, args.Source, Reagent, -amount); - if (amount > 0) - solutionSys.TryAddReagent(args.SolutionEntity, args.Source, Reagent, amount, out _); - } - else if (Group != null) - { - var prototypeMan = IoCManager.Resolve(); - foreach (var quant in args.Source.Contents.ToArray()) + var proto = prototypeMan.Index(quant.Reagent.Prototype); + if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group)) { - var proto = prototypeMan.Index(quant.Reagent.Prototype); - if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group)) - { - if (amount < 0) - solutionSys.RemoveReagent(args.SolutionEntity, args.Source, quant.Reagent, amount); - if (amount > 0) - solutionSys.TryAddReagent(args.SolutionEntity, args.Source, quant.Reagent, amount, out _); - } + if (amount < 0) + args.Source.RemoveReagent(quant.Reagent, amount); + if (amount > 0) + args.Source.AddReagent(quant.Reagent, amount); } } } diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs b/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs index 66ae5ba1db..9b97572067 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs @@ -7,7 +7,7 @@ namespace Content.Server.Chemistry.ReagentEffects { public sealed partial class AdjustTemperature : ReagentEffect { - [DataField("amount")] + [DataField] public float Amount; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/CauseZombieInfection.cs b/Content.Server/Chemistry/ReagentEffects/CauseZombieInfection.cs index ed3098dbdc..029b149500 100644 --- a/Content.Server/Chemistry/ReagentEffects/CauseZombieInfection.cs +++ b/Content.Server/Chemistry/ReagentEffects/CauseZombieInfection.cs @@ -1,9 +1,7 @@ -using Content.Shared.Chemistry.Reagent; -using Robust.Shared.Prototypes; - -using Robust.Shared.Configuration; using Content.Server.Zombies; - +using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; diff --git a/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs b/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs index f0deb29f87..402b30a069 100644 --- a/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs +++ b/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs @@ -1,6 +1,6 @@ +using Content.Server.Body.Systems; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; -using Content.Server.Body.Systems; using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReactionEffects @@ -11,7 +11,7 @@ namespace Content.Server.Chemistry.ReactionEffects [UsedImplicitly] public sealed partial class ChemCleanBloodstream : ReagentEffect { - [DataField("cleanseRate")] + [DataField] public float CleanseRate = 3.0f; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs b/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs index 9f074bca52..206b8ed04d 100644 --- a/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs +++ b/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs @@ -15,7 +15,7 @@ namespace Content.Server.Chemistry.ReagentEffects /// /// How much eye damage to add. /// - [DataField("amount")] + [DataField] public int Amount = -1; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs b/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs index 630d00124c..851c0adf5f 100644 --- a/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs +++ b/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs @@ -1,5 +1,5 @@ -using Content.Shared.Chemistry.Reagent; using Content.Server.Medical; +using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; using Robust.Shared.Prototypes; @@ -12,10 +12,10 @@ namespace Content.Server.Chemistry.ReagentEffects public sealed partial class ChemVomit : ReagentEffect { /// How many units of thirst to add each time we vomit - [DataField("thirstAmount")] + [DataField] public float ThirstAmount = -8f; /// How many units of hunger to add each time we vomit - [DataField("hungerAmount")] + [DataField] public float HungerAmount = -8f; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/CreateGas.cs b/Content.Server/Chemistry/ReagentEffects/CreateGas.cs index ca9ecd67d1..c1da3c48db 100644 --- a/Content.Server/Chemistry/ReagentEffects/CreateGas.cs +++ b/Content.Server/Chemistry/ReagentEffects/CreateGas.cs @@ -8,13 +8,13 @@ namespace Content.Server.Chemistry.ReagentEffects; public sealed partial class CreateGas : ReagentEffect { - [DataField("gas", required: true)] + [DataField(required: true)] public Gas Gas = default!; /// /// For each unit consumed, how many moles of gas should be created? /// - [DataField("multiplier")] + [DataField] public float Multiplier = 3f; public override bool ShouldLog => true; diff --git a/Content.Server/Chemistry/ReagentEffects/CureZombieInfection.cs b/Content.Server/Chemistry/ReagentEffects/CureZombieInfection.cs index 4e1733e60a..d56fc11531 100644 --- a/Content.Server/Chemistry/ReagentEffects/CureZombieInfection.cs +++ b/Content.Server/Chemistry/ReagentEffects/CureZombieInfection.cs @@ -1,14 +1,13 @@ -using Content.Shared.Chemistry.Reagent; -using Robust.Shared.Prototypes; -using Robust.Shared.Configuration; using Content.Server.Zombies; - +using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; public sealed partial class CureZombieInfection : ReagentEffect { - [DataField("innoculate")] + [DataField] public bool Innoculate; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/Drunk.cs b/Content.Server/Chemistry/ReagentEffects/Drunk.cs index 8053c8100f..dbce995ca2 100644 --- a/Content.Server/Chemistry/ReagentEffects/Drunk.cs +++ b/Content.Server/Chemistry/ReagentEffects/Drunk.cs @@ -9,13 +9,13 @@ public sealed partial class Drunk : ReagentEffect /// /// BoozePower is how long each metabolism cycle will make the drunk effect last for. /// - [DataField("boozePower")] + [DataField] public float BoozePower = 3f; /// /// Whether speech should be slurred. /// - [DataField("slurSpeech")] + [DataField] public bool SlurSpeech = true; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/Electrocute.cs b/Content.Server/Chemistry/ReagentEffects/Electrocute.cs index 85819d36ea..272a0fce42 100644 --- a/Content.Server/Chemistry/ReagentEffects/Electrocute.cs +++ b/Content.Server/Chemistry/ReagentEffects/Electrocute.cs @@ -6,14 +6,14 @@ namespace Content.Server.Chemistry.ReagentEffects; public sealed partial class Electrocute : ReagentEffect { - [DataField("electrocuteTime")] public int ElectrocuteTime = 2; + [DataField] public int ElectrocuteTime = 2; - [DataField("electrocuteDamageScale")] public int ElectrocuteDamageScale = 5; + [DataField] public int ElectrocuteDamageScale = 5; /// /// true - refresh electrocute time, false - accumulate electrocute time /// - [DataField("refresh")] public bool Refresh = true; + [DataField] public bool Refresh = true; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-electrocute", ("chance", Probability), ("time", ElectrocuteTime)); diff --git a/Content.Server/Chemistry/ReagentEffects/Emote.cs b/Content.Server/Chemistry/ReagentEffects/Emote.cs index 45da55ea1a..a4d49e4ad1 100644 --- a/Content.Server/Chemistry/ReagentEffects/Emote.cs +++ b/Content.Server/Chemistry/ReagentEffects/Emote.cs @@ -16,7 +16,7 @@ public sealed partial class Emote : ReagentEffect [DataField("emote", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? EmoteId; - [DataField("showInChat")] + [DataField] public bool ShowInChat; // JUSTIFICATION: Emoting is flavor, so same reason popup messages are not in here. diff --git a/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs b/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs index 26bd4c8b7e..5b36967f6a 100644 --- a/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs +++ b/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs @@ -10,7 +10,7 @@ namespace Content.Server.Chemistry.ReagentEffects [UsedImplicitly] public sealed partial class FlammableReaction : ReagentEffect { - [DataField("multiplier")] + [DataField] public float Multiplier = 0.05f; public override bool ShouldLog => true; diff --git a/Content.Server/Chemistry/ReagentEffects/HealthChange.cs b/Content.Server/Chemistry/ReagentEffects/HealthChange.cs index 6d22db742f..a0c976bdc9 100644 --- a/Content.Server/Chemistry/ReagentEffects/HealthChange.cs +++ b/Content.Server/Chemistry/ReagentEffects/HealthChange.cs @@ -1,5 +1,3 @@ -using System.Linq; -using System.Text.Json.Serialization; using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; @@ -7,6 +5,8 @@ using Content.Shared.FixedPoint; using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Shared.Prototypes; +using System.Linq; +using System.Text.Json.Serialization; namespace Content.Server.Chemistry.ReagentEffects { @@ -19,19 +19,19 @@ namespace Content.Server.Chemistry.ReagentEffects /// /// Damage to apply every metabolism cycle. Damage Ignores resistances. /// + [DataField(required: true)] [JsonPropertyName("damage")] - [DataField("damage", required: true)] public DamageSpecifier Damage = default!; /// /// Should this effect scale the damage by the amount of chemical in the solution? /// Useful for touch reactions, like styptic powder or acid. /// + [DataField] [JsonPropertyName("scaleByQuantity")] - [DataField("scaleByQuantity")] public bool ScaleByQuantity; - [DataField("ignoreResistances")] + [DataField] [JsonPropertyName("ignoreResistances")] public bool IgnoreResistances = true; diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs b/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs index bb990214f1..7b966ea478 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs @@ -7,10 +7,10 @@ namespace Content.Server.Chemistry.ReagentEffects; public sealed partial class ModifyBleedAmount : ReagentEffect { - [DataField("scaled")] + [DataField] public bool Scaled = false; - [DataField("amount")] + [DataField] public float Amount = -1.0f; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs b/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs index 42fb14809f..748aa71083 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs @@ -8,10 +8,10 @@ namespace Content.Server.Chemistry.ReagentEffects; public sealed partial class ModifyBloodLevel : ReagentEffect { - [DataField("scaled")] + [DataField] public bool Scaled = false; - [DataField("amount")] + [DataField] public FixedPoint2 Amount = 1.0f; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs b/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs index 948726bb06..0301742c5a 100644 --- a/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs +++ b/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs @@ -15,19 +15,19 @@ namespace Content.Server.Chemistry.ReagentEffects /// /// How much the entities' walk speed is multiplied by. /// - [DataField("walkSpeedModifier")] + [DataField] public float WalkSpeedModifier { get; set; } = 1; /// /// How much the entities' run speed is multiplied by. /// - [DataField("sprintSpeedModifier")] + [DataField] public float SprintSpeedModifier { get; set; } = 1; /// /// How long the modifier applies (in seconds) when metabolized. /// - [DataField("statusLifetime")] + [DataField] public float StatusLifetime = 2f; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs b/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs index 28356bbd30..34a2454139 100644 --- a/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs +++ b/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs @@ -7,7 +7,7 @@ namespace Content.Server.Chemistry.ReagentEffects; public sealed partial class Oxygenate : ReagentEffect { - [DataField("factor")] + [DataField] public float Factor = 1f; // JUSTIFICATION: This is internal magic that players never directly interact with. diff --git a/Content.Server/Chemistry/ReagentEffects/Paralyze.cs b/Content.Server/Chemistry/ReagentEffects/Paralyze.cs index 262d942fa9..077d1abf2c 100644 --- a/Content.Server/Chemistry/ReagentEffects/Paralyze.cs +++ b/Content.Server/Chemistry/ReagentEffects/Paralyze.cs @@ -1,17 +1,17 @@ -using Content.Shared.Chemistry.Reagent; using Content.Server.Stunnable; +using Content.Shared.Chemistry.Reagent; using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; public sealed partial class Paralyze : ReagentEffect { - [DataField("paralyzeTime")] public double ParalyzeTime = 2; + [DataField] public double ParalyzeTime = 2; /// /// true - refresh paralyze time, false - accumulate paralyze time /// - [DataField("refresh")] public bool Refresh = true; + [DataField] public bool Refresh = true; protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-paralyze", diff --git a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs index a2d35c8264..f43b4828f9 100644 --- a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs +++ b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs @@ -1,16 +1,19 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Server.Botany.Components; +using Content.Server.Botany.Components; using Content.Shared.Chemistry.Reagent; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using System.Diagnostics.CodeAnalysis; namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism { [ImplicitDataDefinitionForInheritors] public abstract partial class PlantAdjustAttribute : ReagentEffect { - [DataField("amount")] public float Amount { get; protected set; } = 1; - [DataField("prob")] public float Prob { get; protected set; } = 1; // = (80); + [DataField] + public float Amount { get; protected set; } = 1; + + [DataField] + public float Prob { get; protected set; } = 1; // = (80); /// /// Checks if the plant holder can metabolize the reagent or not. Checks if it has an alive plant by default. diff --git a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs index bcd5a01170..990a5a5003 100644 --- a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs +++ b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs @@ -11,13 +11,13 @@ namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism [DataDefinition] public sealed partial class RobustHarvest : ReagentEffect { - [DataField("potencyLimit")] + [DataField] public int PotencyLimit = 50; - [DataField("potencyIncrease")] + [DataField] public int PotencyIncrease = 3; - [DataField("potencySeedlessThreshold")] + [DataField] public int PotencySeedlessThreshold = 30; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs b/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs index 660a539e8a..8278e95c1d 100644 --- a/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs +++ b/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs @@ -8,13 +8,13 @@ namespace Content.Server.Chemistry.ReagentEffects { public sealed partial class PopupMessage : ReagentEffect { - [DataField("messages", required: true)] + [DataField(required: true)] public string[] Messages = default!; - [DataField("type")] + [DataField] public PopupRecipients Type = PopupRecipients.Local; - [DataField("visualType")] + [DataField] public PopupType VisualType = PopupType.Small; // JUSTIFICATION: This is purely cosmetic. diff --git a/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs b/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs index 06608df4bb..66454b25fd 100644 --- a/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs +++ b/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs @@ -17,25 +17,25 @@ namespace Content.Server.Chemistry.ReagentEffects.StatusEffects [UsedImplicitly] public sealed partial class GenericStatusEffect : ReagentEffect { - [DataField("key", required: true)] + [DataField(required: true)] public string Key = default!; - [DataField("component")] + [DataField] public string Component = String.Empty; - [DataField("time")] + [DataField] public float Time = 2.0f; /// /// true - refresh status effect time, false - accumulate status effect time /// - [DataField("refresh")] + [DataField] public bool Refresh = true; /// /// Should this effect add the status effect, remove time from it, or set its cooldown? /// - [DataField("type")] + [DataField] public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs b/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs index 7ceb91a0d1..7ee70957b7 100644 --- a/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs +++ b/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs @@ -11,19 +11,19 @@ namespace Content.Server.Chemistry.ReagentEffects.StatusEffects /// public sealed partial class Jitter : ReagentEffect { - [DataField("amplitude")] + [DataField] public float Amplitude = 10.0f; - [DataField("frequency")] + [DataField] public float Frequency = 4.0f; - [DataField("time")] + [DataField] public float Time = 2.0f; /// /// true - refresh jitter time, false - accumulate jitter time /// - [DataField("refresh")] + [DataField] public bool Refresh = true; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs b/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs index c23956760a..a20f54728e 100644 --- a/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs +++ b/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs @@ -1,4 +1,3 @@ -using System.Numerics; using Content.Server.Decals; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; @@ -6,6 +5,7 @@ using Content.Shared.Decals; using Content.Shared.FixedPoint; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using System.Numerics; namespace Content.Server.Chemistry.TileReactions; @@ -18,7 +18,7 @@ public sealed partial class CleanDecalsReaction : ITileReaction /// /// For every cleaned decal we lose this much reagent. /// - [DataField("cleanCost")] + [DataField] public FixedPoint2 CleanCost { get; private set; } = FixedPoint2.New(0.25f); public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume) diff --git a/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs b/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs index 4e2f52d3bc..9d358de07e 100644 --- a/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs @@ -1,12 +1,12 @@ -using System.Linq; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Content.Shared.Fluids.Components; using Robust.Shared.Map; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using System.Linq; namespace Content.Server.Chemistry.TileReactions; @@ -28,7 +28,7 @@ public sealed partial class CleanTileReaction : ITileReaction /// /// What reagent to replace the tile conents with. /// - [DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer))] + [DataField("reagent", customTypeSerializer: typeof(PrototypeIdSerializer))] public string ReplacementReagent = "Water"; FixedPoint2 ITileReaction.TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume) @@ -43,17 +43,16 @@ public sealed partial class CleanTileReaction : ITileReaction foreach (var entity in entities) { if (!puddleQuery.TryGetComponent(entity, out var puddle) || - !solutionContainerSystem.TryGetSolution(entity, puddle.SolutionName, out var puddleSolution)) + !solutionContainerSystem.TryGetSolution(entity, puddle.SolutionName, out var puddleSolution, out _)) { continue; } - var purgeable = - solutionContainerSystem.SplitSolutionWithout(entity, puddleSolution, purgeAmount, ReplacementReagent, reagent.ID); + var purgeable = solutionContainerSystem.SplitSolutionWithout(puddleSolution.Value, purgeAmount, ReplacementReagent, reagent.ID); purgeAmount -= purgeable.Volume; - solutionContainerSystem.TryAddSolution(entity, puddleSolution, new Solution(ReplacementReagent, purgeable.Volume)); + solutionContainerSystem.TryAddSolution(puddleSolution.Value, new Solution(ReplacementReagent, purgeable.Volume)); if (purgeable.Volume <= FixedPoint2.Zero) break; diff --git a/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs b/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs index 3b1494cc2f..9cb1ba201d 100644 --- a/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs @@ -1,5 +1,4 @@ -using System.Numerics; -using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Content.Shared.Maps; @@ -8,22 +7,23 @@ using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using System.Numerics; namespace Content.Server.Chemistry.TileReactions; [DataDefinition] public sealed partial class CreateEntityTileReaction : ITileReaction { - [DataField("entity", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] + [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] public string Entity = default!; - [DataField("usage")] + [DataField] public FixedPoint2 Usage = FixedPoint2.New(1); /// /// How many of the whitelisted entity can fit on one tile? /// - [DataField("maxOnTile")] + [DataField] public int MaxOnTile = 1; /// @@ -32,7 +32,7 @@ public sealed partial class CreateEntityTileReaction : ITileReaction [DataField("maxOnTileWhitelist")] public EntityWhitelist? Whitelist; - [DataField("randomOffsetMax")] + [DataField] public float RandomOffsetMax = 0.0f; public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume) diff --git a/Content.Server/Cloning/CloningSystem.cs b/Content.Server/Cloning/CloningSystem.cs index 6156a88c38..95b0bd7310 100644 --- a/Content.Server/Cloning/CloningSystem.cs +++ b/Content.Server/Cloning/CloningSystem.cs @@ -29,7 +29,6 @@ using Content.Shared.Roles.Jobs; using Robust.Server.Containers; using Robust.Server.GameObjects; using Robust.Server.Player; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Containers; diff --git a/Content.Server/Construction/Conditions/MinSolution.cs b/Content.Server/Construction/Conditions/MinSolution.cs index d70e84761d..f98d639b7b 100644 --- a/Content.Server/Construction/Conditions/MinSolution.cs +++ b/Content.Server/Construction/Conditions/MinSolution.cs @@ -1,4 +1,4 @@ -using Content.Shared.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Construction; using Content.Shared.Examine; @@ -34,7 +34,7 @@ public sealed partial class MinSolution : IGraphCondition public bool Condition(EntityUid uid, IEntityManager entMan) { var containerSys = entMan.System(); - if (!containerSys.TryGetSolution(uid, Solution, out var solution)) + if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution)) return false; solution.TryGetReagentQuantity(Reagent, out var quantity); @@ -47,7 +47,7 @@ public sealed partial class MinSolution : IGraphCondition var uid = args.Examined; var containerSys = entMan.System(); - if (!containerSys.TryGetSolution(uid, Solution, out var solution)) + if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution)) return false; solution.TryGetReagentQuantity(Reagent, out var quantity); diff --git a/Content.Server/Construction/Conditions/SolutionEmpty.cs b/Content.Server/Construction/Conditions/SolutionEmpty.cs index d3cbd7356e..9235a187eb 100644 --- a/Content.Server/Construction/Conditions/SolutionEmpty.cs +++ b/Content.Server/Construction/Conditions/SolutionEmpty.cs @@ -1,4 +1,4 @@ -using Content.Shared.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Construction; using Content.Shared.Examine; @@ -19,7 +19,7 @@ public sealed partial class SolutionEmpty : IGraphCondition public bool Condition(EntityUid uid, IEntityManager entMan) { var containerSys = entMan.System(); - if (!containerSys.TryGetSolution(uid, Solution, out var solution)) + if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution)) return false; return solution.Volume == 0; @@ -31,7 +31,7 @@ public sealed partial class SolutionEmpty : IGraphCondition var uid = args.Examined; var containerSys = entMan.System(); - if (!containerSys.TryGetSolution(uid, Solution, out var solution)) + if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution)) return false; // already empty so dont show examine diff --git a/Content.Server/Destructible/DestructibleSystem.cs b/Content.Server/Destructible/DestructibleSystem.cs index 7e43e72007..16c54fd3b0 100644 --- a/Content.Server/Destructible/DestructibleSystem.cs +++ b/Content.Server/Destructible/DestructibleSystem.cs @@ -1,7 +1,7 @@ -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Construction; using Content.Server.Destructible.Thresholds; using Content.Server.Destructible.Thresholds.Behaviors; @@ -9,7 +9,6 @@ using Content.Server.Destructible.Thresholds.Triggers; using Content.Server.Explosion.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Stack; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Destructible; @@ -20,6 +19,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using System.Linq; namespace Content.Server.Destructible { diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs index 97ea392450..5166aaccab 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs @@ -10,12 +10,12 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataDefinition] public sealed partial class SolutionExplosionBehavior : IThresholdBehavior { - [DataField("solution", required: true)] + [DataField(required: true)] public string Solution = default!; public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) { - if (system.SolutionContainerSystem.TryGetSolution(owner, Solution, out var explodingSolution) + if (system.SolutionContainerSystem.TryGetSolution(owner, Solution, out _, out var explodingSolution) && system.EntityManager.TryGetComponent(owner, out ExplosiveComponent? explosiveComponent)) { // Don't explode if there's no solution diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs index 66f42857cf..9e22510307 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs @@ -1,6 +1,6 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.Components; using Content.Server.Fluids.EntitySystems; -using Content.Shared.Chemistry.EntitySystems; using JetBrains.Annotations; namespace Content.Server.Destructible.Thresholds.Behaviors @@ -9,7 +9,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataDefinition] public sealed partial class SpillBehavior : IThresholdBehavior { - [DataField("solution")] + [DataField] public string? Solution; /// @@ -28,13 +28,12 @@ namespace Content.Server.Destructible.Thresholds.Behaviors var coordinates = system.EntityManager.GetComponent(owner).Coordinates; if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) && - solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, - out var compSolution)) + 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 var behaviorSolution)) + solutionContainerSystem.TryGetSolution(owner, Solution, out _, out var behaviorSolution)) { spillableSystem.TrySplashSpillAt(owner, coordinates, behaviorSolution, out _, user: cause); } diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs index 323dae493a..5bb60abdc9 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs @@ -1,30 +1,30 @@ -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Explosion.Components; using Content.Server.Flash; using Content.Server.Flash.Components; using Content.Server.Radio.EntitySystems; +using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.Implants.Components; using Content.Shared.Interaction; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; using Content.Shared.Payload.Components; -using Robust.Shared.Prototypes; using Content.Shared.Radio; using Content.Shared.Slippery; using Content.Shared.StepTrigger.Systems; using Content.Shared.Trigger; +using Content.Shared.Weapons.Ranged.Events; using JetBrains.Annotations; using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; -using Content.Shared.Mobs; -using Content.Shared.Mobs.Components; -using Content.Shared.Weapons.Ranged.Events; -using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Explosion.EntitySystems @@ -65,6 +65,7 @@ namespace Content.Server.Explosion.EntitySystems [Dependency] private readonly RadioSystem _radioSystem = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; public override void Initialize() { @@ -233,7 +234,7 @@ namespace Content.Server.Explosion.EntitySystems comp.TimeRemaining += amount; } - public void HandleTimerTrigger(EntityUid uid, EntityUid? user, float delay , float beepInterval, float? initialBeepDelay, SoundSpecifier? beepSound) + public void HandleTimerTrigger(EntityUid uid, EntityUid? user, float delay, float beepInterval, float? initialBeepDelay, SoundSpecifier? beepSound) { if (delay <= 0) { @@ -253,12 +254,18 @@ namespace Content.Server.Explosion.EntitySystems TryComp(container.ContainedEntities[0], out ChemicalPayloadComponent? chemicalPayloadComponent)) { // If a beaker is missing, the entity won't explode, so no reason to log it - if (!TryComp(chemicalPayloadComponent?.BeakerSlotA.Item, out SolutionContainerManagerComponent? beakerA) || - !TryComp(chemicalPayloadComponent?.BeakerSlotB.Item, out SolutionContainerManagerComponent? beakerB)) + if (chemicalPayloadComponent?.BeakerSlotA.Item is not { } beakerA || + chemicalPayloadComponent?.BeakerSlotB.Item is not { } beakerB || + !TryComp(beakerA, out SolutionContainerManagerComponent? containerA) || + !TryComp(beakerB, out SolutionContainerManagerComponent? containerB) || + !TryComp(beakerA, out FitsInDispenserComponent? fitsA) || + !TryComp(beakerB, out FitsInDispenserComponent? fitsB) || + !_solutionContainerSystem.TryGetSolution((beakerA, containerA), fitsA.Solution, out _, out var solutionA) || + !_solutionContainerSystem.TryGetSolution((beakerB, containerB), fitsB.Solution, out _, out var solutionB)) return; _adminLogger.Add(LogType.Trigger, - $"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}, which contains [{string.Join(", ", beakerA.Solutions.Values.First())}] in one beaker and [{string.Join(", ", beakerB.Solutions.Values.First())}] in the other."); + $"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}, which contains {SolutionContainerSystem.ToPrettyString(solutionA)} in one beaker and {SolutionContainerSystem.ToPrettyString(solutionB)} in the other."); } else { diff --git a/Content.Server/Extinguisher/FireExtinguisherSystem.cs b/Content.Server/Extinguisher/FireExtinguisherSystem.cs index 30895deb4c..5adf067d9b 100644 --- a/Content.Server/Extinguisher/FireExtinguisherSystem.cs +++ b/Content.Server/Extinguisher/FireExtinguisherSystem.cs @@ -1,8 +1,7 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Popups; -using Content.Shared.Audio; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Extinguisher; using Content.Shared.FixedPoint; using Content.Shared.Interaction; @@ -10,7 +9,6 @@ using Content.Shared.Interaction.Events; using Content.Shared.Verbs; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; namespace Content.Server.Extinguisher; @@ -32,25 +30,25 @@ public sealed class FireExtinguisherSystem : EntitySystem SubscribeLocalEvent(OnSprayAttempt); } - private void OnFireExtinguisherInit(EntityUid uid, FireExtinguisherComponent component, ComponentInit args) + private void OnFireExtinguisherInit(Entity entity, ref ComponentInit args) { - if (component.HasSafety) + if (entity.Comp.HasSafety) { - UpdateAppearance(uid, component); + UpdateAppearance((entity.Owner, entity.Comp)); } } - private void OnUseInHand(EntityUid uid, FireExtinguisherComponent component, UseInHandEvent args) + private void OnUseInHand(Entity entity, ref UseInHandEvent args) { if (args.Handled) return; - ToggleSafety(uid, args.User, component); + ToggleSafety((entity.Owner, entity.Comp), args.User); args.Handled = true; } - private void OnAfterInteract(EntityUid uid, FireExtinguisherComponent component, AfterInteractEvent args) + private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { if (args.Target == null || !args.CanReach) { @@ -60,24 +58,23 @@ public sealed class FireExtinguisherSystem : EntitySystem if (args.Handled) return; - if (component.HasSafety && component.Safety) + if (entity.Comp.HasSafety && entity.Comp.Safety) { - _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), uid, - args.User); + _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), entity.Owner, args.User); return; } - if (args.Target is not {Valid: true} target || - !_solutionContainerSystem.TryGetDrainableSolution(target, out var targetSolution) || - !_solutionContainerSystem.TryGetRefillableSolution(uid, out var container)) + if (args.Target is not { Valid: true } target || + !_solutionContainerSystem.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution) || + !_solutionContainerSystem.TryGetRefillableSolution(entity.Owner, out var containerSoln, out var containerSolution)) { return; } args.Handled = true; - var transfer = container.AvailableVolume; - if (TryComp(uid, out var solTrans)) + var transfer = containerSolution.AvailableVolume; + if (TryComp(entity.Owner, out var solTrans)) { transfer = solTrans.TransferAmount; } @@ -85,59 +82,57 @@ public sealed class FireExtinguisherSystem : EntitySystem if (transfer > 0) { - var drained = _solutionContainerSystem.Drain(target, targetSolution, transfer); - _solutionContainerSystem.TryAddSolution(uid, container, drained); + var drained = _solutionContainerSystem.Drain(target, targetSoln.Value, transfer); + _solutionContainerSystem.TryAddSolution(containerSoln.Value, drained); - _audio.PlayPvs(component.RefillSound, uid); - _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-after-interact-refilled-message", ("owner", uid)), - uid, args.Target.Value); + _audio.PlayPvs(entity.Comp.RefillSound, entity.Owner); + _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-after-interact-refilled-message", ("owner", entity.Owner)), + entity.Owner, args.Target.Value); } } - private void OnGetInteractionVerbs(EntityUid uid, FireExtinguisherComponent component, GetVerbsEvent args) + private void OnGetInteractionVerbs(Entity entity, ref GetVerbsEvent args) { if (!args.CanInteract) return; + var user = args.User; var verb = new InteractionVerb { - Act = () => ToggleSafety(uid, args.User, component), + Act = () => ToggleSafety((entity.Owner, entity.Comp), user), Text = Loc.GetString("fire-extinguisher-component-verb-text"), }; args.Verbs.Add(verb); } - private void OnSprayAttempt(EntityUid uid, FireExtinguisherComponent component, SprayAttemptEvent args) + private void OnSprayAttempt(Entity entity, ref SprayAttemptEvent args) { - if (component.HasSafety && component.Safety) + if (entity.Comp.HasSafety && entity.Comp.Safety) { - _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), uid, - args.User); + _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), entity, args.User); args.Cancel(); } } - private void UpdateAppearance(EntityUid uid, FireExtinguisherComponent comp, - AppearanceComponent? appearance=null) + private void UpdateAppearance(Entity entity) { - if (!Resolve(uid, ref appearance, false)) + if (!Resolve(entity, ref entity.Comp2, false)) return; - if (comp.HasSafety) + if (entity.Comp1.HasSafety) { - _appearance.SetData(uid, FireExtinguisherVisuals.Safety, comp.Safety, appearance); + _appearance.SetData(entity, FireExtinguisherVisuals.Safety, entity.Comp1.Safety, entity.Comp2); } } - public void ToggleSafety(EntityUid uid, EntityUid user, - FireExtinguisherComponent? extinguisher = null) + public void ToggleSafety(Entity extinguisher, EntityUid user) { - if (!Resolve(uid, ref extinguisher)) + if (!Resolve(extinguisher, ref extinguisher.Comp)) return; - extinguisher.Safety = !extinguisher.Safety; - _audio.PlayPvs(extinguisher.SafetySound, uid, AudioParams.Default.WithVariation(0.125f).WithVolume(-4f)); - UpdateAppearance(uid, extinguisher); + extinguisher.Comp.Safety = !extinguisher.Comp.Safety; + _audio.PlayPvs(extinguisher.Comp.SafetySound, extinguisher, AudioParams.Default.WithVariation(0.125f).WithVolume(-4f)); + UpdateAppearance((extinguisher.Owner, extinguisher.Comp)); } } diff --git a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs index a2c89d4e42..3fd2ca00e2 100644 --- a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs +++ b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Popups; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; @@ -24,7 +25,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem [Dependency] private readonly PuddleSystem _puddleSystem = default!; [Dependency] private readonly SharedMeleeWeaponSystem _melee = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; public override void Initialize() @@ -33,7 +34,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem SubscribeLocalEvent(OnAbsorbentInit); SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnInteractNoHand); - SubscribeLocalEvent(OnAbsorbentSolutionChange); + SubscribeLocalEvent(OnAbsorbentSolutionChange); } private void OnAbsorbentInit(EntityUid uid, AbsorbentComponent component, ComponentInit args) @@ -42,14 +43,14 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem UpdateAbsorbent(uid, component); } - private void OnAbsorbentSolutionChange(EntityUid uid, AbsorbentComponent component, SolutionChangedEvent args) + private void OnAbsorbentSolutionChange(EntityUid uid, AbsorbentComponent component, ref SolutionContainerChangedEvent args) { UpdateAbsorbent(uid, component); } private void UpdateAbsorbent(EntityUid uid, AbsorbentComponent component) { - if (!_solutionSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out _, out var solution)) return; var oldProgress = component.Progress.ShallowClone(); @@ -102,17 +103,17 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem public void Mop(EntityUid user, EntityUid target, EntityUid used, AbsorbentComponent component) { - if (!_solutionSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorbentSolution)) + if (!_solutionContainerSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorberSoln)) return; if (_useDelay.ActiveDelay(used)) return; // If it's a puddle try to grab from - if (!TryPuddleInteract(user, used, target, component, absorbentSolution)) + if (!TryPuddleInteract(user, used, target, component, absorberSoln.Value)) { // If it's refillable try to transfer - if (!TryRefillableInteract(user, used, target, component, absorbentSolution)) + if (!TryRefillableInteract(user, used, target, component, absorberSoln.Value)) return; } } @@ -120,24 +121,24 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem /// /// Logic for an absorbing entity interacting with a refillable. /// - private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, Solution absorbentSolution) + private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, Entity absorbentSoln) { if (!TryComp(target, out RefillableSolutionComponent? refillable)) return false; - if (!_solutionSystem.TryGetRefillableSolution(target, out var refillableSolution, refillable: refillable)) + if (!_solutionContainerSystem.TryGetRefillableSolution((target, refillable, null), out var refillableSoln, out var refillableSolution)) return false; if (refillableSolution.Volume <= 0) { // Target empty - only transfer absorbent contents into refillable - if (!TryTransferFromAbsorbentToRefillable(user, used, target, component, absorbentSolution, refillableSolution)) + if (!TryTransferFromAbsorbentToRefillable(user, used, target, component, absorbentSoln, refillableSoln.Value)) return false; } else { // Target non-empty - do a two-way transfer - if (!TryTwoWayAbsorbentRefillableTransfer(user, used, target, component, absorbentSolution, refillableSolution)) + if (!TryTwoWayAbsorbentRefillableTransfer(user, used, target, component, absorbentSoln, refillableSoln.Value)) return false; } @@ -154,15 +155,17 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem EntityUid used, EntityUid target, AbsorbentComponent component, - Solution absorbentSolution, - Solution refillableSolution) + Entity absorbentSoln, + Entity refillableSoln) { + var absorbentSolution = absorbentSoln.Comp.Solution; if (absorbentSolution.Volume <= 0) { _popups.PopupEntity(Loc.GetString("mopping-system-target-container-empty", ("target", target)), user, user); return false; } + var refillableSolution = refillableSoln.Comp.Solution; var transferAmount = component.PickupAmount < refillableSolution.AvailableVolume ? component.PickupAmount : refillableSolution.AvailableVolume; @@ -174,17 +177,15 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem } // Prioritize transferring non-evaporatives if absorbent has any - var contaminants = absorbentSolution.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents); + var contaminants = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, transferAmount, PuddleSystem.EvaporationReagents); if (contaminants.Volume > 0) { - _solutionSystem.UpdateChemicals(used, absorbentSolution, true); - _solutionSystem.TryAddSolution(target, refillableSolution, contaminants); + _solutionContainerSystem.TryAddSolution(refillableSoln, contaminants); } else { - var evaporatives = absorbentSolution.SplitSolution(transferAmount); - _solutionSystem.UpdateChemicals(used, absorbentSolution, true); - _solutionSystem.TryAddSolution(target, refillableSolution, evaporatives); + var evaporatives = _solutionContainerSystem.SplitSolution(absorbentSoln, transferAmount); + _solutionContainerSystem.TryAddSolution(refillableSoln, evaporatives); } return true; @@ -198,12 +199,12 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem EntityUid used, EntityUid target, AbsorbentComponent component, - Solution absorbentSolution, - Solution refillableSolution) + Entity absorbentSoln, + Entity refillableSoln) { - var contaminantsFromAbsorbent = absorbentSolution.SplitSolutionWithout(component.PickupAmount, PuddleSystem.EvaporationReagents); - _solutionSystem.UpdateChemicals(used, absorbentSolution, true); + var contaminantsFromAbsorbent = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, component.PickupAmount, PuddleSystem.EvaporationReagents); + var absorbentSolution = absorbentSoln.Comp.Solution; if (contaminantsFromAbsorbent.Volume == FixedPoint2.Zero && absorbentSolution.AvailableVolume == FixedPoint2.Zero) { // Nothing to transfer to refillable and no room to absorb anything extra @@ -217,8 +218,9 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem component.PickupAmount : absorbentSolution.AvailableVolume; + var refillableSolution = refillableSoln.Comp.Solution; var waterFromRefillable = refillableSolution.SplitSolutionWithOnly(waterPulled, PuddleSystem.EvaporationReagents); - _solutionSystem.UpdateChemicals(target, refillableSolution); + _solutionContainerSystem.UpdateChemicals(refillableSoln); if (waterFromRefillable.Volume == FixedPoint2.Zero && contaminantsFromAbsorbent.Volume == FixedPoint2.Zero) { @@ -234,7 +236,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem if (waterFromRefillable.Volume > FixedPoint2.Zero) { // transfer water to absorbent - _solutionSystem.TryAddSolution(used, absorbentSolution, waterFromRefillable); + _solutionContainerSystem.TryAddSolution(absorbentSoln, waterFromRefillable); anyTransferOccurred = true; } @@ -248,12 +250,12 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem { // transfer as much contaminants to refillable as will fit var contaminantsForRefillable = contaminantsFromAbsorbent.SplitSolution(refillableSolution.AvailableVolume); - _solutionSystem.TryAddSolution(target, refillableSolution, contaminantsForRefillable); + _solutionContainerSystem.TryAddSolution(refillableSoln, contaminantsForRefillable); anyTransferOccurred = true; } // absorb everything that did not fit in the refillable back by the absorbent - _solutionSystem.TryAddSolution(used, absorbentSolution, contaminantsFromAbsorbent); + _solutionContainerSystem.TryAddSolution(absorbentSoln, contaminantsFromAbsorbent); } return anyTransferOccurred; @@ -262,23 +264,24 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem /// /// Logic for an absorbing entity interacting with a puddle. /// - private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, Solution absorberSoln) + private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, Entity absorberSoln) { if (!TryComp(target, out PuddleComponent? puddle)) return false; - if (!_solutionSystem.TryGetSolution(target, puddle.SolutionName, out var puddleSoln) || puddleSoln.Volume <= 0) + if (!_solutionContainerSystem.ResolveSolution(target, puddle.SolutionName, ref puddle.Solution, out var puddleSolution) || puddleSolution.Volume <= 0) return false; // Check if the puddle has any non-evaporative reagents - if (_puddleSystem.CanFullyEvaporate(puddleSoln)) + if (_puddleSystem.CanFullyEvaporate(puddleSolution)) { _popups.PopupEntity(Loc.GetString("mopping-system-puddle-evaporate", ("target", target)), user, user); return true; } // Check if we have any evaporative reagents on our absorber to transfer - var available = absorberSoln.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents); + var absorberSolution = absorberSoln.Comp.Solution; + var available = absorberSolution.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents); // No material if (available == FixedPoint2.Zero) @@ -290,8 +293,8 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem var transferMax = absorber.PickupAmount; var transferAmount = available > transferMax ? transferMax : available; - var puddleSplit = puddleSoln.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents); - var absorberSplit = absorberSoln.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents); + var puddleSplit = puddleSolution.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents); + var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents); // Do tile reactions first var coordinates = Transform(target).Coordinates; @@ -300,11 +303,9 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem _puddleSystem.DoTileReactions(mapGrid.GetTileRef(coordinates), absorberSplit); } - puddleSoln.AddSolution(absorberSplit, _prototype); - absorberSoln.AddSolution(puddleSplit, _prototype); + _solutionContainerSystem.AddSolution(puddle.Solution.Value, absorberSplit); + _solutionContainerSystem.AddSolution(absorberSoln, puddleSplit); - _solutionSystem.UpdateChemicals(used, absorberSoln); - _solutionSystem.UpdateChemicals(target, puddleSoln); _audio.PlayPvs(absorber.PickupSound, target); _useDelay.BeginDelay(used); diff --git a/Content.Server/Fluids/EntitySystems/DrainSystem.cs b/Content.Server/Fluids/EntitySystems/DrainSystem.cs index 505ce71261..726ed0b13c 100644 --- a/Content.Server/Fluids/EntitySystems/DrainSystem.cs +++ b/Content.Server/Fluids/EntitySystems/DrainSystem.cs @@ -1,9 +1,9 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.DoAfter; using Content.Server.Fluids.Components; using Content.Server.Popups; using Content.Shared.Audio; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Examine; @@ -13,10 +13,9 @@ using Content.Shared.Fluids.Components; using Content.Shared.Interaction; using Content.Shared.Tag; using Content.Shared.Verbs; -using Content.Shared.Fluids.Components; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Collections; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -25,7 +24,7 @@ namespace Content.Server.Fluids.EntitySystems; public sealed class DrainSystem : SharedDrainSystem { [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; @@ -33,6 +32,7 @@ public sealed class DrainSystem : SharedDrainSystem [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly PuddleSystem _puddleSystem = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public override void Initialize() { @@ -43,7 +43,7 @@ public sealed class DrainSystem : SharedDrainSystem SubscribeLocalEvent(OnDoAfter); } - private void AddEmptyVerb(EntityUid uid, DrainComponent component, GetVerbsEvent args) + private void AddEmptyVerb(Entity entity, ref GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || args.Using == null) return; @@ -52,12 +52,14 @@ public sealed class DrainSystem : SharedDrainSystem !TryComp(args.Target, out DrainComponent? drain)) return; + var used = args.Using.Value; + var target = args.Target; Verb verb = new() { - Text = Loc.GetString("drain-component-empty-verb-inhand", ("object", Name(args.Using.Value))), + Text = Loc.GetString("drain-component-empty-verb-inhand", ("object", Name(used))), Act = () => { - Empty(args.Using.Value, spillable, args.Target, drain); + Empty(used, spillable, target, drain); }, Impact = LogImpact.Low, Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")) @@ -69,8 +71,7 @@ public sealed class DrainSystem : SharedDrainSystem private void Empty(EntityUid container, SpillableComponent spillable, EntityUid target, DrainComponent drain) { // Find the solution in the container that is emptied - if (!_solutionSystem.TryGetDrainableSolution(container, out var containerSolution) || - containerSolution.Volume == FixedPoint2.Zero) + if (!_solutionContainerSystem.TryGetDrainableSolution(container, out var containerSoln, out var containerSolution) || containerSolution.Volume == FixedPoint2.Zero) { _popupSystem.PopupEntity( Loc.GetString("drain-component-empty-verb-using-is-empty-message", ("object", container)), @@ -79,17 +80,17 @@ public sealed class DrainSystem : SharedDrainSystem } // try to find the drain's solution - if (!_solutionSystem.TryGetSolution(target, DrainComponent.SolutionName, out var drainSolution)) + if (!_solutionContainerSystem.ResolveSolution(target, DrainComponent.SolutionName, ref drain.Solution, out var drainSolution)) { return; } // Try to transfer as much solution as possible to the drain - var transferSolution = _solutionSystem.SplitSolution(container, containerSolution, + var transferSolution = _solutionContainerSystem.SplitSolution(containerSoln.Value, FixedPoint2.Min(containerSolution.Volume, drainSolution.AvailableVolume)); - _solutionSystem.TryAddSolution(target, drainSolution, transferSolution); + _solutionContainerSystem.TryAddSolution(drain.Solution.Value, transferSolution); _audioSystem.PlayPvs(drain.ManualDrainSound, target); _ambientSoundSystem.SetAmbience(target, true); @@ -111,7 +112,7 @@ public sealed class DrainSystem : SharedDrainSystem var managerQuery = GetEntityQuery(); var xformQuery = GetEntityQuery(); var puddleQuery = GetEntityQuery(); - var puddles = new ValueList<(EntityUid Entity, string Solution)>(); + var puddles = new ValueList<(Entity Entity, string Solution)>(); var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var drain)) @@ -134,9 +135,7 @@ public sealed class DrainSystem : SharedDrainSystem continue; // Best to do this one every second rather than once every tick... - _solutionSystem.TryGetSolution(uid, DrainComponent.SolutionName, out var drainSolution, manager); - - if (drainSolution is null) + if (!_solutionContainerSystem.ResolveSolution((uid, manager), DrainComponent.SolutionName, ref drain.Solution, out var drainSolution)) continue; if (drainSolution.AvailableVolume <= 0) @@ -146,7 +145,7 @@ public sealed class DrainSystem : SharedDrainSystem } // Remove a bit from the buffer - _solutionSystem.SplitSolution(uid, drainSolution, (drain.UnitsDestroyedPerSecond * drain.DrainFrequency)); + _solutionContainerSystem.SplitSolution(drain.Solution.Value, (drain.UnitsDestroyedPerSecond * drain.DrainFrequency)); // This will ensure that UnitsPerSecond is per second... var amount = drain.UnitsPerSecond * drain.DrainFrequency; @@ -162,7 +161,7 @@ public sealed class DrainSystem : SharedDrainSystem // and these are placed by mappers and not buildable/movable so shouldnt really be a problem... if (puddleQuery.TryGetComponent(entity, out var puddle)) { - puddles.Add((entity, puddle.SolutionName)); + puddles.Add(((entity, puddle), puddle.SolutionName)); } } @@ -180,7 +179,7 @@ public sealed class DrainSystem : SharedDrainSystem { // Queue the solution deletion if it's empty. EvaporationSystem might also do this // but queuedelete should be pretty safe. - if (!_solutionSystem.TryGetSolution(puddle, solution, out var puddleSolution)) + if (!_solutionContainerSystem.ResolveSolution(puddle.Owner, solution, ref puddle.Comp.Solution, out var puddleSolution)) { EntityManager.QueueDeleteEntity(puddle); continue; @@ -190,24 +189,26 @@ public sealed class DrainSystem : SharedDrainSystem // the drain component's units per second adjusted for # of puddles // the puddle's remaining volume (making it cleanly zero) // the drain's remaining volume in its buffer. - var transferSolution = _solutionSystem.SplitSolution(puddle, puddleSolution, + var transferSolution = _solutionContainerSystem.SplitSolution(puddle.Comp.Solution.Value, FixedPoint2.Min(FixedPoint2.New(amount), puddleSolution.Volume, drainSolution.AvailableVolume)); - _solutionSystem.TryAddSolution(uid, drainSolution, transferSolution); + drainSolution.AddSolution(transferSolution, _prototypeManager); if (puddleSolution.Volume <= 0) { QueueDel(puddle); } } + + _solutionContainerSystem.UpdateChemicals(drain.Solution.Value); } } - private void OnExamined(EntityUid uid, DrainComponent component, ExaminedEvent args) + private void OnExamined(Entity entity, ref ExaminedEvent args) { if (!args.IsInDetailsRange || - !HasComp(uid) || - !_solutionSystem.TryGetSolution(uid, DrainComponent.SolutionName, out var drainSolution)) + !HasComp(entity) || + !_solutionContainerSystem.ResolveSolution(entity.Owner, DrainComponent.SolutionName, ref entity.Comp.Solution, out var drainSolution)) { return; } @@ -218,11 +219,11 @@ public sealed class DrainSystem : SharedDrainSystem args.Message.AddMarkup($"\n\n{text}"); } - private void OnInteract(EntityUid uid, DrainComponent component, InteractEvent args) + private void OnInteract(Entity entity, ref AfterInteractUsingEvent args) { if (!args.CanReach || args.Target == null || !_tagSystem.HasTag(args.Used, DrainComponent.PlungerTag) || - !_solutionSystem.TryGetSolution(args.Target.Value, DrainComponent.SolutionName, out var drainSolution)) + !_solutionContainerSystem.ResolveSolution(args.Target.Value, DrainComponent.SolutionName, ref entity.Comp.Solution, out var drainSolution)) { return; } @@ -233,10 +234,10 @@ public sealed class DrainSystem : SharedDrainSystem return; } - _audioSystem.PlayPvs(component.PlungerSound, uid); + _audioSystem.PlayPvs(entity.Comp.PlungerSound, entity); - var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.UnclogDuration, new DrainDoAfterEvent(),uid, args.Target, args.Used) + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.UnclogDuration, new DrainDoAfterEvent(), entity, args.Target, args.Used) { BreakOnTargetMove = true, BreakOnUserMove = true, @@ -247,27 +248,26 @@ public sealed class DrainSystem : SharedDrainSystem _doAfterSystem.TryStartDoAfter(doAfterArgs); } - private void OnDoAfter(EntityUid uid, DrainComponent component, DoAfterEvent args) + private void OnDoAfter(Entity entity, ref DrainDoAfterEvent args) { if (args.Target == null) return; - if (!_random.Prob(component.UnclogProbability)) + if (!_random.Prob(entity.Comp.UnclogProbability)) { _popupSystem.PopupEntity(Loc.GetString("drain-component-unclog-fail", ("object", args.Target.Value)), args.Target.Value); return; } - if (!_solutionSystem.TryGetSolution(args.Target.Value, DrainComponent.SolutionName, - out var drainSolution)) + if (!_solutionContainerSystem.ResolveSolution(args.Target.Value, DrainComponent.SolutionName, ref entity.Comp.Solution)) { return; } - _solutionSystem.RemoveAllSolution(args.Target.Value, drainSolution); - _audioSystem.PlayPvs(component.UnclogSound, args.Target.Value); + _solutionContainerSystem.RemoveAllSolution(entity.Comp.Solution.Value); + _audioSystem.PlayPvs(entity.Comp.UnclogSound, args.Target.Value); _popupSystem.PopupEntity(Loc.GetString("drain-component-unclog-success", ("object", args.Target.Value)), args.Target.Value); } } diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs index d0df5e0505..f3489ba7c6 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs @@ -18,9 +18,9 @@ public sealed partial class PuddleSystem public static string[] EvaporationReagents = new[] { Water, SoapyWater }; - private void OnEvaporationMapInit(EntityUid uid, EvaporationComponent component, MapInitEvent args) + private void OnEvaporationMapInit(Entity entity, ref MapInitEvent args) { - component.NextTick = _timing.CurTime + EvaporationCooldown; + entity.Comp.NextTick = _timing.CurTime + EvaporationCooldown; } private void UpdateEvaporation(EntityUid uid, Solution solution) @@ -52,7 +52,7 @@ public sealed partial class PuddleSystem evaporation.NextTick += EvaporationCooldown; - if (!_solutionContainerSystem.TryGetSolution(uid, puddle.SolutionName, out var puddleSolution)) + if (!_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution, out var puddleSolution)) continue; var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds; diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs index e1681d8731..083d15c22e 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs @@ -1,4 +1,4 @@ -using Content.Server.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.Components; using Content.Server.Nutrition.EntitySystems; using Content.Shared.Chemistry.Components; @@ -36,29 +36,29 @@ public sealed partial class PuddleSystem SubscribeLocalEvent(SplashOnMeleeHit, after: new[] { typeof(OpenableSystem) }); SubscribeLocalEvent>(AddSpillVerb); SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnOverflow); + SubscribeLocalEvent(OnOverflow); SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent(OnAttemptPacifiedThrow); } - private void OnExamined(EntityUid uid, SpillableComponent component, ExaminedEvent args) + private void OnExamined(Entity entity, ref ExaminedEvent args) { args.PushMarkup(Loc.GetString("spill-examine-is-spillable")); - if (HasComp(uid)) + if (HasComp(entity)) args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon")); } - private void OnOverflow(EntityUid uid, SpillableComponent component, ref SolutionOverflowEvent args) + private void OnOverflow(Entity entity, ref SolutionContainerOverflowEvent args) { if (args.Handled) return; - TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _); + TrySpillAt(Transform(entity).Coordinates, args.Overflow, out _); args.Handled = true; } - private void SplashOnMeleeHit(EntityUid uid, SpillableComponent component, MeleeHitEvent args) + private void SplashOnMeleeHit(Entity entity, ref MeleeHitEvent args) { if (args.Handled) return; @@ -68,20 +68,20 @@ public sealed partial class PuddleSystem // If this also has solution transfer, then assume the transfer amount is how much we want to spill. // Otherwise let's say they want to spill a quarter of its max volume. - if (!_solutionContainerSystem.TryGetDrainableSolution(uid, out var solution)) + if (!_solutionContainerSystem.TryGetDrainableSolution(entity.Owner, out var soln, out var solution)) return; var hitCount = args.HitEntities.Count; var totalSplit = FixedPoint2.Min(solution.MaxVolume * 0.25, solution.Volume); - if (TryComp(uid, out var transfer)) + if (TryComp(entity, out var transfer)) { totalSplit = FixedPoint2.Min(transfer.TransferAmount, solution.Volume); } // a little lame, but reagent quantity is not very balanced and we don't want people // spilling like 100u of reagent on someone at once! - totalSplit = FixedPoint2.Min(totalSplit, component.MaxMeleeSpillAmount); + totalSplit = FixedPoint2.Min(totalSplit, entity.Comp.MaxMeleeSpillAmount); if (totalSplit == 0) return; @@ -95,29 +95,29 @@ public sealed partial class PuddleSystem continue; } - var splitSolution = _solutionContainerSystem.SplitSolution(uid, solution, totalSplit / hitCount); + var splitSolution = _solutionContainerSystem.SplitSolution(soln.Value, totalSplit / hitCount); - _adminLogger.Add(LogType.MeleeHit, $"{ToPrettyString(args.User)} splashed {SolutionContainerSystem.ToPrettyString(splitSolution):solution} from {ToPrettyString(uid):entity} onto {ToPrettyString(hit):target}"); + _adminLogger.Add(LogType.MeleeHit, $"{ToPrettyString(args.User)} splashed {SolutionContainerSystem.ToPrettyString(splitSolution):solution} from {ToPrettyString(entity.Owner):entity} onto {ToPrettyString(hit):target}"); _reactive.DoEntityReaction(hit, splitSolution, ReactionMethod.Touch); _popups.PopupEntity( - Loc.GetString("spill-melee-hit-attacker", ("amount", totalSplit / hitCount), ("spillable", uid), + Loc.GetString("spill-melee-hit-attacker", ("amount", totalSplit / hitCount), ("spillable", entity.Owner), ("target", Identity.Entity(hit, EntityManager))), hit, args.User); _popups.PopupEntity( - Loc.GetString("spill-melee-hit-others", ("attacker", args.User), ("spillable", uid), + Loc.GetString("spill-melee-hit-others", ("attacker", args.User), ("spillable", entity.Owner), ("target", Identity.Entity(hit, EntityManager))), hit, Filter.PvsExcept(args.User), true, PopupType.SmallCaution); } } - private void OnGotEquipped(EntityUid uid, SpillableComponent component, GotEquippedEvent args) + private void OnGotEquipped(Entity entity, ref GotEquippedEvent args) { - if (!component.SpillWorn) + if (!entity.Comp.SpillWorn) return; - if (!TryComp(uid, out ClothingComponent? clothing)) + if (!TryComp(entity, out ClothingComponent? clothing)) return; // check if entity was actually used as clothing @@ -126,33 +126,33 @@ public sealed partial class PuddleSystem if (!isCorrectSlot) return; - if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution)) return; if (solution.Volume == 0) return; // spill all solution on the player - var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.Volume); - TrySplashSpillAt(uid, Transform(args.Equipee).Coordinates, drainedSolution, out _); + var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume); + TrySplashSpillAt(entity.Owner, Transform(args.Equipee).Coordinates, drainedSolution, out _); } - private void SpillOnLand(EntityUid uid, SpillableComponent component, ref LandEvent args) + private void SpillOnLand(Entity entity, ref LandEvent args) { - if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution)) return; - if (_openable.IsClosed(uid)) + if (_openable.IsClosed(entity.Owner)) return; if (args.User != null) { _adminLogger.Add(LogType.Landed, - $"{ToPrettyString(uid):entity} spilled a solution {SolutionContainerSystem.ToPrettyString(solution):solution} on landing"); + $"{ToPrettyString(entity.Owner):entity} spilled a solution {SolutionContainerSystem.ToPrettyString(solution):solution} on landing"); } - var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.Volume); - TrySplashSpillAt(uid, Transform(uid).Coordinates, drainedSolution, out _); + var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume); + TrySplashSpillAt(entity.Owner, Transform(entity).Coordinates, drainedSolution, out _); } /// @@ -165,18 +165,18 @@ public sealed partial class PuddleSystem return; // Don’t care about empty containers. - if (!_solutionContainerSystem.TryGetSolution(ent, ent.Comp.SolutionName, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(ent.Owner, ent.Comp.SolutionName, out _, out var solution) || solution.Volume <= 0) return; args.Cancel("pacified-cannot-throw-spill"); } - private void AddSpillVerb(EntityUid uid, SpillableComponent component, GetVerbsEvent args) + private void AddSpillVerb(Entity entity, ref GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract) return; - if (!_solutionContainerSystem.TryGetSolution(args.Target, component.SolutionName, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(args.Target, entity.Comp.SolutionName, out var soln, out var solution)) return; if (_openable.IsClosed(args.Target)) @@ -195,20 +195,21 @@ public sealed partial class PuddleSystem }; // TODO VERB ICONS spill icon? pouring out a glass/beaker? - if (component.SpillDelay == null) + if (entity.Comp.SpillDelay == null) { + var target = args.Target; verb.Act = () => { - var puddleSolution = _solutionContainerSystem.SplitSolution(args.Target, - solution, solution.Volume); - TrySpillAt(Transform(args.Target).Coordinates, puddleSolution, out _); + var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume); + TrySpillAt(Transform(target).Coordinates, puddleSolution, out _); }; } else { + var user = args.User; verb.Act = () => { - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.SpillDelay ?? 0, new SpillDoAfterEvent(), uid, target: uid) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, entity.Comp.SpillDelay ?? 0, new SpillDoAfterEvent(), entity.Owner, target: entity.Owner) { BreakOnTargetMove = true, BreakOnUserMove = true, @@ -222,17 +223,17 @@ public sealed partial class PuddleSystem args.Verbs.Add(verb); } - private void OnDoAfter(EntityUid uid, SpillableComponent component, DoAfterEvent args) + private void OnDoAfter(Entity entity, ref SpillDoAfterEvent args) { if (args.Handled || args.Cancelled || args.Args.Target == null) return; //solution gone by other means before doafter completes - if (!_solutionContainerSystem.TryGetDrainableSolution(uid, out var solution) || solution.Volume == 0) + if (!_solutionContainerSystem.TryGetDrainableSolution(entity.Owner, out var soln, out var solution) || solution.Volume == 0) return; - var puddleSolution = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume); - TrySpillAt(Transform(uid).Coordinates, puddleSolution, out _); + var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume); + TrySpillAt(Transform(entity).Coordinates, puddleSolution, out _); args.Handled = true; } } diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Transfers.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Transfers.cs index ba73adf389..04bbf55c58 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Transfers.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Transfers.cs @@ -1,9 +1,7 @@ -using Content.Server.Fluids.Components; using Content.Shared.Chemistry.Components; using Content.Shared.DragDrop; using Content.Shared.FixedPoint; using Content.Shared.Fluids; -using Content.Shared.Fluids.Components; namespace Content.Server.Fluids.EntitySystems; @@ -14,33 +12,30 @@ public sealed partial class PuddleSystem SubscribeLocalEvent(OnRefillableDragged); } - private void OnRefillableDragged(EntityUid uid, RefillableSolutionComponent component, ref DragDropDraggedEvent args) + private void OnRefillableDragged(Entity entity, ref DragDropDraggedEvent args) { - _solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution); - - if (solution?.Volume == FixedPoint2.Zero) + if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.Solution, out var soln, out var solution) || solution.Volume == FixedPoint2.Zero) { - _popups.PopupEntity(Loc.GetString("mopping-system-empty", ("used", uid)), uid, args.User); + _popups.PopupEntity(Loc.GetString("mopping-system-empty", ("used", entity.Owner)), entity, args.User); return; } // Dump reagents into DumpableSolution if (TryComp(args.Target, out var dump)) { - _solutionContainerSystem.TryGetDumpableSolution(args.Target, out var dumpableSolution, dump); - if (dumpableSolution == null || solution == null) + if (!_solutionContainerSystem.TryGetDumpableSolution((args.Target, dump, null), out var dumpableSoln, out var dumpableSolution)) return; bool success = true; if (dump.Unlimited) { - var split = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume); + var split = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume); dumpableSolution.AddSolution(split, _prototypeManager); } else { - var split = _solutionContainerSystem.SplitSolution(uid, solution, dumpableSolution.AvailableVolume); - success = _solutionContainerSystem.TryAddSolution(args.Target, dumpableSolution, split); + var split = _solutionContainerSystem.SplitSolution(soln.Value, dumpableSolution.AvailableVolume); + success = _solutionContainerSystem.TryAddSolution(dumpableSoln.Value, split); } if (success) @@ -55,25 +50,21 @@ public sealed partial class PuddleSystem return; } - TryComp(args.Target, out var drainable); - - _solutionContainerSystem.TryGetDrainableSolution(args.Target, out var drainableSolution, drainable); - // Take reagents from target - if (drainable != null) + if (!TryComp(args.Target, out var drainable)) { - if (drainableSolution == null || solution == null) + if (!_solutionContainerSystem.TryGetDrainableSolution((args.Target, drainable, null), out var drainableSolution, out _)) return; - var split = _solutionContainerSystem.SplitSolution(args.Target, drainableSolution, solution.AvailableVolume); + var split = _solutionContainerSystem.SplitSolution(drainableSolution.Value, solution.AvailableVolume); - if (_solutionContainerSystem.TryAddSolution(uid, solution, split)) + if (_solutionContainerSystem.TryAddSolution(soln.Value, split)) { - _audio.PlayPvs(AbsorbentComponent.DefaultTransferSound, uid); + _audio.PlayPvs(AbsorbentComponent.DefaultTransferSound, entity); } else { - _popups.PopupEntity(Loc.GetString("mopping-system-full", ("used", uid)), uid, args.User); + _popups.PopupEntity(Loc.GetString("mopping-system-full", ("used", entity.Owner)), entity, args.User); } } } diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs index 05d0809bb2..844f43a5e4 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Administration.Logs; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.DoAfter; using Content.Server.Fluids.Components; using Content.Server.Spreader; @@ -22,19 +23,13 @@ using Content.Shared.Popups; using Content.Shared.Slippery; using Content.Shared.StepTrigger.Components; using Content.Shared.StepTrigger.Systems; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; +using Robust.Server.Audio; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; -using Content.Shared.Movement.Components; -using Content.Shared.Movement.Systems; -using Content.Shared.Maps; -using Content.Shared.Effects; -using Robust.Server.Audio; namespace Content.Server.Fluids.EntitySystems; @@ -91,7 +86,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem // Shouldn't need re-anchoring. SubscribeLocalEvent(OnAnchorChanged); SubscribeLocalEvent(HandlePuddleExamined); - SubscribeLocalEvent(OnSolutionUpdate); + SubscribeLocalEvent(OnSolutionUpdate); SubscribeLocalEvent(OnPuddleInit); SubscribeLocalEvent(OnPuddleSpread); SubscribeLocalEvent(OnPuddleSlip); @@ -102,13 +97,13 @@ public sealed partial class PuddleSystem : SharedPuddleSystem InitializeTransfers(); } - private void OnPuddleSpread(EntityUid uid, PuddleComponent component, ref SpreadNeighborsEvent args) + private void OnPuddleSpread(Entity entity, ref SpreadNeighborsEvent args) { - var overflow = GetOverflowSolution(uid, component); + var overflow = GetOverflowSolution(entity.Owner, entity.Comp); if (overflow.Volume == FixedPoint2.Zero) { - RemCompDeferred(uid); + RemCompDeferred(entity); return; } @@ -125,7 +120,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem foreach (var neighbor in args.Neighbors) { if (!puddleQuery.TryGetComponent(neighbor, out var puddle) || - !_solutionContainerSystem.TryGetSolution(neighbor, puddle.SolutionName, out var neighborSolution) || + !_solutionContainerSystem.ResolveSolution(neighbor, puddle.SolutionName, ref puddle.Solution, out var neighborSolution) || CanFullyEvaporate(neighborSolution)) { continue; @@ -138,7 +133,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem var split = overflow.SplitSolution(remaining); - if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split)) + if (!_solutionContainerSystem.TryAddSolution(puddle.Solution.Value, split)) continue; args.Updates--; @@ -150,7 +145,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem if (overflow.Volume == FixedPoint2.Zero) { - RemCompDeferred(uid); + RemCompDeferred(entity); return; } } @@ -173,7 +168,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem break; } - RemCompDeferred(uid); + RemCompDeferred(entity); return; } @@ -186,7 +181,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem { // Overflow to neighbours (unless it's pure water) if (!puddleQuery.TryGetComponent(neighbor, out var puddle) || - !_solutionContainerSystem.TryGetSolution(neighbor, puddle.SolutionName, out var neighborSolution) || + !_solutionContainerSystem.ResolveSolution(neighbor, puddle.SolutionName, ref puddle.Solution, out var neighborSolution) || CanFullyEvaporate(neighborSolution)) { continue; @@ -194,7 +189,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem var split = overflow.SplitSolution(spillPerNeighbor); - if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split)) + if (!_solutionContainerSystem.TryAddSolution(puddle.Solution.Value, split)) continue; EnsureComp(neighbor); @@ -206,13 +201,13 @@ public sealed partial class PuddleSystem : SharedPuddleSystem } // Add the remainder back - if (_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var puddleSolution)) + if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution)) { - _solutionContainerSystem.TryAddSolution(uid, puddleSolution, overflow); + _solutionContainerSystem.TryAddSolution(entity.Comp.Solution.Value, overflow); } } - private void OnPuddleSlip(EntityUid uid, PuddleComponent component, ref SlipEvent args) + private void OnPuddleSlip(Entity entity, ref SlipEvent args) { // Reactive entities have a chance to get a touch reaction from slipping on a puddle // (i.e. it is implied they fell face first onto it or something) @@ -224,14 +219,14 @@ public sealed partial class PuddleSystem : SharedPuddleSystem if (!_random.Prob(0.5f)) return; - if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution)) + if (!_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution)) return; - _popups.PopupEntity(Loc.GetString("puddle-component-slipped-touch-reaction", ("puddle", uid)), + _popups.PopupEntity(Loc.GetString("puddle-component-slipped-touch-reaction", ("puddle", entity.Owner)), args.Slipped, args.Slipped, PopupType.SmallCaution); // Take 15% of the puddle solution - var splitSol = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume * 0.15f); + var splitSol = _solutionContainerSystem.SplitSolution(entity.Comp.Solution.Value, solution.Volume * 0.15f); _reactive.DoEntityReaction(args.Slipped, splitSol, ReactionMethod.Touch); } @@ -248,27 +243,27 @@ public sealed partial class PuddleSystem : SharedPuddleSystem TickEvaporation(); } - private void OnPuddleInit(EntityUid uid, PuddleComponent component, ComponentInit args) + private void OnPuddleInit(Entity entity, ref ComponentInit args) { - _solutionContainerSystem.EnsureSolution(uid, component.SolutionName, FixedPoint2.New(PuddleVolume), out _); + _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName, FixedPoint2.New(PuddleVolume), out _); } - private void OnSolutionUpdate(EntityUid uid, PuddleComponent component, SolutionChangedEvent args) + private void OnSolutionUpdate(Entity entity, ref SolutionContainerChangedEvent args) { - if (args.Solution.Name != component.SolutionName) + if (args.SolutionId != entity.Comp.SolutionName) return; if (args.Solution.Volume <= 0) { - _deletionQueue.Add(uid); + _deletionQueue.Add(entity); return; } - _deletionQueue.Remove(uid); - UpdateSlip(uid, component, args.Solution); - UpdateSlow(uid, args.Solution); - UpdateEvaporation(uid, args.Solution); - UpdateAppearance(uid, component); + _deletionQueue.Remove(entity); + UpdateSlip(entity, entity.Comp, args.Solution); + UpdateSlow(entity, args.Solution); + UpdateEvaporation(entity, args.Solution); + UpdateAppearance(entity, entity.Comp); } private void UpdateAppearance(EntityUid uid, PuddleComponent? puddleComponent = null, AppearanceComponent? appearance = null) @@ -281,7 +276,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem var volume = FixedPoint2.Zero; Color color = Color.White; - if (_solutionContainerSystem.TryGetSolution(uid, puddleComponent.SolutionName, out var solution)) + if (_solutionContainerSystem.ResolveSolution(uid, puddleComponent.SolutionName, ref puddleComponent.Solution, out var solution)) { volume = solution.Volume / puddleComponent.OverflowVolume; @@ -364,39 +359,31 @@ public sealed partial class PuddleSystem : SharedPuddleSystem } } - private void HandlePuddleExamined(EntityUid uid, PuddleComponent component, ExaminedEvent args) + private void HandlePuddleExamined(Entity entity, ref ExaminedEvent args) { - if (TryComp(uid, out var slippery) && slippery.Active) + if (TryComp(entity, out var slippery) && slippery.Active) { args.PushMarkup(Loc.GetString("puddle-component-examine-is-slipper-text")); } - if (HasComp(uid)) + if (HasComp(entity) && + _solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution)) { - if (_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution) && - CanFullyEvaporate(solution)) - { + if (CanFullyEvaporate(solution)) args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating")); - } - else if (solution?.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero) - { + else if (solution.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero) args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial")); - } else - { args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no")); - } } else - { args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no")); - } } - private void OnAnchorChanged(EntityUid uid, PuddleComponent puddle, ref AnchorStateChangedEvent args) + private void OnAnchorChanged(Entity entity, ref AnchorStateChangedEvent args) { if (!args.Anchored) - QueueDel(uid); + QueueDel(entity); } /// @@ -407,8 +394,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem if (!Resolve(uid, ref puddleComponent)) return FixedPoint2.Zero; - return _solutionContainerSystem.TryGetSolution(uid, puddleComponent.SolutionName, - out var solution) + return _solutionContainerSystem.ResolveSolution(uid, puddleComponent.SolutionName, ref puddleComponent.Solution, out var solution) ? solution.Volume : FixedPoint2.Zero; } @@ -432,14 +418,12 @@ public sealed partial class PuddleSystem : SharedPuddleSystem return false; if (addedSolution.Volume == 0 || - !_solutionContainerSystem.TryGetSolution(puddleUid, puddleComponent.SolutionName, - out var solution)) + !_solutionContainerSystem.ResolveSolution(puddleUid, puddleComponent.SolutionName, ref puddleComponent.Solution)) { return false; } - solution.AddSolution(addedSolution, _prototypeManager); - _solutionContainerSystem.UpdateChemicals(puddleUid, solution, true); + _solutionContainerSystem.AddSolution(puddleComponent.Solution.Value, addedSolution); if (checkForOverflow && IsOverflowing(puddleUid, puddleComponent)) { @@ -482,15 +466,14 @@ public sealed partial class PuddleSystem : SharedPuddleSystem /// public Solution GetOverflowSolution(EntityUid uid, PuddleComponent? puddle = null) { - if (!Resolve(uid, ref puddle) || !_solutionContainerSystem.TryGetSolution(uid, puddle.SolutionName, - out var solution)) + if (!Resolve(uid, ref puddle) || !_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution)) { return new Solution(0); } // TODO: This is going to fail with struct solutions. var remaining = puddle.OverflowVolume; - var split = _solutionContainerSystem.SplitSolution(uid, solution, CurrentVolume(uid, puddle) - remaining); + var split = _solutionContainerSystem.SplitSolution(puddle.Solution.Value, CurrentVolume(uid, puddle) - remaining); return split; } diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index 5459dacf0b..795655068f 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -1,7 +1,7 @@ -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Chemistry.ReactionEffects; using Content.Server.Spreader; using Content.Shared.Chemistry; @@ -21,6 +21,8 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; +using System.Linq; + using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; namespace Content.Server.Fluids.EntitySystems; @@ -42,7 +44,7 @@ public sealed class SmokeSystem : EntitySystem [Dependency] private readonly ReactiveSystem _reactive = default!; [Dependency] private readonly SharedBroadphaseSystem _broadphase = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly TransformSystem _transform = default!; private EntityQuery _smokeQuery; @@ -59,6 +61,7 @@ public sealed class SmokeSystem : EntitySystem SubscribeLocalEvent(OnStartCollide); SubscribeLocalEvent(OnEndCollide); SubscribeLocalEvent(OnReactionAttempt); + SubscribeLocalEvent>(OnReactionAttempt); SubscribeLocalEvent(OnSmokeSpread); SubscribeLocalEvent(OnAffectedUnpaused); } @@ -80,33 +83,33 @@ public sealed class SmokeSystem : EntitySystem } } - private void OnStartCollide(EntityUid uid, SmokeComponent component, ref StartCollideEvent args) + private void OnStartCollide(Entity entity, ref StartCollideEvent args) { if (_smokeAffectedQuery.HasComponent(args.OtherEntity)) return; var smokeAffected = AddComp(args.OtherEntity); - smokeAffected.SmokeEntity = uid; + smokeAffected.SmokeEntity = entity; smokeAffected.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1); } - private void OnEndCollide(EntityUid uid, SmokeComponent component, ref EndCollideEvent args) + private void OnEndCollide(Entity entity, ref EndCollideEvent args) { // if we are already in smoke, make sure the thing we are exiting is the current smoke we are in. if (_smokeAffectedQuery.TryGetComponent(args.OtherEntity, out var smokeAffectedComponent)) { - if (smokeAffectedComponent.SmokeEntity != uid) + if (smokeAffectedComponent.SmokeEntity != entity.Owner) return; } - var exists = Exists(uid); + var exists = Exists(entity); if (!TryComp(args.OtherEntity, out var body)) return; foreach (var ent in _physics.GetContactingEntities(args.OtherEntity, body)) { - if (exists && ent == uid) + if (exists && ent == entity.Owner) continue; if (!_smokeQuery.HasComponent(ent)) @@ -121,51 +124,51 @@ public sealed class SmokeSystem : EntitySystem RemComp(args.OtherEntity, smokeAffectedComponent); } - private void OnAffectedUnpaused(EntityUid uid, SmokeAffectedComponent component, ref EntityUnpausedEvent args) + private void OnAffectedUnpaused(Entity entity, ref EntityUnpausedEvent args) { - component.NextSecond += args.PausedTime; + entity.Comp.NextSecond += args.PausedTime; } - private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args) + private void OnSmokeSpread(Entity entity, ref SpreadNeighborsEvent args) { - if (component.SpreadAmount == 0 || !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution)) + if (entity.Comp.SpreadAmount == 0 || !_solutionContainerSystem.ResolveSolution(entity.Owner, SmokeComponent.SolutionName, ref entity.Comp.Solution, out var solution)) { - RemCompDeferred(uid); + RemCompDeferred(entity); return; } - if (Prototype(uid) is not { } prototype) + if (Prototype(entity) is not { } prototype) { - RemCompDeferred(uid); + RemCompDeferred(entity); return; } if (!args.NeighborFreeTiles.Any()) return; - TryComp(uid, out var timer); + TryComp(entity, out var timer); // wtf is the logic behind any of this. - var smokePerSpread = component.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count); + var smokePerSpread = entity.Comp.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count); foreach (var neighbor in args.NeighborFreeTiles) { var coords = neighbor.Grid.GridTileToLocal(neighbor.Tile); var ent = Spawn(prototype.ID, coords); var spreadAmount = Math.Max(0, smokePerSpread); - component.SpreadAmount -= args.NeighborFreeTiles.Count(); + entity.Comp.SpreadAmount -= args.NeighborFreeTiles.Count(); - StartSmoke(ent, solution.Clone(), timer?.Lifetime ?? component.Duration, spreadAmount); + StartSmoke(ent, solution.Clone(), timer?.Lifetime ?? entity.Comp.Duration, spreadAmount); - if (component.SpreadAmount == 0) + if (entity.Comp.SpreadAmount == 0) { - RemCompDeferred(uid); + RemCompDeferred(entity); break; } } args.Updates--; - if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || component.SpreadAmount < 1) + if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || entity.Comp.SpreadAmount < 1) return; // We have no more neighbours to spread to. So instead we will randomly distribute our volume to neighbouring smoke tiles. @@ -179,21 +182,21 @@ public sealed class SmokeSystem : EntitySystem continue; smoke.SpreadAmount++; - component.SpreadAmount--; + entity.Comp.SpreadAmount--; EnsureComp(neighbor); - if (component.SpreadAmount == 0) + if (entity.Comp.SpreadAmount == 0) { - RemCompDeferred(uid); + RemCompDeferred(entity); break; } } } - private void OnReactionAttempt(EntityUid uid, SmokeComponent component, ReactionAttemptEvent args) + private void OnReactionAttempt(Entity entity, ref ReactionAttemptEvent args) { - if (args.Solution.Name != SmokeComponent.SolutionName) + if (args.Cancelled) return; // Prevent smoke/foam fork bombs (smoke creating more smoke). @@ -201,12 +204,18 @@ public sealed class SmokeSystem : EntitySystem { if (effect is AreaReactionEffect) { - args.Cancel(); + args.Cancelled = true; return; } } } + private void OnReactionAttempt(Entity entity, ref SolutionRelayEvent args) + { + if (args.Name == SmokeComponent.SolutionName) + OnReactionAttempt(entity, ref args.Event); + } + /// /// Sets up a smoke component for spreading. /// @@ -245,14 +254,14 @@ public sealed class SmokeSystem : EntitySystem if (!Resolve(smokeUid, ref component)) return; - if (!_solutionSystem.TryGetSolution(smokeUid, SmokeComponent.SolutionName, out var solution) || + if (!_solutionContainerSystem.ResolveSolution(smokeUid, SmokeComponent.SolutionName, ref component.Solution, out var solution) || solution.Contents.Count == 0) { return; } ReactWithEntity(entity, smokeUid, solution, component); - UpdateVisuals(smokeUid); + UpdateVisuals((smokeUid, component)); } private void ReactWithEntity(EntityUid entity, EntityUid smokeUid, Solution solution, SmokeComponent? component = null) @@ -263,11 +272,14 @@ public sealed class SmokeSystem : EntitySystem if (!TryComp(entity, out var bloodstream)) return; - var blockIngestion = _internals.AreInternalsWorking(entity); + if (!_solutionContainerSystem.ResolveSolution(entity, bloodstream.ChemicalSolutionName, ref bloodstream.ChemicalSolution, out var chemSolution) || chemSolution.AvailableVolume <= 0) + return; + + var blockIngestion = _internals.AreInternalsWorking(entity); var cloneSolution = solution.Clone(); var availableTransfer = FixedPoint2.Min(cloneSolution.Volume, component.TransferRate); - var transferAmount = FixedPoint2.Min(availableTransfer, bloodstream.ChemicalSolution.AvailableVolume); + var transferAmount = FixedPoint2.Min(availableTransfer, chemSolution.AvailableVolume); var transferSolution = cloneSolution.SplitSolution(transferAmount); foreach (var reagentQuantity in transferSolution.Contents.ToArray()) @@ -296,7 +308,7 @@ public sealed class SmokeSystem : EntitySystem if (!Resolve(uid, ref component, ref xform)) return; - if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) || !solution.Any()) + if (!_solutionContainerSystem.ResolveSolution(uid, SmokeComponent.SolutionName, ref component.Solution, out var solution) || !solution.Any()) return; if (!_mapManager.TryGetGrid(xform.GridUid, out var mapGrid)) @@ -317,29 +329,30 @@ public sealed class SmokeSystem : EntitySystem /// /// Adds the specified solution to the relevant smoke solution. /// - private void TryAddSolution(EntityUid uid, Solution solution) + private void TryAddSolution(Entity smoke, Solution solution) { if (solution.Volume == FixedPoint2.Zero) return; - if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solutionArea)) + if (!Resolve(smoke, ref smoke.Comp)) return; - var addSolution = - solution.SplitSolution(FixedPoint2.Min(solution.Volume, solutionArea.AvailableVolume)); + if (!_solutionContainerSystem.ResolveSolution(smoke.Owner, SmokeComponent.SolutionName, ref smoke.Comp.Solution, out var solutionArea)) + return; - _solutionSystem.TryAddSolution(uid, solutionArea, addSolution); + var addSolution = solution.SplitSolution(FixedPoint2.Min(solution.Volume, solutionArea.AvailableVolume)); + _solutionContainerSystem.TryAddSolution(smoke.Comp.Solution.Value, addSolution); - UpdateVisuals(uid); + UpdateVisuals(smoke); } - private void UpdateVisuals(EntityUid uid) + private void UpdateVisuals(Entity smoke) { - if (!TryComp(uid, out AppearanceComponent? appearance) || - !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution)) + if (!Resolve(smoke, ref smoke.Comp1, ref smoke.Comp2) || + !_solutionContainerSystem.ResolveSolution(smoke.Owner, SmokeComponent.SolutionName, ref smoke.Comp1.Solution, out var solution)) return; var color = solution.GetColor(_prototype); - _appearance.SetData(uid, SmokeVisuals.Color, color, appearance); + _appearance.SetData(smoke.Owner, SmokeVisuals.Color, color, smoke.Comp2); } } diff --git a/Content.Server/Fluids/EntitySystems/SpraySystem.cs b/Content.Server/Fluids/EntitySystems/SpraySystem.cs index 1b87b3ef24..5acd2c9118 100644 --- a/Content.Server/Fluids/EntitySystems/SpraySystem.cs +++ b/Content.Server/Fluids/EntitySystems/SpraySystem.cs @@ -1,22 +1,21 @@ -using System.Numerics; using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Chemistry.EntitySystems; using Content.Server.Cooldown; using Content.Server.Extinguisher; using Content.Server.Fluids.Components; using Content.Server.Gravity; using Content.Server.Popups; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Cooldown; using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Vapor; using Robust.Server.GameObjects; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Physics.Components; using Robust.Shared.Prototypes; using Robust.Shared.Timing; +using System.Numerics; namespace Content.Server.Fluids.EntitySystems; @@ -40,23 +39,23 @@ public sealed class SpraySystem : EntitySystem SubscribeLocalEvent(OnAfterInteract, after: new[] { typeof(FireExtinguisherSystem) }); } - private void OnAfterInteract(EntityUid uid, SprayComponent component, AfterInteractEvent args) + private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled) return; args.Handled = true; - if (!_solutionContainer.TryGetSolution(uid, SprayComponent.SolutionName, out var solution)) + if (!_solutionContainer.TryGetSolution(entity.Owner, SprayComponent.SolutionName, out var soln, out var solution)) return; var ev = new SprayAttemptEvent(args.User); - RaiseLocalEvent(uid, ev); + RaiseLocalEvent(entity, ev); if (ev.Cancelled) return; var curTime = _gameTiming.CurTime; - if (TryComp(uid, out var cooldown) + if (TryComp(entity, out var cooldown) && curTime < cooldown.CooldownEnd) { return; @@ -64,8 +63,7 @@ public sealed class SpraySystem : EntitySystem if (solution.Volume <= 0) { - _popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), uid, - args.User); + _popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), entity.Owner, args.User); return; } @@ -82,9 +80,9 @@ public sealed class SpraySystem : EntitySystem var diffNorm = diffPos.Normalized(); var diffLength = diffPos.Length(); - if (diffLength > component.SprayDistance) + if (diffLength > entity.Comp.SprayDistance) { - diffLength = component.SprayDistance; + diffLength = entity.Comp.SprayDistance; } var diffAngle = diffNorm.ToAngle(); @@ -93,8 +91,8 @@ public sealed class SpraySystem : EntitySystem var threeQuarters = diffNorm * 0.75f; var quarter = diffNorm * 0.25f; - var amount = Math.Max(Math.Min((solution.Volume / component.TransferAmount).Int(), component.VaporAmount), 1); - var spread = component.VaporSpread / amount; + var amount = Math.Max(Math.Min((solution.Volume / entity.Comp.TransferAmount).Int(), entity.Comp.VaporAmount), 1); + var spread = entity.Comp.VaporSpread / amount; // TODO: Just use usedelay homie. var cooldownTime = 0f; @@ -108,18 +106,18 @@ public sealed class SpraySystem : EntitySystem .Offset((diffNorm + rotation.ToVec()).Normalized() * diffLength + quarter); var distance = (target.Position - userMapPos.Position).Length(); - if (distance > component.SprayDistance) - target = userMapPos.Offset(diffNorm * component.SprayDistance); + if (distance > entity.Comp.SprayDistance) + target = userMapPos.Offset(diffNorm * entity.Comp.SprayDistance); - var adjustedSolutionAmount = component.TransferAmount / component.VaporAmount; - var newSolution = _solutionContainer.SplitSolution(uid, solution, adjustedSolutionAmount); + var adjustedSolutionAmount = entity.Comp.TransferAmount / entity.Comp.VaporAmount; + var newSolution = _solutionContainer.SplitSolution(soln.Value, adjustedSolutionAmount); if (newSolution.Volume <= FixedPoint2.Zero) break; // Spawn the vapor cloud onto the grid/map the user is present on. Offset the start position based on how far the target destination is. var vaporPos = userMapPos.Offset(distance < 1 ? quarter : threeQuarters); - var vapor = Spawn(component.SprayedPrototype, vaporPos); + var vapor = Spawn(entity.Comp.SprayedPrototype, vaporPos); var vaporXform = xformQuery.GetComponent(vapor); _transform.SetWorldRotation(vaporXform, rotation); @@ -137,22 +135,21 @@ public sealed class SpraySystem : EntitySystem // impulse direction is defined in world-coordinates, not local coordinates var impulseDirection = rotation.ToVec(); - var time = diffLength / component.SprayVelocity; + var time = diffLength / entity.Comp.SprayVelocity; cooldownTime = MathF.Max(time, cooldownTime); - _vapor.Start(ent, vaporXform, impulseDirection * diffLength, component.SprayVelocity, target, time, args.User); + _vapor.Start(ent, vaporXform, impulseDirection * diffLength, entity.Comp.SprayVelocity, target, time, args.User); if (TryComp(args.User, out var body)) { if (_gravity.IsWeightless(args.User, body)) - _physics.ApplyLinearImpulse(args.User, -impulseDirection.Normalized() * component.PushbackAmount, body: body); + _physics.ApplyLinearImpulse(args.User, -impulseDirection.Normalized() * entity.Comp.PushbackAmount, body: body); } } - _audio.PlayPvs(component.SpraySound, uid, component.SpraySound.Params.WithVariation(0.125f)); + _audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f)); - RaiseLocalEvent(uid, - new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true); + RaiseLocalEvent(entity, new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true); } } diff --git a/Content.Server/Glue/GlueSystem.cs b/Content.Server/Glue/GlueSystem.cs index 58eed00c49..2b7f0060bc 100644 --- a/Content.Server/Glue/GlueSystem.cs +++ b/Content.Server/Glue/GlueSystem.cs @@ -1,16 +1,15 @@ using Content.Server.Administration.Logs; -using Content.Shared.Popups; -using Content.Shared.Item; -using Content.Shared.Glue; -using Content.Shared.Interaction; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.EntitySystems; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; +using Content.Shared.Glue; using Content.Shared.Hands; -using Robust.Shared.Timing; +using Content.Shared.Interaction; using Content.Shared.Interaction.Components; -using Robust.Shared.Audio; +using Content.Shared.Item; +using Content.Shared.Popups; using Robust.Shared.Audio.Systems; +using Robust.Shared.Timing; namespace Content.Server.Glue; @@ -33,7 +32,7 @@ public sealed class GlueSystem : SharedGlueSystem } // When glue bottle is used on item it will apply the glued and unremoveable components. - private void OnInteract(EntityUid uid, GlueComponent component, AfterInteractEvent args) + private void OnInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled) return; @@ -41,10 +40,10 @@ public sealed class GlueSystem : SharedGlueSystem if (!args.CanReach || args.Target is not { Valid: true } target) return; - if (TryGlue(uid, component, target, args.User)) + if (TryGlue(entity, target, args.User)) { args.Handled = true; - _audio.PlayPvs(component.Squeeze, uid); + _audio.PlayPvs(entity.Comp.Squeeze, entity); _popup.PopupEntity(Loc.GetString("glue-success", ("target", target)), args.User, args.User, PopupType.Medium); } else @@ -53,7 +52,7 @@ public sealed class GlueSystem : SharedGlueSystem } } - private bool TryGlue(EntityUid uid, GlueComponent component, EntityUid target, EntityUid actor) + private bool TryGlue(Entity glue, EntityUid target, EntityUid actor) { // if item is glued then don't apply glue again so it can be removed for reasonable time if (HasComp(target) || !HasComp(target)) @@ -61,13 +60,13 @@ public sealed class GlueSystem : SharedGlueSystem return false; } - if (HasComp(target) && _solutionContainer.TryGetSolution(uid, component.Solution, out var solution)) + if (HasComp(target) && _solutionContainer.TryGetSolution(glue.Owner, glue.Comp.Solution, out _, out var solution)) { - var quantity = solution.RemoveReagent(component.Reagent, component.ConsumptionUnit); + var quantity = solution.RemoveReagent(glue.Comp.Reagent, glue.Comp.ConsumptionUnit); if (quantity > 0) { - EnsureComp(target).Duration = quantity.Double() * component.DurationPerUnit; - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} glued {ToPrettyString(target):subject} with {ToPrettyString(uid):tool}"); + EnsureComp(target).Duration = quantity.Double() * glue.Comp.DurationPerUnit; + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} glued {ToPrettyString(target):subject} with {ToPrettyString(glue.Owner):tool}"); return true; } } @@ -90,17 +89,17 @@ public sealed class GlueSystem : SharedGlueSystem } } - private void OnGluedInit(EntityUid uid, GluedComponent component, ComponentInit args) + private void OnGluedInit(Entity entity, ref ComponentInit args) { - var meta = MetaData(uid); + var meta = MetaData(entity); var name = meta.EntityName; - component.BeforeGluedEntityName = meta.EntityName; - _metaData.SetEntityName(uid, Loc.GetString("glued-name-prefix", ("target", name))); + entity.Comp.BeforeGluedEntityName = meta.EntityName; + _metaData.SetEntityName(entity.Owner, Loc.GetString("glued-name-prefix", ("target", name))); } - private void OnHandPickUp(EntityUid uid, GluedComponent component, GotEquippedHandEvent args) + private void OnHandPickUp(Entity entity, ref GotEquippedHandEvent args) { - EnsureComp(uid); - component.Until = _timing.CurTime + component.Duration; + EnsureComp(entity); + entity.Comp.Until = _timing.CurTime + entity.Comp.Duration; } } diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index e4159f89ef..c7e1824c40 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -1,9 +1,8 @@ -using System.Linq; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Construction; using Content.Server.DeviceLinking.Events; using Content.Server.DeviceLinking.Systems; -using Content.Server.DeviceNetwork; using Content.Server.Hands.Systems; using Content.Server.Kitchen.Components; using Content.Server.Power.Components; @@ -31,6 +30,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Player; +using System.Linq; namespace Content.Server.Kitchen.EntitySystems { @@ -57,7 +57,7 @@ namespace Content.Server.Kitchen.EntitySystems SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); SubscribeLocalEvent(OnInteractUsing, after: new[] { typeof(AnchorableSystem) }); SubscribeLocalEvent(OnBreak); SubscribeLocalEvent(OnPowerChanged); @@ -76,21 +76,21 @@ namespace Content.Server.Kitchen.EntitySystems SubscribeLocalEvent(OnCookStop); } - private void OnCookStart(EntityUid uid, ActiveMicrowaveComponent component, ComponentStartup args) + private void OnCookStart(Entity ent, ref ComponentStartup args) { - if (!TryComp(uid, out var microwaveComponent)) + if (!TryComp(ent, out var microwaveComponent)) return; - SetAppearance(uid, MicrowaveVisualState.Cooking, microwaveComponent); + SetAppearance(ent.Owner, MicrowaveVisualState.Cooking, microwaveComponent); microwaveComponent.PlayingStream = - _audio.PlayPvs(microwaveComponent.LoopingSound, uid, AudioParams.Default.WithLoop(true).WithMaxDistance(5)).Value.Entity; + _audio.PlayPvs(microwaveComponent.LoopingSound, ent, AudioParams.Default.WithLoop(true).WithMaxDistance(5)).Value.Entity; } - private void OnCookStop(EntityUid uid, ActiveMicrowaveComponent component, ComponentShutdown args) + private void OnCookStop(Entity ent, ref ComponentShutdown args) { - if (!TryComp(uid, out var microwaveComponent)) + if (!TryComp(ent, out var microwaveComponent)) return; - SetAppearance(uid, MicrowaveVisualState.Idle, microwaveComponent); + SetAppearance(ent.Owner, MicrowaveVisualState.Idle, microwaveComponent); microwaveComponent.PlayingStream = _audio.Stop(microwaveComponent.PlayingStream); } @@ -111,12 +111,13 @@ namespace Content.Server.Kitchen.EntitySystems if (!TryComp(entity, out var solutions)) continue; - foreach (var (_, solution) in solutions.Solutions) + foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((entity, solutions))) { + var solution = soln.Comp.Solution; if (solution.Temperature > component.TemperatureUpperThreshold) continue; - _solutionContainer.AddThermalEnergy(entity, solution, heatToAdd); + _solutionContainer.AddThermalEnergy(soln, heatToAdd); } } } @@ -134,8 +135,9 @@ namespace Content.Server.Kitchen.EntitySystems continue; // go over every solution - foreach (var (_, solution) in solMan.Solutions) + foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan))) { + var solution = soln.Comp.Solution; foreach (var (reagent, _) in recipe.IngredientsReagents) { // removed everything @@ -154,7 +156,7 @@ namespace Content.Server.Kitchen.EntitySystems totalReagentsToRemove[reagent] -= quant; } - _solutionContainer.RemoveReagent(item, solution, reagent, quant); + _solutionContainer.RemoveReagent(soln, reagent, quant); } } } @@ -193,7 +195,7 @@ namespace Content.Server.Kitchen.EntitySystems _deviceLink.EnsureSinkPorts(ent, ent.Comp.OnPort); } - private void OnSuicide(EntityUid uid, MicrowaveComponent component, SuicideEvent args) + private void OnSuicide(Entity ent, ref SuicideEvent args) { if (args.Handled) return; @@ -208,7 +210,7 @@ namespace Content.Server.Kitchen.EntitySystems foreach (var part in headSlots) { - _container.Insert(part.Id, component.Storage); + _container.Insert(part.Id, ent.Comp.Storage); headCount++; } } @@ -224,73 +226,73 @@ namespace Content.Server.Kitchen.EntitySystems _popupSystem.PopupEntity(othersMessage, victim, Filter.PvsExcept(victim), true); _popupSystem.PopupEntity(selfMessage, victim, victim); - _audio.PlayPvs(component.ClickSound, uid, AudioParams.Default.WithVolume(-2)); - component.CurrentCookTimerTime = 10; - Wzhzhzh(uid, component, args.Victim); - UpdateUserInterfaceState(uid, component); + _audio.PlayPvs(ent.Comp.ClickSound, ent.Owner, AudioParams.Default.WithVolume(-2)); + ent.Comp.CurrentCookTimerTime = 10; + Wzhzhzh(ent.Owner, ent.Comp, args.Victim); + UpdateUserInterfaceState(ent.Owner, ent.Comp); } - private void OnSolutionChange(EntityUid uid, MicrowaveComponent component, SolutionChangedEvent args) + private void OnSolutionChange(Entity ent, ref SolutionContainerChangedEvent args) { - UpdateUserInterfaceState(uid, component); + UpdateUserInterfaceState(ent, ent.Comp); } - private void OnInteractUsing(EntityUid uid, MicrowaveComponent component, InteractUsingEvent args) + private void OnInteractUsing(Entity ent, ref InteractUsingEvent args) { if (args.Handled) return; - if (!(TryComp(uid, out var apc) && apc.Powered)) + if (!(TryComp(ent, out var apc) && apc.Powered)) { - _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-no-power"), uid, args.User); + _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-no-power"), ent, args.User); return; } - if (component.Broken) + if (ent.Comp.Broken) { - _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-broken"), uid, args.User); + _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-broken"), ent, args.User); return; } if (!HasComp(args.Used)) { - _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-transfer-fail"), uid, args.User); + _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-transfer-fail"), ent, args.User); return; } args.Handled = true; - _handsSystem.TryDropIntoContainer(args.User, args.Used, component.Storage); - UpdateUserInterfaceState(uid, component); + _handsSystem.TryDropIntoContainer(args.User, args.Used, ent.Comp.Storage); + UpdateUserInterfaceState(ent, ent.Comp); } - private void OnBreak(EntityUid uid, MicrowaveComponent component, BreakageEventArgs args) + private void OnBreak(Entity ent, ref BreakageEventArgs args) { - component.Broken = true; - SetAppearance(uid, MicrowaveVisualState.Broken, component); - RemComp(uid); - _sharedContainer.EmptyContainer(component.Storage); - UpdateUserInterfaceState(uid, component); + ent.Comp.Broken = true; + SetAppearance(ent, MicrowaveVisualState.Broken, ent.Comp); + RemComp(ent); + _sharedContainer.EmptyContainer(ent.Comp.Storage); + UpdateUserInterfaceState(ent, ent.Comp); } - private void OnPowerChanged(EntityUid uid, MicrowaveComponent component, ref PowerChangedEvent args) + private void OnPowerChanged(Entity ent, ref PowerChangedEvent args) { if (!args.Powered) { - SetAppearance(uid, MicrowaveVisualState.Idle, component); - RemComp(uid); - _sharedContainer.EmptyContainer(component.Storage); + SetAppearance(ent, MicrowaveVisualState.Idle, ent.Comp); + RemComp(ent); + _sharedContainer.EmptyContainer(ent.Comp.Storage); } - UpdateUserInterfaceState(uid, component); + UpdateUserInterfaceState(ent, ent.Comp); } - private void OnRefreshParts(EntityUid uid, MicrowaveComponent component, RefreshPartsEvent args) + private void OnRefreshParts(Entity ent, ref RefreshPartsEvent args) { - var cookRating = args.PartRatings[component.MachinePartCookTimeMultiplier]; - component.CookTimeMultiplier = MathF.Pow(component.CookTimeScalingConstant, cookRating - 1); + var cookRating = args.PartRatings[ent.Comp.MachinePartCookTimeMultiplier]; + ent.Comp.CookTimeMultiplier = MathF.Pow(ent.Comp.CookTimeScalingConstant, cookRating - 1); } - private void OnUpgradeExamine(EntityUid uid, MicrowaveComponent component, UpgradeExamineEvent args) + private void OnUpgradeExamine(Entity ent, ref UpgradeExamineEvent args) { - args.AddPercentageUpgrade("microwave-component-upgrade-cook-time", component.CookTimeMultiplier); + args.AddPercentageUpgrade("microwave-component-upgrade-cook-time", ent.Comp.CookTimeMultiplier); } private void OnSignalReceived(Entity ent, ref SignalReceivedEvent args) @@ -391,8 +393,9 @@ namespace Content.Server.Kitchen.EntitySystems if (!TryComp(item, out var solMan)) continue; - foreach (var (_, solution) in solMan.Solutions) + foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan))) { + var solution = soln.Comp.Solution; foreach (var (reagent, quantity) in solution.Contents) { if (reagentDict.ContainsKey(reagent.Prototype)) @@ -489,38 +492,38 @@ namespace Content.Server.Kitchen.EntitySystems } #region ui - private void OnEjectMessage(EntityUid uid, MicrowaveComponent component, MicrowaveEjectMessage args) + private void OnEjectMessage(Entity ent, ref MicrowaveEjectMessage args) { - if (!HasContents(component) || HasComp(uid)) + if (!HasContents(ent.Comp) || HasComp(ent)) return; - _sharedContainer.EmptyContainer(component.Storage); - _audio.PlayPvs(component.ClickSound, uid, AudioParams.Default.WithVolume(-2)); - UpdateUserInterfaceState(uid, component); + _sharedContainer.EmptyContainer(ent.Comp.Storage); + _audio.PlayPvs(ent.Comp.ClickSound, ent, AudioParams.Default.WithVolume(-2)); + UpdateUserInterfaceState(ent, ent.Comp); } - private void OnEjectIndex(EntityUid uid, MicrowaveComponent component, MicrowaveEjectSolidIndexedMessage args) + private void OnEjectIndex(Entity ent, ref MicrowaveEjectSolidIndexedMessage args) { - if (!HasContents(component) || HasComp(uid)) + if (!HasContents(ent.Comp) || HasComp(ent)) return; - _sharedContainer.Remove(EntityManager.GetEntity(args.EntityID), component.Storage); - UpdateUserInterfaceState(uid, component); + _sharedContainer.Remove(EntityManager.GetEntity(args.EntityID), ent.Comp.Storage); + UpdateUserInterfaceState(ent, ent.Comp); } - private void OnSelectTime(EntityUid uid, MicrowaveComponent comp, MicrowaveSelectCookTimeMessage args) + private void OnSelectTime(Entity ent, ref MicrowaveSelectCookTimeMessage args) { - if (!HasContents(comp) || HasComp(uid) || !(TryComp(uid, out var apc) && apc.Powered)) + if (!HasContents(ent.Comp) || HasComp(ent) || !(TryComp(ent, out var apc) && apc.Powered)) return; // some validation to prevent trollage - if (args.NewCookTime % 5 != 0 || args.NewCookTime > comp.MaxCookTime) + if (args.NewCookTime % 5 != 0 || args.NewCookTime > ent.Comp.MaxCookTime) return; - comp.CurrentCookTimeButtonIndex = args.ButtonIndex; - comp.CurrentCookTimerTime = args.NewCookTime; - _audio.PlayPvs(comp.ClickSound, uid, AudioParams.Default.WithVolume(-2)); - UpdateUserInterfaceState(uid, comp); + ent.Comp.CurrentCookTimeButtonIndex = args.ButtonIndex; + ent.Comp.CurrentCookTimerTime = args.NewCookTime; + _audio.PlayPvs(ent.Comp.ClickSound, ent, AudioParams.Default.WithVolume(-2)); + UpdateUserInterfaceState(ent, ent.Comp); } #endregion } diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs index ba6795ad9f..cd9a82a072 100644 --- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs @@ -1,11 +1,10 @@ -using System.Linq; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Construction; using Content.Server.Kitchen.Components; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Stack; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Containers.ItemSlots; using Content.Shared.FixedPoint; using Content.Shared.Interaction; @@ -19,6 +18,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Timing; +using System.Linq; namespace Content.Server.Kitchen.EntitySystems { @@ -26,7 +26,7 @@ namespace Content.Server.Kitchen.EntitySystems internal sealed class ReagentGrinderSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainersSystem = default!; [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; @@ -70,7 +70,7 @@ namespace Content.Server.Kitchen.EntitySystems var inputContainer = _containerSystem.EnsureContainer(uid, SharedReagentGrinder.InputContainerId); var outputContainer = _itemSlotsSystem.GetItemOrNull(uid, SharedReagentGrinder.BeakerSlotId); - if (outputContainer is null || !_solutionsSystem.TryGetFitsInDispenser(outputContainer.Value, out var containerSolution)) + if (outputContainer is null || !_solutionContainersSystem.TryGetFitsInDispenser(outputContainer.Value, out var containerSoln, out var containerSolution)) continue; foreach (var item in inputContainer.ContainedEntities.ToList()) @@ -108,7 +108,7 @@ namespace Content.Server.Kitchen.EntitySystems QueueDel(item); } - _solutionsSystem.TryAddSolution(outputContainer.Value, containerSolution, solution); + _solutionContainersSystem.TryAddSolution(containerSoln.Value, solution); } _userInterfaceSystem.TrySendUiMessage(uid, ReagentGrinderUiKey.Key, @@ -118,9 +118,9 @@ namespace Content.Server.Kitchen.EntitySystems } } - private void OnEntRemoveAttempt(EntityUid uid, ReagentGrinderComponent reagentGrinder, ContainerIsRemovingAttemptEvent args) + private void OnEntRemoveAttempt(Entity entity, ref ContainerIsRemovingAttemptEvent args) { - if (HasComp(uid)) + if (HasComp(entity)) args.Cancel(); } @@ -132,17 +132,17 @@ namespace Content.Server.Kitchen.EntitySystems _appearanceSystem.SetData(uid, ReagentGrinderVisualState.BeakerAttached, outputContainer.HasValue); } - private void OnInteractUsing(EntityUid uid, ReagentGrinderComponent reagentGrinder, InteractUsingEvent args) + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { var heldEnt = args.Used; - var inputContainer = _containerSystem.EnsureContainer(uid, SharedReagentGrinder.InputContainerId); + var inputContainer = _containerSystem.EnsureContainer(entity.Owner, SharedReagentGrinder.InputContainerId); if (!HasComp(heldEnt)) { if (!HasComp(heldEnt)) { // This is ugly but we can't use whitelistFailPopup because there are 2 containers with different whitelists. - _popupSystem.PopupEntity(Loc.GetString("reagent-grinder-component-cannot-put-entity-message"), uid, args.User); + _popupSystem.PopupEntity(Loc.GetString("reagent-grinder-component-cannot-put-entity-message"), entity.Owner, args.User); } // Entity did NOT pass the whitelist for grind/juice. @@ -156,7 +156,7 @@ namespace Content.Server.Kitchen.EntitySystems // Cap the chamber. Don't want someone putting in 500 entities and ejecting them all at once. // Maybe I should have done that for the microwave too? - if (inputContainer.ContainedEntities.Count >= reagentGrinder.StorageMaxEntities) + if (inputContainer.ContainedEntities.Count >= entity.Comp.StorageMaxEntities) return; if (!_containerSystem.Insert(heldEnt, inputContainer)) @@ -168,19 +168,19 @@ namespace Content.Server.Kitchen.EntitySystems /// /// Gotta be efficient, you know? you're saving a whole extra second here and everything. /// - private void OnRefreshParts(EntityUid uid, ReagentGrinderComponent component, RefreshPartsEvent args) + private void OnRefreshParts(Entity entity, ref RefreshPartsEvent args) { - var ratingWorkTime = args.PartRatings[component.MachinePartWorkTime]; - var ratingStorage = args.PartRatings[component.MachinePartStorageMax]; + var ratingWorkTime = args.PartRatings[entity.Comp.MachinePartWorkTime]; + var ratingStorage = args.PartRatings[entity.Comp.MachinePartStorageMax]; - component.WorkTimeMultiplier = MathF.Pow(component.PartRatingWorkTimerMulitplier, ratingWorkTime - 1); - component.StorageMaxEntities = component.BaseStorageMaxEntities + (int) (component.StoragePerPartRating * (ratingStorage - 1)); + entity.Comp.WorkTimeMultiplier = MathF.Pow(entity.Comp.PartRatingWorkTimerMulitplier, ratingWorkTime - 1); + entity.Comp.StorageMaxEntities = entity.Comp.BaseStorageMaxEntities + (int) (entity.Comp.StoragePerPartRating * (ratingStorage - 1)); } - private void OnUpgradeExamine(EntityUid uid, ReagentGrinderComponent component, UpgradeExamineEvent args) + private void OnUpgradeExamine(Entity entity, ref UpgradeExamineEvent args) { - args.AddPercentageUpgrade("reagent-grinder-component-upgrade-work-time", component.WorkTimeMultiplier); - args.AddNumberUpgrade("reagent-grinder-component-upgrade-storage", component.StorageMaxEntities - component.BaseStorageMaxEntities); + args.AddPercentageUpgrade("reagent-grinder-component-upgrade-work-time", entity.Comp.WorkTimeMultiplier); + args.AddNumberUpgrade("reagent-grinder-component-upgrade-storage", entity.Comp.StorageMaxEntities - entity.Comp.BaseStorageMaxEntities); } private void UpdateUiState(EntityUid uid) @@ -193,7 +193,7 @@ namespace Content.Server.Kitchen.EntitySystems var canGrind = false; if (outputContainer is not null - && _solutionsSystem.TryGetFitsInDispenser(outputContainer.Value, out containerSolution) + && _solutionContainersSystem.TryGetFitsInDispenser(outputContainer.Value, out _, out containerSolution) && inputContainer.ContainedEntities.Count > 0) { canGrind = inputContainer.ContainedEntities.All(CanGrind); @@ -212,43 +212,43 @@ namespace Content.Server.Kitchen.EntitySystems _userInterfaceSystem.TrySetUiState(uid, ReagentGrinderUiKey.Key, state); } - private void OnStartMessage(EntityUid uid, ReagentGrinderComponent reagentGrinder, ReagentGrinderStartMessage message) + private void OnStartMessage(Entity entity, ref ReagentGrinderStartMessage message) { - if (!this.IsPowered(uid, EntityManager) || HasComp(uid)) + if (!this.IsPowered(entity.Owner, EntityManager) || HasComp(entity)) return; - DoWork(uid, reagentGrinder, message.Program); + DoWork(entity.Owner, entity.Comp, message.Program); } - private void OnEjectChamberAllMessage(EntityUid uid, ReagentGrinderComponent reagentGrinder, ReagentGrinderEjectChamberAllMessage message) + private void OnEjectChamberAllMessage(Entity entity, ref ReagentGrinderEjectChamberAllMessage message) { - var inputContainer = _containerSystem.EnsureContainer(uid, SharedReagentGrinder.InputContainerId); + var inputContainer = _containerSystem.EnsureContainer(entity.Owner, SharedReagentGrinder.InputContainerId); - if (HasComp(uid) || inputContainer.ContainedEntities.Count <= 0) + if (HasComp(entity) || inputContainer.ContainedEntities.Count <= 0) return; - ClickSound(uid, reagentGrinder); - foreach (var entity in inputContainer.ContainedEntities.ToList()) + ClickSound(entity); + foreach (var toEject in inputContainer.ContainedEntities.ToList()) { - _containerSystem.Remove(entity, inputContainer); - _randomHelper.RandomOffset(entity, 0.4f); + _containerSystem.Remove(toEject, inputContainer); + _randomHelper.RandomOffset(toEject, 0.4f); } - UpdateUiState(uid); + UpdateUiState(entity); } - private void OnEjectChamberContentMessage(EntityUid uid, ReagentGrinderComponent reagentGrinder, ReagentGrinderEjectChamberContentMessage message) + private void OnEjectChamberContentMessage(Entity entity, ref ReagentGrinderEjectChamberContentMessage message) { - if (HasComp(uid)) + if (HasComp(entity)) return; - var inputContainer = _containerSystem.EnsureContainer(uid, SharedReagentGrinder.InputContainerId); + var inputContainer = _containerSystem.EnsureContainer(entity.Owner, SharedReagentGrinder.InputContainerId); var ent = GetEntity(message.EntityId); if (_containerSystem.Remove(ent, inputContainer)) { _randomHelper.RandomOffset(ent, 0.4f); - ClickSound(uid, reagentGrinder); - UpdateUiState(uid); + ClickSound(entity); + UpdateUiState(entity); } } @@ -290,16 +290,16 @@ namespace Content.Server.Kitchen.EntitySystems new ReagentGrinderWorkStartedMessage(program)); } - private void ClickSound(EntityUid uid, ReagentGrinderComponent reagentGrinder) + private void ClickSound(Entity reagentGrinder) { - _audioSystem.PlayPvs(reagentGrinder.ClickSound, uid, AudioParams.Default.WithVolume(-2f)); + _audioSystem.PlayPvs(reagentGrinder.Comp.ClickSound, reagentGrinder.Owner, AudioParams.Default.WithVolume(-2f)); } private Solution? GetGrindSolution(EntityUid uid) { if (TryComp(uid, out var extractable) && extractable.GrindableSolution is not null - && _solutionsSystem.TryGetSolution(uid, extractable.GrindableSolution, out var solution)) + && _solutionContainersSystem.TryGetSolution(uid, extractable.GrindableSolution, out _, out var solution)) { return solution; } @@ -311,7 +311,7 @@ namespace Content.Server.Kitchen.EntitySystems { var solutionName = CompOrNull(uid)?.GrindableSolution; - return solutionName is not null && _solutionsSystem.TryGetSolution(uid, solutionName, out _); + return solutionName is not null && _solutionContainersSystem.TryGetSolution(uid, solutionName, out _, out _); } private bool CanJuice(EntityUid uid) diff --git a/Content.Server/Lube/LubeSystem.cs b/Content.Server/Lube/LubeSystem.cs index 86921d222c..d777ae9406 100644 --- a/Content.Server/Lube/LubeSystem.cs +++ b/Content.Server/Lube/LubeSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Administration.Logs; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.EntitySystems; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; @@ -28,7 +28,7 @@ public sealed class LubeSystem : EntitySystem SubscribeLocalEvent(OnInteract, after: new[] { typeof(OpenableSystem) }); } - private void OnInteract(EntityUid uid, LubeComponent component, AfterInteractEvent args) + private void OnInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled) return; @@ -36,10 +36,10 @@ public sealed class LubeSystem : EntitySystem if (!args.CanReach || args.Target is not { Valid: true } target) return; - if (TryLube(uid, component, target, args.User)) + if (TryLube(entity, target, args.User)) { args.Handled = true; - _audio.PlayPvs(component.Squeeze, uid); + _audio.PlayPvs(entity.Comp.Squeeze, entity); _popup.PopupEntity(Loc.GetString("lube-success", ("target", Identity.Entity(target, EntityManager))), args.User, args.User, PopupType.Medium); } else @@ -48,22 +48,22 @@ public sealed class LubeSystem : EntitySystem } } - private bool TryLube(EntityUid uid, LubeComponent component, EntityUid target, EntityUid actor) + private bool TryLube(Entity lube, EntityUid target, EntityUid actor) { if (HasComp(target) || !HasComp(target)) { return false; } - if (HasComp(target) && _solutionContainer.TryGetSolution(uid, component.Solution, out var solution)) + if (HasComp(target) && _solutionContainer.TryGetSolution(lube.Owner, lube.Comp.Solution, out _, out var solution)) { - var quantity = solution.RemoveReagent(component.Reagent, component.Consumption); + var quantity = solution.RemoveReagent(lube.Comp.Reagent, lube.Comp.Consumption); if (quantity > 0) { var lubed = EnsureComp(target); - lubed.SlipsLeft = _random.Next(component.MinSlips * quantity.Int(), component.MaxSlips * quantity.Int()); - lubed.SlipStrength = component.SlipStrength; - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} lubed {ToPrettyString(target):subject} with {ToPrettyString(uid):tool}"); + lubed.SlipsLeft = _random.Next(lube.Comp.MinSlips * quantity.Int(), lube.Comp.MaxSlips * quantity.Int()); + lubed.SlipStrength = lube.Comp.SlipStrength; + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} lubed {ToPrettyString(target):subject} with {ToPrettyString(lube.Owner):tool}"); return true; } } diff --git a/Content.Server/Materials/MaterialReclaimerSystem.cs b/Content.Server/Materials/MaterialReclaimerSystem.cs index d6a94ec6d2..ff05a72ef0 100644 --- a/Content.Server/Materials/MaterialReclaimerSystem.cs +++ b/Content.Server/Materials/MaterialReclaimerSystem.cs @@ -1,4 +1,4 @@ -using System.Linq; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Chemistry.EntitySystems; using Content.Server.Construction; using Content.Server.Fluids.EntitySystems; @@ -11,7 +11,6 @@ using Content.Server.Wires; using Content.Shared.Body.Systems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; @@ -20,6 +19,7 @@ using Content.Shared.Mind; using Robust.Server.GameObjects; using Robust.Shared.Player; using Robust.Shared.Utility; +using System.Linq; namespace Content.Server.Materials; @@ -51,40 +51,40 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem SubscribeLocalEvent(OnSuicide); SubscribeLocalEvent(OnActivePowerChanged); } - private void OnStartup(EntityUid uid, MaterialReclaimerComponent component, ComponentStartup args) + private void OnStartup(Entity entity, ref ComponentStartup args) { - component.OutputSolution = _solutionContainer.EnsureSolution(uid, component.SolutionContainerId); + _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.SolutionContainerId); } - private void OnUpgradeExamine(EntityUid uid, MaterialReclaimerComponent component, UpgradeExamineEvent args) + private void OnUpgradeExamine(Entity entity, ref UpgradeExamineEvent args) { - args.AddPercentageUpgrade(Loc.GetString("material-reclaimer-upgrade-process-rate"), component.MaterialProcessRate / component.BaseMaterialProcessRate); + args.AddPercentageUpgrade(Loc.GetString("material-reclaimer-upgrade-process-rate"), entity.Comp.MaterialProcessRate / entity.Comp.BaseMaterialProcessRate); } - private void OnRefreshParts(EntityUid uid, MaterialReclaimerComponent component, RefreshPartsEvent args) + private void OnRefreshParts(Entity entity, ref RefreshPartsEvent args) { - var rating = args.PartRatings[component.MachinePartProcessRate] - 1; - component.MaterialProcessRate = component.BaseMaterialProcessRate * MathF.Pow(component.PartRatingProcessRateMultiplier, rating); - Dirty(component); + var rating = args.PartRatings[entity.Comp.MachinePartProcessRate] - 1; + entity.Comp.MaterialProcessRate = entity.Comp.BaseMaterialProcessRate * MathF.Pow(entity.Comp.PartRatingProcessRateMultiplier, rating); + Dirty(entity); } - private void OnPowerChanged(EntityUid uid, MaterialReclaimerComponent component, ref PowerChangedEvent args) + private void OnPowerChanged(Entity entity, ref PowerChangedEvent args) { - AmbientSound.SetAmbience(uid, component.Enabled && args.Powered); - component.Powered = args.Powered; - Dirty(component); + AmbientSound.SetAmbience(entity.Owner, entity.Comp.Enabled && args.Powered); + entity.Comp.Powered = args.Powered; + Dirty(entity); } - private void OnInteractUsing(EntityUid uid, MaterialReclaimerComponent component, InteractUsingEvent args) + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { if (args.Handled) return; // if we're trying to get a solution out of the reclaimer, don't destroy it - if (component.OutputSolution.Contents.Any()) + if (_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.SolutionContainerId, out _, out var outputSolution) && outputSolution.Contents.Any()) { if (TryComp(args.Used, out var managerComponent) && - managerComponent.Solutions.Any(s => s.Value.AvailableVolume > 0)) + _solutionContainer.EnumerateSolutions((args.Used, managerComponent)).Any(s => s.Solution.Comp.Solution.AvailableVolume > 0)) { if (_openable.IsClosed(args.Used)) return; @@ -95,10 +95,10 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem } } - args.Handled = TryStartProcessItem(uid, args.Used, component, args.User); + args.Handled = TryStartProcessItem(entity.Owner, args.Used, entity.Comp, args.User); } - private void OnSuicide(EntityUid uid, MaterialReclaimerComponent component, SuicideEvent args) + private void OnSuicide(Entity entity, ref SuicideEvent args) { if (args.Handled) return; @@ -109,9 +109,9 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem _mind.TryGetMind(actor.PlayerSession, out var mindId, out var mind)) { _ticker.OnGhostAttempt(mindId, false, mind: mind); - if (mind.OwnedEntity is { Valid: true } entity) + if (mind.OwnedEntity is { Valid: true } suicider) { - _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message"), entity); + _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message"), suicider); } } @@ -120,13 +120,13 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem Filter.PvsExcept(victim, entityManager: EntityManager), true); _body.GibBody(victim, true); - _appearance.SetData(uid, RecyclerVisuals.Bloody, true); + _appearance.SetData(entity.Owner, RecyclerVisuals.Bloody, true); } - private void OnActivePowerChanged(EntityUid uid, ActiveMaterialReclaimerComponent component, ref PowerChangedEvent args) + private void OnActivePowerChanged(Entity entity, ref PowerChangedEvent args) { if (!args.Powered) - TryFinishProcessItem(uid, null, component); + TryFinishProcessItem(entity, null, entity.Comp); } /// @@ -224,6 +224,8 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem { if (!Resolve(reclaimer, ref reclaimerComponent, ref xform)) return; + if (!_solutionContainer.TryGetSolution(reclaimer, reclaimerComponent.SolutionContainerId, out var outputSolution)) + return; efficiency *= reclaimerComponent.Efficiency; @@ -241,8 +243,9 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem // if the item we inserted has reagents, add it in. if (TryComp(item, out var solutionContainer)) { - foreach (var solution in solutionContainer.Solutions.Values) + foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solutionContainer))) { + var solution = soln.Comp.Solution; foreach (var quantity in solution.Contents) { totalChemicals.AddReagent(quantity.Reagent.Prototype, quantity.Quantity * efficiency, false); @@ -250,7 +253,7 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem } } - _solutionContainer.TryTransferSolution(reclaimer, reclaimerComponent.OutputSolution, totalChemicals, totalChemicals.Volume); + _solutionContainer.TryTransferSolution(outputSolution.Value, totalChemicals, totalChemicals.Volume); if (totalChemicals.Volume > 0) { _puddle.TrySpillAt(reclaimer, totalChemicals, out _, sound, transformComponent: xform); diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs index b083c480f6..19cb62f836 100644 --- a/Content.Server/Medical/CryoPodSystem.cs +++ b/Content.Server/Medical/CryoPodSystem.cs @@ -5,6 +5,7 @@ using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Unary.EntitySystems; using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Medical.Components; using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; @@ -16,7 +17,6 @@ using Content.Server.UserInterface; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Climbing.Systems; using Content.Shared.Containers.ItemSlots; @@ -28,7 +28,6 @@ using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Medical.Cryogenics; using Content.Shared.MedicalScanner; -using Content.Shared.Tools; using Content.Shared.Verbs; using Robust.Server.GameObjects; using Robust.Shared.Timing; @@ -36,7 +35,7 @@ using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; namespace Content.Server.Medical; -public sealed partial class CryoPodSystem: SharedCryoPodSystem +public sealed partial class CryoPodSystem : SharedCryoPodSystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly GasCanisterSystem _gasCanisterSystem = default!; @@ -105,14 +104,15 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem && fitsInDispenserQuery.TryGetComponent(container, out var fitsInDispenserComponent) && solutionContainerManagerQuery.TryGetComponent(container, out var solutionContainerManagerComponent) - && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution, dispenserFits: fitsInDispenserComponent, solutionManager: solutionContainerManagerComponent)) + && _solutionContainerSystem.TryGetFitsInDispenser((container.Value, fitsInDispenserComponent, solutionContainerManagerComponent), + out var containerSolution, out _)) { if (!bloodStreamQuery.TryGetComponent(patient, out var bloodstream)) { continue; } - var solutionToInject = _solutionContainerSystem.SplitSolution(container.Value, containerSolution, cryoPod.BeakerTransferAmount); + var solutionToInject = _solutionContainerSystem.SplitSolution(containerSolution.Value, cryoPod.BeakerTransferAmount); _bloodstreamSystem.TryAddToChemicals(patient.Value, solutionToInject, bloodstream); _reactiveSystem.DoEntityReaction(patient.Value, solutionToInject, ReactionMethod.Injection); } @@ -123,7 +123,7 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem { if (!Resolve(uid, ref cryoPodComponent)) return null; - if (cryoPodComponent.BodyContainer.ContainedEntity is not {Valid: true} contained) + if (cryoPodComponent.BodyContainer.ContainedEntity is not { Valid: true } contained) return null; base.EjectBody(uid, cryoPodComponent); _climbSystem.ForciblySetClimbing(contained, uid); @@ -132,12 +132,12 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem #region Interaction - private void HandleDragDropOn(EntityUid uid, CryoPodComponent cryoPodComponent, ref DragDropTargetEvent args) + private void HandleDragDropOn(Entity entity, ref DragDropTargetEvent args) { - if (cryoPodComponent.BodyContainer.ContainedEntity != null) + if (entity.Comp.BodyContainer.ContainedEntity != null) return; - var doAfterArgs = new DoAfterArgs(EntityManager, args.User, cryoPodComponent.EntryDelay, new CryoPodDragFinished(), uid, target: args.Dragged, used: uid) + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.EntryDelay, new CryoPodDragFinished(), entity, target: args.Dragged, used: entity) { BreakOnDamage = true, BreakOnTargetMove = true, @@ -148,61 +148,65 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem args.Handled = true; } - private void OnDragFinished(EntityUid uid, CryoPodComponent component, CryoPodDragFinished args) + private void OnDragFinished(Entity entity, ref CryoPodDragFinished args) { if (args.Cancelled || args.Handled || args.Args.Target == null) return; - if (InsertBody(uid, args.Args.Target.Value, component)) + if (InsertBody(entity.Owner, args.Args.Target.Value, entity.Comp)) { - if (!TryComp(uid, out CryoPodAirComponent? cryoPodAir)) + if (!TryComp(entity.Owner, out CryoPodAirComponent? cryoPodAir)) _adminLogger.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(uid)}"); + $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(entity.Owner)}"); _adminLogger.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(uid)} which contains gas: {cryoPodAir!.Air.ToPrettyString():gasMix}"); + $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(entity.Owner)} which contains gas: {cryoPodAir!.Air.ToPrettyString():gasMix}"); } args.Handled = true; } - private void OnActivateUIAttempt(EntityUid uid, CryoPodComponent cryoPodComponent, ActivatableUIOpenAttemptEvent args) + private void OnActivateUIAttempt(Entity entity, ref ActivatableUIOpenAttemptEvent args) { if (args.Cancelled) { return; } - var containedEntity = cryoPodComponent.BodyContainer.ContainedEntity; - if (containedEntity == null || containedEntity == args.User || !HasComp(uid)) + var containedEntity = entity.Comp.BodyContainer.ContainedEntity; + if (containedEntity == null || containedEntity == args.User || !HasComp(entity)) { args.Cancel(); } } - private void OnActivateUI(EntityUid uid, CryoPodComponent cryoPodComponent, AfterActivatableUIOpenEvent args) + private void OnActivateUI(Entity entity, ref AfterActivatableUIOpenEvent args) { - TryComp(cryoPodComponent.BodyContainer.ContainedEntity, out var temp); - TryComp(cryoPodComponent.BodyContainer.ContainedEntity, out var bloodstream); + TryComp(entity.Comp.BodyContainer.ContainedEntity, out var temp); + TryComp(entity.Comp.BodyContainer.ContainedEntity, out var bloodstream); _userInterfaceSystem.TrySendUiMessage( - uid, + entity.Owner, HealthAnalyzerUiKey.Key, - new HealthAnalyzerScannedUserMessage(GetNetEntity(cryoPodComponent.BodyContainer.ContainedEntity), - temp?.CurrentTemperature ?? 0, bloodstream != null ? bloodstream.BloodSolution.FillFraction : 0)); + new HealthAnalyzerScannedUserMessage(GetNetEntity(entity.Comp.BodyContainer.ContainedEntity), + temp?.CurrentTemperature ?? 0, + (bloodstream != null && _solutionContainerSystem.ResolveSolution(entity.Owner, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)) + ? bloodSolution.FillFraction + : 0 + )); } - private void OnInteractUsing(EntityUid uid, CryoPodComponent cryoPodComponent, InteractUsingEvent args) + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { - if (args.Handled || !cryoPodComponent.Locked || cryoPodComponent.BodyContainer.ContainedEntity == null) + if (args.Handled || !entity.Comp.Locked || entity.Comp.BodyContainer.ContainedEntity == null) return; - args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, cryoPodComponent.PryDelay, "Prying", new CryoPodPryFinished()); + args.Handled = _toolSystem.UseTool(args.Used, args.User, entity.Owner, entity.Comp.PryDelay, "Prying", new CryoPodPryFinished()); } - private void OnExamined(EntityUid uid, CryoPodComponent component, ExaminedEvent args) + private void OnExamined(Entity entity, ref ExaminedEvent args) { - var container = _itemSlotsSystem.GetItemOrNull(uid, component.SolutionContainerName); - if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution)) + var container = _itemSlotsSystem.GetItemOrNull(entity.Owner, entity.Comp.SolutionContainerName); + if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var containerSolution)) { args.PushMarkup(Loc.GetString("cryo-pod-examine", ("beaker", Name(container.Value)))); if (containerSolution.Volume == 0) @@ -212,64 +216,63 @@ public sealed partial class CryoPodSystem: SharedCryoPodSystem } } - private void OnPowerChanged(EntityUid uid, CryoPodComponent component, ref PowerChangedEvent args) + private void OnPowerChanged(Entity entity, ref PowerChangedEvent args) { // Needed to avoid adding/removing components on a deleted entity - if (Terminating(uid)) + if (Terminating(entity)) { return; } if (args.Powered) { - EnsureComp(uid); + EnsureComp(entity); } else { - RemComp(uid); - _uiSystem.TryCloseAll(uid, HealthAnalyzerUiKey.Key); + RemComp(entity); + _uiSystem.TryCloseAll(entity.Owner, HealthAnalyzerUiKey.Key); } - UpdateAppearance(uid, component); + UpdateAppearance(entity.Owner, entity.Comp); } #endregion #region Atmos handler - private void OnCryoPodUpdateAtmosphere(EntityUid uid, CryoPodComponent cryoPod, ref AtmosDeviceUpdateEvent args) + private void OnCryoPodUpdateAtmosphere(Entity entity, ref AtmosDeviceUpdateEvent args) { - if (!TryComp(uid, out NodeContainerComponent? nodeContainer)) + if (!TryComp(entity, out NodeContainerComponent? nodeContainer)) return; - if (!_nodeContainer.TryGetNode(nodeContainer, cryoPod.PortName, out PortablePipeNode? portNode)) + if (!_nodeContainer.TryGetNode(nodeContainer, entity.Comp.PortName, out PortablePipeNode? portNode)) return; - if (!TryComp(uid, out CryoPodAirComponent? cryoPodAir)) + if (!TryComp(entity, out CryoPodAirComponent? cryoPodAir)) return; _atmosphereSystem.React(cryoPodAir.Air, portNode); - if (portNode.NodeGroup is PipeNet {NodeCount: > 1} net) + if (portNode.NodeGroup is PipeNet { NodeCount: > 1 } net) { _gasCanisterSystem.MixContainerWithPipeNet(cryoPodAir.Air, net.Air); } } - private void OnGasAnalyzed(EntityUid uid, CryoPodComponent component, GasAnalyzerScanEvent args) + private void OnGasAnalyzed(Entity entity, ref GasAnalyzerScanEvent args) { - if (!TryComp(uid, out CryoPodAirComponent? cryoPodAir)) + if (!TryComp(entity, out CryoPodAirComponent? cryoPodAir)) return; - var gasMixDict = new Dictionary { { Name(uid), cryoPodAir.Air } }; + var gasMixDict = new Dictionary { { Name(entity.Owner), cryoPodAir.Air } }; // If it's connected to a port, include the port side - if (TryComp(uid, out NodeContainerComponent? nodeContainer)) + if (TryComp(entity, out NodeContainerComponent? nodeContainer)) { - if (_nodeContainer.TryGetNode(nodeContainer, component.PortName, out PipeNode? port)) - gasMixDict.Add(component.PortName, port.Air); + if (_nodeContainer.TryGetNode(nodeContainer, entity.Comp.PortName, out PipeNode? port)) + gasMixDict.Add(entity.Comp.PortName, port.Air); } args.GasMixtures = gasMixDict; } - #endregion } diff --git a/Content.Server/Medical/HealingSystem.cs b/Content.Server/Medical/HealingSystem.cs index 57f66f2378..38f14ea9db 100644 --- a/Content.Server/Medical/HealingSystem.cs +++ b/Content.Server/Medical/HealingSystem.cs @@ -1,7 +1,9 @@ using Content.Server.Administration.Logs; using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Medical.Components; +using Content.Server.Popups; using Content.Server.Stack; using Content.Shared.Audio; using Content.Shared.Damage; @@ -15,8 +17,6 @@ using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Stacks; -using Content.Server.Popups; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Random; @@ -34,6 +34,7 @@ public sealed class HealingSystem : EntitySystem [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; public override void Initialize() { @@ -43,7 +44,7 @@ public sealed class HealingSystem : EntitySystem SubscribeLocalEvent(OnDoAfter); } - private void OnDoAfter(EntityUid uid, DamageableComponent component, HealingDoAfterEvent args) + private void OnDoAfter(Entity entity, ref HealingDoAfterEvent args) { var dontRepeat = false; @@ -54,8 +55,8 @@ public sealed class HealingSystem : EntitySystem return; if (healing.DamageContainers is not null && - component.DamageContainerID is not null && - !healing.DamageContainers.Contains(component.DamageContainerID)) + entity.Comp.DamageContainerID is not null && + !healing.DamageContainers.Contains(entity.Comp.DamageContainerID)) { return; } @@ -63,22 +64,22 @@ public sealed class HealingSystem : EntitySystem // Heal some bloodloss damage. if (healing.BloodlossModifier != 0) { - if (!TryComp(uid, out var bloodstream)) + if (!TryComp(entity, out var bloodstream)) return; var isBleeding = bloodstream.BleedAmount > 0; - _bloodstreamSystem.TryModifyBleedAmount(uid, healing.BloodlossModifier); + _bloodstreamSystem.TryModifyBleedAmount(entity.Owner, healing.BloodlossModifier); if (isBleeding != bloodstream.BleedAmount > 0) { dontRepeat = true; - _popupSystem.PopupEntity(Loc.GetString("medical-item-stop-bleeding"), uid, args.User); + _popupSystem.PopupEntity(Loc.GetString("medical-item-stop-bleeding"), entity, args.User); } } // Restores missing blood if (healing.ModifyBloodLevel != 0) - _bloodstreamSystem.TryModifyBloodLevel(uid, healing.ModifyBloodLevel); + _bloodstreamSystem.TryModifyBloodLevel(entity.Owner, healing.ModifyBloodLevel); - var healed = _damageable.TryChangeDamage(uid, healing.Damage, true, origin: args.Args.User); + var healed = _damageable.TryChangeDamage(entity.Owner, healing.Damage, true, origin: args.Args.User); if (healed == null && healing.BloodlossModifier != 0) return; @@ -99,10 +100,10 @@ public sealed class HealingSystem : EntitySystem QueueDel(args.Used.Value); } - if (uid != args.User) + if (entity.Owner != args.User) { _adminLogger.Add(LogType.Healed, - $"{EntityManager.ToPrettyString(args.User):user} healed {EntityManager.ToPrettyString(uid):target} for {total:damage} damage"); + $"{EntityManager.ToPrettyString(args.User):user} healed {EntityManager.ToPrettyString(entity.Owner):target} for {total:damage} damage"); } else { @@ -110,12 +111,12 @@ public sealed class HealingSystem : EntitySystem $"{EntityManager.ToPrettyString(args.User):user} healed themselves for {total:damage} damage"); } - _audio.PlayPvs(healing.HealingEndSound, uid, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f)); + _audio.PlayPvs(healing.HealingEndSound, entity.Owner, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f)); // Logic to determine the whether or not to repeat the healing action - args.Repeat = (HasDamage(component, healing) && !dontRepeat); + args.Repeat = (HasDamage(entity.Comp, healing) && !dontRepeat); if (!args.Repeat && !dontRepeat) - _popupSystem.PopupEntity(Loc.GetString("medical-item-finished-using", ("item", args.Used)), uid, args.User); + _popupSystem.PopupEntity(Loc.GetString("medical-item-finished-using", ("item", args.Used)), entity.Owner, args.User); args.Handled = true; } @@ -134,21 +135,21 @@ public sealed class HealingSystem : EntitySystem return false; } - private void OnHealingUse(EntityUid uid, HealingComponent component, UseInHandEvent args) + private void OnHealingUse(Entity entity, ref UseInHandEvent args) { if (args.Handled) return; - if (TryHeal(uid, args.User, args.User, component)) + if (TryHeal(entity, args.User, args.User, entity.Comp)) args.Handled = true; } - private void OnHealingAfterInteract(EntityUid uid, HealingComponent component, AfterInteractEvent args) + private void OnHealingAfterInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled || !args.CanReach || args.Target == null) return; - if (TryHeal(uid, args.User, args.Target.Value, component)) + if (TryHeal(entity, args.User, args.Target.Value, entity.Comp)) args.Handled = true; } @@ -170,10 +171,14 @@ public sealed class HealingSystem : EntitySystem if (TryComp(uid, out var stack) && stack.Count < 1) return false; - if (!TryComp(target, out var bloodstream)) - return false; + var anythingToDo = + HasDamage(targetDamage, component) || + component.ModifyBloodLevel > 0 // Special case if healing item can restore lost blood... + && TryComp(target, out var bloodstream) + && _solutionContainerSystem.ResolveSolution(target, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution) + && bloodSolution.Volume < bloodSolution.MaxVolume; // ...and there is lost blood to restore. - if (!HasDamage(targetDamage, component) && !(bloodstream.BloodSolution.Volume < bloodstream.BloodSolution.MaxVolume && component.ModifyBloodLevel > 0)) + if (!anythingToDo) { _popupSystem.PopupEntity(Loc.GetString("medical-item-cant-use", ("item", uid)), uid, user); return false; diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index fe3944b21e..d9559a9626 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -1,14 +1,14 @@ +using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Medical.Components; using Content.Server.PowerCell; +using Content.Server.Temperature.Components; using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.Interaction; using Content.Shared.MedicalScanner; using Content.Shared.Mobs.Components; using Robust.Server.GameObjects; -using Content.Server.Temperature.Components; -using Content.Server.Body.Components; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Player; @@ -19,6 +19,7 @@ namespace Content.Server.Medical [Dependency] private readonly PowerCellSystem _cell = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; public override void Initialize() @@ -28,14 +29,14 @@ namespace Content.Server.Medical SubscribeLocalEvent(OnDoAfter); } - private void OnAfterInteract(EntityUid uid, HealthAnalyzerComponent healthAnalyzer, AfterInteractEvent args) + private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { - if (args.Target == null || !args.CanReach || !HasComp(args.Target) || !_cell.HasActivatableCharge(uid, user: args.User)) + if (args.Target == null || !args.CanReach || !HasComp(args.Target) || !_cell.HasActivatableCharge(entity.Owner, user: args.User)) return; - _audio.PlayPvs(healthAnalyzer.ScanningBeginSound, uid); + _audio.PlayPvs(entity.Comp.ScanningBeginSound, entity); - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, healthAnalyzer.ScanDelay, new HealthAnalyzerDoAfterEvent(), uid, target: args.Target, used: uid) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, TimeSpan.FromSeconds(entity.Comp.ScanDelay), new HealthAnalyzerDoAfterEvent(), entity.Owner, target: args.Target, used: entity.Owner) { BreakOnTargetMove = true, BreakOnUserMove = true, @@ -43,14 +44,14 @@ namespace Content.Server.Medical }); } - private void OnDoAfter(EntityUid uid, HealthAnalyzerComponent component, DoAfterEvent args) + private void OnDoAfter(Entity entity, ref HealthAnalyzerDoAfterEvent args) { - if (args.Handled || args.Cancelled || args.Args.Target == null || !_cell.TryUseActivatableCharge(uid, user: args.User)) + if (args.Handled || args.Cancelled || args.Target == null || !_cell.TryUseActivatableCharge(entity.Owner, user: args.User)) return; - _audio.PlayPvs(component.ScanningEndSound, args.Args.User); + _audio.PlayPvs(entity.Comp.ScanningEndSound, args.User); - UpdateScannedUser(uid, args.Args.User, args.Args.Target.Value, component); + UpdateScannedUser(entity, args.User, args.Target.Value, entity.Comp); args.Handled = true; } @@ -73,13 +74,26 @@ namespace Content.Server.Medical if (!HasComp(target)) return; - TryComp(target, out var temp); - TryComp(target, out var bloodstream); + float bodyTemperature; + if (TryComp(target, out var temp)) + bodyTemperature = temp.CurrentTemperature; + else + bodyTemperature = float.NaN; + + float bloodAmount; + if (TryComp(target, out var bloodstream) && + _solutionContainerSystem.ResolveSolution(target.Value, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)) + bloodAmount = bloodSolution.FillFraction; + else + bloodAmount = float.NaN; OpenUserInterface(user, uid); - _uiSystem.SendUiMessage(ui, new HealthAnalyzerScannedUserMessage(GetNetEntity(target), temp != null ? temp.CurrentTemperature : float.NaN, - bloodstream != null ? bloodstream.BloodSolution.FillFraction : float.NaN)); + _uiSystem.SendUiMessage(ui, new HealthAnalyzerScannedUserMessage( + GetNetEntity(target), + bodyTemperature, + bloodAmount + )); } } } diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index fedb6d2357..8c3b15aed3 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -1,17 +1,16 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Forensics; using Content.Server.Popups; using Content.Server.Stunnable; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.IdentityManagement; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.StatusEffect; using Robust.Server.Audio; -using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Prototypes; @@ -59,29 +58,32 @@ namespace Content.Server.Medical // Empty the stomach out into it foreach (var stomach in stomachList) { - if (_solutionContainer.TryGetSolution(stomach.Comp.Owner, StomachSystem.DefaultSolutionName, - out var sol)) + if (_solutionContainer.ResolveSolution(stomach.Comp.Owner, StomachSystem.DefaultSolutionName, ref stomach.Comp.Solution, out var sol)) { solution.AddSolution(sol, _proto); sol.RemoveAllSolution(); - _solutionContainer.UpdateChemicals(stomach.Comp.Owner, sol); + _solutionContainer.UpdateChemicals(stomach.Comp.Solution.Value); } } // Adds a tiny amount of the chem stream from earlier along with vomit if (TryComp(uid, out var bloodStream)) { - var chemMultiplier = 0.1; - var vomitMultiplier = 0.9; + const float chemMultiplier = 0.1f; - // Makes a vomit solution the size of 90% of the chemicals removed from the chemstream - var vomitAmount = new Solution("Vomit", solutionSize * vomitMultiplier); + var vomitAmount = solutionSize; // Takes 10% of the chemicals removed from the chem stream - var vomitChemstreamAmount = _solutionContainer.SplitSolution(uid, bloodStream.ChemicalSolution, solutionSize * chemMultiplier); + if (_solutionContainer.ResolveSolution(uid, bloodStream.ChemicalSolutionName, ref bloodStream.ChemicalSolution)) + { + var vomitChemstreamAmount = _solutionContainer.SplitSolution(bloodStream.ChemicalSolution.Value, vomitAmount); + vomitChemstreamAmount.ScaleSolution(chemMultiplier); + solution.AddSolution(vomitChemstreamAmount, _proto); - _solutionContainer.SplitSolution(uid, bloodStream.ChemicalSolution, solutionSize * vomitMultiplier); - solution.AddSolution(vomitAmount, _proto); - solution.AddSolution(vomitChemstreamAmount, _proto); + vomitAmount -= (float) vomitChemstreamAmount.Volume; + } + + // Makes a vomit solution the size of 90% of the chemicals removed from the chemstream + solution.AddReagent("Vomit", vomitAmount); // TODO: Dehardcode vomit prototype } if (_puddle.TrySpillAt(uid, solution, out var puddle, false)) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs index 7b66cff1f8..01cfbd113d 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs @@ -1,15 +1,13 @@ using Content.Server.Chat.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.NPC.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.Emag.Components; using Content.Shared.Interaction; using Content.Shared.Mobs.Components; using Content.Shared.Popups; using Content.Shared.Silicons.Bots; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific; @@ -21,7 +19,7 @@ public sealed partial class MedibotInjectOperator : HTNOperator private SharedAudioSystem _audio = default!; private SharedInteractionSystem _interaction = default!; private SharedPopupSystem _popup = default!; - private SolutionContainerSystem _solution = default!; + private SolutionContainerSystem _solutionContainer = default!; /// /// Target entity to inject. @@ -37,7 +35,7 @@ public sealed partial class MedibotInjectOperator : HTNOperator _audio = sysManager.GetEntitySystem(); _interaction = sysManager.GetEntitySystem(); _popup = sysManager.GetEntitySystem(); - _solution = sysManager.GetEntitySystem(); + _solutionContainer = sysManager.GetEntitySystem(); } public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status) @@ -61,7 +59,7 @@ public sealed partial class MedibotInjectOperator : HTNOperator if (!_entMan.TryGetComponent(target, out var damage)) return HTNOperatorStatus.Failed; - if (!_solution.TryGetInjectableSolution(target, out var injectable)) + if (!_solutionContainer.TryGetInjectableSolution(target, out var injectable, out _)) return HTNOperatorStatus.Failed; if (!_interaction.InRangeUnobstructed(owner, target)) @@ -81,7 +79,7 @@ public sealed partial class MedibotInjectOperator : HTNOperator return HTNOperatorStatus.Failed; _entMan.EnsureComponent(target); - _solution.TryAddReagent(target, injectable, treatment.Reagent, treatment.Quantity, out _); + _solutionContainer.TryAddReagent(injectable.Value, treatment.Reagent, treatment.Quantity, out _); _popup.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, target); _audio.PlayPvs(botComp.InjectSound, target); _chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, hideChat: true, hideLog: true); diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs index 641b8c20e1..76d0ebe83a 100644 --- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs +++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs @@ -1,4 +1,4 @@ -using System.Linq; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.NPC.Queries; using Content.Server.NPC.Queries.Considerations; @@ -7,7 +7,6 @@ using Content.Server.NPC.Queries.Queries; using Content.Server.Nutrition.Components; using Content.Server.Nutrition.EntitySystems; using Content.Server.Storage.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Examine; using Content.Shared.Fluids.Components; using Content.Shared.Hands.Components; @@ -20,9 +19,9 @@ using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; using Microsoft.Extensions.ObjectPool; using Robust.Server.Containers; -using Robust.Shared.Collections; using Robust.Shared.Prototypes; using Robust.Shared.Utility; +using System.Linq; namespace Content.Server.NPC.Systems; @@ -492,7 +491,7 @@ public sealed class NPCUtilitySystem : EntitySystem foreach (var ent in entities) { if (!_puddleQuery.TryGetComponent(ent, out var puddleComp) || - !_solutions.TryGetSolution(ent, puddleComp.SolutionName, out var sol) || + !_solutions.TryGetSolution(ent, puddleComp.SolutionName, out _, out var sol) || _puddle.CanFullyEvaporate(sol)) { _entityList.Add(ent); diff --git a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs index eebe7f98d8..45d868cdbf 100644 --- a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs @@ -1,9 +1,9 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Explosion.Components; using Content.Server.Explosion.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Nutrition.Components; using Content.Server.Popups; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Containers.ItemSlots; using Content.Shared.Interaction; using Content.Shared.Nutrition.Components; @@ -11,7 +11,6 @@ using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Rejuvenate; using Content.Shared.Throwing; using JetBrains.Annotations; -using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Player; @@ -42,7 +41,7 @@ namespace Content.Server.Nutrition.EntitySystems if (EntityManager.TryGetComponent(uid, out FoodComponent? foodComp)) { - if (_solutions.TryGetSolution(uid, foodComp.Solution, out var solution)) + if (_solutions.TryGetSolution(uid, foodComp.Solution, out _, out var solution)) { _puddle.TrySpillAt(uid, solution, out _, false); } @@ -56,9 +55,9 @@ namespace Content.Server.Nutrition.EntitySystems EntityManager.QueueDeleteEntity(uid); } - private void OnInteractUsing(EntityUid uid, CreamPieComponent component, InteractUsingEvent args) + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { - ActivatePayload(uid); + ActivatePayload(entity); } private void ActivatePayload(EntityUid uid) @@ -89,12 +88,12 @@ namespace Content.Server.Nutrition.EntitySystems { otherPlayers.RemovePlayer(actor.PlayerSession); } - _popup.PopupEntity(Loc.GetString("cream-pied-component-on-hit-by-message-others", ("owner", uid),("thrower", args.Thrown)), uid, otherPlayers, false); + _popup.PopupEntity(Loc.GetString("cream-pied-component-on-hit-by-message-others", ("owner", uid), ("thrower", args.Thrown)), uid, otherPlayers, false); } - private void OnRejuvenate(EntityUid uid, CreamPiedComponent component, RejuvenateEvent args) + private void OnRejuvenate(Entity entity, ref RejuvenateEvent args) { - SetCreamPied(uid, component, false); + SetCreamPied(entity, entity.Comp, false); } } } diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index e41c834c80..b32f5a7f63 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; -using Content.Server.Chemistry.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Chemistry.ReagentEffects; using Content.Server.Fluids.EntitySystems; using Content.Server.Forensics; @@ -61,7 +61,7 @@ public sealed class DrinkSystem : EntitySystem base.Initialize(); // TODO add InteractNoHandEvent for entities like mice. - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); SubscribeLocalEvent(OnDrinkInit); // run before inventory so for bucket it always tries to drink before equipping (when empty) // run after openable so its always open -> drink @@ -80,7 +80,7 @@ public sealed class DrinkSystem : EntitySystem if (!Resolve(uid, ref component)) return FixedPoint2.Zero; - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol)) + if (!_solutionContainer.TryGetSolution(uid, component.Solution, out _, out var sol)) return FixedPoint2.Zero; return sol.Volume; @@ -102,7 +102,7 @@ public sealed class DrinkSystem : EntitySystem if (!Resolve(uid, ref comp)) return 0f; - if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out var solution)) + if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out _, out var solution)) return 0f; var total = 0f; @@ -128,31 +128,31 @@ public sealed class DrinkSystem : EntitySystem return total; } - private void OnExamined(EntityUid uid, DrinkComponent component, ExaminedEvent args) + private void OnExamined(Entity entity, ref ExaminedEvent args) { - var hasOpenable = TryComp(uid, out var openable); - if (_openable.IsClosed(uid, null, openable) || !args.IsInDetailsRange || !component.Examinable) + var hasOpenable = TryComp(entity, out var openable); + if (_openable.IsClosed(entity.Owner, null, openable) || !args.IsInDetailsRange || !entity.Comp.Examinable) return; // put Empty / Xu after Opened, or start a new line args.Message.AddMarkup(hasOpenable ? " - " : "\n"); - var empty = IsEmpty(uid, component); + var empty = IsEmpty(entity, entity.Comp); if (empty) { args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-is-empty")); return; } - if (TryComp(uid, out var comp)) + if (TryComp(entity, out var comp)) { //provide exact measurement for beakers - args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(uid, component)))); + args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp)))); } else { //general approximation - var remainingString = (int) _solutionContainer.PercentFull(uid) switch + var remainingString = (int) _solutionContainer.PercentFull(entity) switch { 100 => "drink-component-on-examine-is-full", > 66 => "drink-component-on-examine-is-mostly-full", @@ -163,65 +163,65 @@ public sealed class DrinkSystem : EntitySystem } } - private void AfterInteract(EntityUid uid, DrinkComponent component, AfterInteractEvent args) + private void AfterInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled || args.Target == null || !args.CanReach) return; - args.Handled = TryDrink(args.User, args.Target.Value, component, uid); + args.Handled = TryDrink(args.User, args.Target.Value, entity.Comp, entity); } - private void OnUse(EntityUid uid, DrinkComponent component, UseInHandEvent args) + private void OnUse(Entity entity, ref UseInHandEvent args) { if (args.Handled) return; - args.Handled = TryDrink(args.User, args.User, component, uid); + args.Handled = TryDrink(args.User, args.User, entity.Comp, entity); } - private void OnPressurizedDrinkLand(EntityUid uid, PressurizedDrinkComponent comp, ref LandEvent args) + private void OnPressurizedDrinkLand(Entity entity, ref LandEvent args) { - if (!TryComp(uid, out var drink) || !TryComp(uid, out var openable)) + if (!TryComp(entity, out var drink) || !TryComp(entity, out var openable)) return; if (!openable.Opened && - _random.Prob(comp.BurstChance) && - _solutionContainer.TryGetSolution(uid, drink.Solution, out var interactions)) + _random.Prob(entity.Comp.BurstChance) && + _solutionContainer.TryGetSolution(entity.Owner, drink.Solution, out var soln, out var interactions)) { // using SetOpen instead of TryOpen to not play 2 sounds - _openable.SetOpen(uid, true, openable); + _openable.SetOpen(entity, true, openable); - var solution = _solutionContainer.SplitSolution(uid, interactions, interactions.Volume); - _puddle.TrySpillAt(uid, solution, out _); + var solution = _solutionContainer.SplitSolution(soln.Value, interactions.Volume); + _puddle.TrySpillAt(entity, solution, out _); - _audio.PlayPvs(comp.BurstSound, uid); + _audio.PlayPvs(entity.Comp.BurstSound, entity); } } - private void OnDrinkInit(EntityUid uid, DrinkComponent component, ComponentInit args) + private void OnDrinkInit(Entity entity, ref ComponentInit args) { - if (TryComp(uid, out var existingDrainable)) + if (TryComp(entity, out var existingDrainable)) { // Beakers have Drink component but they should use the existing Drainable - component.Solution = existingDrainable.Solution; + entity.Comp.Solution = existingDrainable.Solution; } else { - _solutionContainer.EnsureSolution(uid, component.Solution); + _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.Solution); } - UpdateAppearance(uid, component); + UpdateAppearance(entity, entity.Comp); - if (TryComp(uid, out RefillableSolutionComponent? refillComp)) - refillComp.Solution = component.Solution; + if (TryComp(entity, out RefillableSolutionComponent? refillComp)) + refillComp.Solution = entity.Comp.Solution; - if (TryComp(uid, out DrainableSolutionComponent? drainComp)) - drainComp.Solution = component.Solution; + if (TryComp(entity, out DrainableSolutionComponent? drainComp)) + drainComp.Solution = entity.Comp.Solution; } - private void OnSolutionChange(EntityUid uid, DrinkComponent component, SolutionChangedEvent args) + private void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { - UpdateAppearance(uid, component); + UpdateAppearance(entity, entity.Comp); } public void UpdateAppearance(EntityUid uid, DrinkComponent component) @@ -244,8 +244,7 @@ public sealed class DrinkSystem : EntitySystem if (_openable.IsClosed(item, user)) return true; - if (!_solutionContainer.TryGetSolution(item, drink.Solution, out var drinkSolution) || - drinkSolution.Volume <= 0) + if (!_solutionContainer.TryGetSolution(item, drink.Solution, out _, out var drinkSolution) || drinkSolution.Volume <= 0) { if (drink.IgnoreEmpty) return false; @@ -254,9 +253,6 @@ public sealed class DrinkSystem : EntitySystem return true; } - if (drinkSolution.Name == null) - return false; - if (_food.IsMouthBlocked(target, user)) return true; @@ -285,7 +281,7 @@ public sealed class DrinkSystem : EntitySystem var doAfterEventArgs = new DoAfterArgs(EntityManager, user, forceDrink ? drink.ForceFeedDelay : drink.Delay, - new ConsumeDoAfterEvent(drinkSolution.Name, flavors), + new ConsumeDoAfterEvent(drink.Solution, flavors), eventTarget: item, target: target, used: item) @@ -307,15 +303,15 @@ public sealed class DrinkSystem : EntitySystem /// /// Raised directed at a victim when someone has force fed them a drink. /// - private void OnDoAfter(EntityUid uid, DrinkComponent component, ConsumeDoAfterEvent args) + private void OnDoAfter(Entity entity, ref ConsumeDoAfterEvent args) { - if (args.Handled || args.Cancelled || component.Deleted) + if (args.Handled || args.Cancelled || entity.Comp.Deleted) return; if (!TryComp(args.Target, out var body)) return; - if (!_solutionContainer.TryGetSolution(args.Used, args.Solution, out var solution)) + if (args.Used is null || !_solutionContainer.TryGetSolution(args.Used.Value, args.Solution, out var soln, out var solution)) return; // TODO this should really be checked every tick. @@ -326,8 +322,8 @@ public sealed class DrinkSystem : EntitySystem if (!_interaction.InRangeUnobstructed(args.User, args.Target.Value)) return; - var transferAmount = FixedPoint2.Min(component.TransferAmount, solution.Volume); - var drained = _solutionContainer.SplitSolution(uid, solution, transferAmount); + var transferAmount = FixedPoint2.Min(entity.Comp.TransferAmount, solution.Volume); + var drained = _solutionContainer.SplitSolution(soln.Value, transferAmount); var forceDrink = args.User != args.Target; args.Handled = true; @@ -344,11 +340,11 @@ public sealed class DrinkSystem : EntitySystem return; } - _solutionContainer.Refill(args.Target.Value, solution, drained); + _solutionContainer.Refill(args.Target.Value, soln.Value, drained); return; } - var firstStomach = stomachs.FirstOrNull(stomach => _stomach.CanTransferSolution(stomach.Comp.Owner, drained)); + var firstStomach = stomachs.FirstOrNull(stomach => _stomach.CanTransferSolution(stomach.Comp.Owner, drained, stomach.Comp)); //All stomachs are full or can't handle whatever solution we have. if (firstStomach == null) @@ -361,7 +357,7 @@ public sealed class DrinkSystem : EntitySystem _puddle.TrySpillAt(args.Target.Value, drained, out _); } else - _solutionContainer.TryAddSolution(uid, solution, drained); + _solutionContainer.TryAddSolution(soln.Value, drained); return; } @@ -380,7 +376,7 @@ public sealed class DrinkSystem : EntitySystem args.User, args.User); // log successful forced drinking - _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(uid):user} forced {ToPrettyString(args.User):target} to drink {ToPrettyString(uid):drink}"); + _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity.Owner):user} forced {ToPrettyString(args.User):target} to drink {ToPrettyString(entity.Owner):drink}"); } else { @@ -391,24 +387,24 @@ public sealed class DrinkSystem : EntitySystem Loc.GetString("drink-component-try-use-drink-success-slurp"), args.User, Filter.PvsExcept(args.User), true); // log successful voluntary drinking - _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} drank {ToPrettyString(uid):drink}"); + _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} drank {ToPrettyString(entity.Owner):drink}"); } - _audio.PlayPvs(component.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-2f)); + _audio.PlayPvs(entity.Comp.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-2f)); _reaction.DoEntityReaction(args.Target.Value, solution, ReactionMethod.Ingestion); //TODO: Grab the stomach UIDs somehow without using Owner _stomach.TryTransferSolution(firstStomach.Value.Comp.Owner, drained, firstStomach.Value.Comp); - _forensics.TransferDna(uid, args.Target.Value); + _forensics.TransferDna(entity, args.Target.Value); if (!forceDrink && solution.Volume > 0) args.Repeat = true; } - private void AddDrinkVerb(EntityUid uid, DrinkComponent component, GetVerbsEvent ev) + private void AddDrinkVerb(Entity entity, ref GetVerbsEvent ev) { - if (uid == ev.User || + if (entity.Owner == ev.User || !ev.CanInteract || !ev.CanAccess || !TryComp(ev.User, out var body) || @@ -416,16 +412,17 @@ public sealed class DrinkSystem : EntitySystem return; // no drinking from living drinks, have to kill them first. - if (_mobState.IsAlive(uid)) + if (_mobState.IsAlive(entity)) return; + var user = ev.User; AlternativeVerb verb = new() { Act = () => { - TryDrink(ev.User, ev.User, component, uid); + TryDrink(user, user, entity.Comp, entity); }, - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")), Text = Loc.GetString("drink-system-verb-drink"), Priority = 2 }; diff --git a/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs b/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs index e01f199ae1..4a18696cea 100644 --- a/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs @@ -1,13 +1,10 @@ -using System.Linq; -using System.Text; using Content.Server.Nutrition.Components; using Content.Shared.CCVar; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Reagent; using Content.Shared.Nutrition; -using Microsoft.VisualBasic; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; +using System.Linq; namespace Content.Server.Nutrition.EntitySystems; diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index b18c77fffb..95a40a9409 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -1,6 +1,6 @@ -using System.Linq; using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Inventory; using Content.Server.Nutrition.Components; using Content.Server.Popups; @@ -9,7 +9,6 @@ using Content.Shared.Administration.Logs; using Content.Shared.Body.Components; using Content.Shared.Body.Organ; using Content.Shared.Chemistry; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.DoAfter; @@ -27,11 +26,9 @@ using Content.Shared.Stacks; using Content.Shared.Storage; using Content.Shared.Verbs; using Robust.Shared.Audio; -using Robust.Shared.Player; -using Robust.Shared.Utility; -using Content.Shared.Tag; -using Content.Shared.Storage; using Robust.Shared.Audio.Systems; +using Robust.Shared.Utility; +using System.Linq; namespace Content.Server.Nutrition.EntitySystems; @@ -75,24 +72,24 @@ public sealed class FoodSystem : EntitySystem /// /// Eat item /// - private void OnUseFoodInHand(EntityUid uid, FoodComponent foodComponent, UseInHandEvent ev) + private void OnUseFoodInHand(Entity entity, ref UseInHandEvent ev) { if (ev.Handled) return; - var result = TryFeed(ev.User, ev.User, uid, foodComponent); + var result = TryFeed(ev.User, ev.User, entity, entity.Comp); ev.Handled = result.Handled; } /// /// Feed someone else /// - private void OnFeedFood(EntityUid uid, FoodComponent foodComponent, AfterInteractEvent args) + private void OnFeedFood(Entity entity, ref AfterInteractEvent args) { if (args.Handled || args.Target == null || !args.CanReach) return; - var result = TryFeed(args.User, args.Target.Value, uid, foodComponent); + var result = TryFeed(args.User, args.Target.Value, entity, entity.Comp); args.Handled = result.Handled; } @@ -112,7 +109,7 @@ public sealed class FoodSystem : EntitySystem if (_openable.IsClosed(food, user)) return (false, true); - if (!_solutionContainer.TryGetSolution(food, foodComp.Solution, out var foodSolution) || foodSolution.Name == null) + if (!_solutionContainer.TryGetSolution(food, foodComp.Solution, out _, out var foodSolution)) return (false, false); if (!_body.TryGetBodyOrganComponents(target, out var stomachs, body)) @@ -177,7 +174,7 @@ public sealed class FoodSystem : EntitySystem var doAfterArgs = new DoAfterArgs(EntityManager, user, forceFeed ? foodComp.ForceFeedDelay : foodComp.Delay, - new ConsumeDoAfterEvent(foodSolution.Name, flavors), + new ConsumeDoAfterEvent(foodComp.Solution, flavors), eventTarget: food, target: target, used: food) @@ -196,9 +193,9 @@ public sealed class FoodSystem : EntitySystem return (true, true); } - private void OnDoAfter(EntityUid uid, FoodComponent component, ConsumeDoAfterEvent args) + private void OnDoAfter(Entity entity, ref ConsumeDoAfterEvent args) { - if (args.Cancelled || args.Handled || component.Deleted || args.Target == null) + if (args.Cancelled || args.Handled || entity.Comp.Deleted || args.Target == null) return; if (!TryComp(args.Target.Value, out var body)) @@ -207,10 +204,10 @@ public sealed class FoodSystem : EntitySystem if (!_body.TryGetBodyOrganComponents(args.Target.Value, out var stomachs, body)) return; - if (!_solutionContainer.TryGetSolution(args.Used, args.Solution, out var solution)) + if (args.Used is null || !_solutionContainer.TryGetSolution(args.Used.Value, args.Solution, out var soln, out var solution)) return; - if (!TryGetRequiredUtensils(args.User, component, out var utensils)) + if (!TryGetRequiredUtensils(args.User, entity.Comp, out var utensils)) return; // TODO this should really be checked every tick. @@ -224,9 +221,9 @@ public sealed class FoodSystem : EntitySystem var forceFeed = args.User != args.Target; args.Handled = true; - var transferAmount = component.TransferAmount != null ? FixedPoint2.Min((FixedPoint2) component.TransferAmount, solution.Volume) : solution.Volume; + var transferAmount = entity.Comp.TransferAmount != null ? FixedPoint2.Min((FixedPoint2) entity.Comp.TransferAmount, solution.Volume) : solution.Volume; - var split = _solutionContainer.SplitSolution(uid, solution, transferAmount); + var split = _solutionContainer.SplitSolution(soln.Value, transferAmount); //TODO: Get the stomach UID somehow without nabbing owner // Get the stomach with the highest available solution volume @@ -235,11 +232,10 @@ public sealed class FoodSystem : EntitySystem foreach (var (stomach, _) in stomachs) { var owner = stomach.Owner; - if (!_stomach.CanTransferSolution(owner, split)) + if (!_stomach.CanTransferSolution(owner, split, stomach)) continue; - if (!_solutionContainer.TryGetSolution(owner, StomachSystem.DefaultSolutionName, - out var stomachSol)) + if (!_solutionContainer.ResolveSolution(owner, StomachSystem.DefaultSolutionName, ref stomach.Solution, out var stomachSol)) continue; if (stomachSol.AvailableVolume <= highestAvailable) @@ -252,7 +248,7 @@ public sealed class FoodSystem : EntitySystem // No stomach so just popup a message that they can't eat. if (stomachToUse == null) { - _solutionContainer.TryAddSolution(uid, solution, split); + _solutionContainer.TryAddSolution(soln.Value, split); _popup.PopupEntity(forceFeed ? Loc.GetString("food-system-you-cannot-eat-any-more-other") : Loc.GetString("food-system-you-cannot-eat-any-more"), args.Target.Value, args.User); return; } @@ -266,23 +262,22 @@ public sealed class FoodSystem : EntitySystem { var targetName = Identity.Entity(args.Target.Value, EntityManager); var userName = Identity.Entity(args.User, EntityManager); - _popup.PopupEntity(Loc.GetString("food-system-force-feed-success", ("user", userName), ("flavors", flavors)), - uid, uid); + _popup.PopupEntity(Loc.GetString("food-system-force-feed-success", ("user", userName), ("flavors", flavors)), entity.Owner, entity.Owner); _popup.PopupEntity(Loc.GetString("food-system-force-feed-success-user", ("target", targetName)), args.User, args.User); // log successful force feed - _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(uid):user} forced {ToPrettyString(args.User):target} to eat {ToPrettyString(uid):food}"); + _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity.Owner):user} forced {ToPrettyString(args.User):target} to eat {ToPrettyString(entity.Owner):food}"); } else { - _popup.PopupEntity(Loc.GetString(component.EatMessage, ("food", uid), ("flavors", flavors)), args.User, args.User); + _popup.PopupEntity(Loc.GetString(entity.Comp.EatMessage, ("food", entity.Owner), ("flavors", flavors)), args.User, args.User); // log successful voluntary eating - _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} ate {ToPrettyString(uid):food}"); + _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} ate {ToPrettyString(entity.Owner):food}"); } - _audio.PlayPvs(component.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-1f)); + _audio.PlayPvs(entity.Comp.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-1f)); // Try to break all used utensils foreach (var utensil in utensils) @@ -292,24 +287,24 @@ public sealed class FoodSystem : EntitySystem args.Repeat = !forceFeed; - if (TryComp(uid, out var stack)) + if (TryComp(entity, out var stack)) { //Not deleting whole stack piece will make troubles with grinding object if (stack.Count > 1) { - _stack.SetCount(uid, stack.Count - 1); - _solutionContainer.TryAddSolution(uid, solution, split); + _stack.SetCount(entity.Owner, stack.Count - 1); + _solutionContainer.TryAddSolution(soln.Value, split); return; } } - else if (GetUsesRemaining(uid, component) > 0) + else if (GetUsesRemaining(entity.Owner, entity.Comp) > 0) { return; } // don't try to repeat if its being deleted args.Repeat = false; - DeleteAndSpawnTrash(component, uid, args.User); + DeleteAndSpawnTrash(entity.Comp, entity.Owner, args.User); } public void DeleteAndSpawnTrash(FoodComponent component, EntityUid food, EntityUid user) @@ -345,9 +340,9 @@ public sealed class FoodSystem : EntitySystem QueueDel(food); } - private void AddEatVerb(EntityUid uid, FoodComponent component, GetVerbsEvent ev) + private void AddEatVerb(Entity entity, ref GetVerbsEvent ev) { - if (uid == ev.User || + if (entity.Owner == ev.User || !ev.CanInteract || !ev.CanAccess || !TryComp(ev.User, out var body) || @@ -355,20 +350,21 @@ public sealed class FoodSystem : EntitySystem return; // have to kill mouse before eating it - if (_mobState.IsAlive(uid) && component.RequireDead) + if (_mobState.IsAlive(entity) && entity.Comp.RequireDead) return; // only give moths eat verb for clothes since it would just fail otherwise - if (!IsDigestibleBy(uid, component, stomachs)) + if (!IsDigestibleBy(entity, entity.Comp, stomachs)) return; + var user = ev.User; AlternativeVerb verb = new() { Act = () => { - TryFeed(ev.User, ev.User, uid, component); + TryFeed(user, user, entity, entity.Comp); }, - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/cutlery.svg.192dpi.png")), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/cutlery.svg.192dpi.png")), Text = Loc.GetString("food-system-verb-eat"), Priority = -1 }; @@ -416,7 +412,7 @@ public sealed class FoodSystem : EntitySystem } if (component.RequiresSpecialDigestion) - return false; + return false; return digestible; } @@ -462,14 +458,14 @@ public sealed class FoodSystem : EntitySystem /// /// Block ingestion attempts based on the equipped mask or head-wear /// - private void OnInventoryIngestAttempt(EntityUid uid, InventoryComponent component, IngestionAttemptEvent args) + private void OnInventoryIngestAttempt(Entity entity, ref IngestionAttemptEvent args) { if (args.Cancelled) return; IngestionBlockerComponent? blocker; - if (_inventory.TryGetSlotEntity(uid, "mask", out var maskUid) && + if (_inventory.TryGetSlotEntity(entity.Owner, "mask", out var maskUid) && TryComp(maskUid, out blocker) && blocker.Enabled) { @@ -478,7 +474,7 @@ public sealed class FoodSystem : EntitySystem return; } - if (_inventory.TryGetSlotEntity(uid, "head", out var headUid) && + if (_inventory.TryGetSlotEntity(entity.Owner, "head", out var headUid) && TryComp(headUid, out blocker) && blocker.Enabled) { @@ -516,7 +512,7 @@ public sealed class FoodSystem : EntitySystem if (!Resolve(uid, ref comp)) return 0; - if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out var solution) || solution.Volume == 0) + if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out _, out var solution) || solution.Volume == 0) return 0; // eat all in 1 go, so non empty is 1 bite diff --git a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs index 56f5d9adeb..064d316bef 100644 --- a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs @@ -1,7 +1,6 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.Components; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Hands.EntitySystems; @@ -9,7 +8,6 @@ using Content.Shared.Interaction; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Player; namespace Content.Server.Nutrition.EntitySystems { @@ -29,12 +27,12 @@ namespace Content.Server.Nutrition.EntitySystems SubscribeLocalEvent(OnComponentStartup); } - private void OnInteractUsing(EntityUid uid, SliceableFoodComponent component, InteractUsingEvent args) + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { if (args.Handled) return; - if (TrySliceFood(uid, args.User, args.Used, component)) + if (TrySliceFood(entity, args.User, args.Used, entity.Comp)) args.Handled = true; } @@ -47,7 +45,7 @@ namespace Content.Server.Nutrition.EntitySystems return false; } - if (!_solutionContainerSystem.TryGetSolution(uid, food.Solution, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(uid, food.Solution, out var soln, out var solution)) { return false; } @@ -59,8 +57,7 @@ namespace Content.Server.Nutrition.EntitySystems var sliceUid = Slice(uid, user, component, transform); - var lostSolution = _solutionContainerSystem.SplitSolution(uid, solution, - solution.Volume / FixedPoint2.New(component.Count)); + var lostSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume / FixedPoint2.New(component.Count)); // Fill new slice FillSlice(sliceUid, lostSolution); @@ -137,27 +134,26 @@ namespace Content.Server.Nutrition.EntitySystems { // Replace all reagents on prototype not just copying poisons (example: slices of eaten pizza should have less nutrition) if (TryComp(sliceUid, out var sliceFoodComp) && - _solutionContainerSystem.TryGetSolution(sliceUid, sliceFoodComp.Solution, out var itsSolution)) + _solutionContainerSystem.TryGetSolution(sliceUid, sliceFoodComp.Solution, out var itsSoln, out var itsSolution)) { - _solutionContainerSystem.RemoveAllSolution(sliceUid, itsSolution); + _solutionContainerSystem.RemoveAllSolution(itsSoln.Value); var lostSolutionPart = solution.SplitSolution(itsSolution.AvailableVolume); - _solutionContainerSystem.TryAddSolution(sliceUid, itsSolution, lostSolutionPart); + _solutionContainerSystem.TryAddSolution(itsSoln.Value, lostSolutionPart); } } - private void OnComponentStartup(EntityUid uid, SliceableFoodComponent component, ComponentStartup args) + private void OnComponentStartup(Entity entity, ref ComponentStartup args) { - component.Count = component.TotalCount; - var foodComp = EnsureComp(uid); + entity.Comp.Count = entity.Comp.TotalCount; - EnsureComp(uid); - _solutionContainerSystem.EnsureSolution(uid, foodComp.Solution); + var foodComp = EnsureComp(entity); + _solutionContainerSystem.EnsureSolution(entity.Owner, foodComp.Solution); } - private void OnExamined(EntityUid uid, SliceableFoodComponent component, ExaminedEvent args) + private void OnExamined(Entity entity, ref ExaminedEvent args) { - args.PushMarkup(Loc.GetString("sliceable-food-component-on-examine-remaining-slices-text", ("remainingCount", component.Count))); + args.PushMarkup(Loc.GetString("sliceable-food-component-on-examine-remaining-slices-text", ("remainingCount", entity.Comp.Count))); } } } diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Cigar.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Cigar.cs index 99a96fd2b3..4e672444d1 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Cigar.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Cigar.cs @@ -1,6 +1,6 @@ using Content.Server.Nutrition.Components; -using Content.Shared.Nutrition.Components; using Content.Shared.Interaction; +using Content.Shared.Nutrition.Components; using Content.Shared.Smoking; using Content.Shared.Temperature; @@ -16,27 +16,27 @@ namespace Content.Server.Nutrition.EntitySystems SubscribeLocalEvent(OnCigarAfterInteract); } - private void OnCigarActivatedEvent(EntityUid uid, CigarComponent component, ActivateInWorldEvent args) + private void OnCigarActivatedEvent(Entity entity, ref ActivateInWorldEvent args) { if (args.Handled) return; - if (!EntityManager.TryGetComponent(uid, out SmokableComponent? smokable)) + if (!EntityManager.TryGetComponent(entity, out SmokableComponent? smokable)) return; if (smokable.State != SmokableState.Lit) return; - SetSmokableState(uid, SmokableState.Burnt, smokable); + SetSmokableState(entity, SmokableState.Burnt, smokable); args.Handled = true; } - private void OnCigarInteractUsingEvent(EntityUid uid, CigarComponent component, InteractUsingEvent args) + private void OnCigarInteractUsingEvent(Entity entity, ref InteractUsingEvent args) { if (args.Handled) return; - if (!EntityManager.TryGetComponent(uid, out SmokableComponent? smokable)) + if (!EntityManager.TryGetComponent(entity, out SmokableComponent? smokable)) return; if (smokable.State != SmokableState.Unlit) @@ -48,16 +48,16 @@ namespace Content.Server.Nutrition.EntitySystems if (!isHotEvent.IsHot) return; - SetSmokableState(uid, SmokableState.Lit, smokable); + SetSmokableState(entity, SmokableState.Lit, smokable); args.Handled = true; } - public void OnCigarAfterInteract(EntityUid uid, CigarComponent component, AfterInteractEvent args) + public void OnCigarAfterInteract(Entity entity, ref AfterInteractEvent args) { var targetEntity = args.Target; if (targetEntity == null || !args.CanReach || - !EntityManager.TryGetComponent(uid, out SmokableComponent? smokable) || + !EntityManager.TryGetComponent(entity, out SmokableComponent? smokable) || smokable.State == SmokableState.Lit) return; @@ -67,13 +67,13 @@ namespace Content.Server.Nutrition.EntitySystems if (!isHotEvent.IsHot) return; - SetSmokableState(uid, SmokableState.Lit, smokable); + SetSmokableState(entity, SmokableState.Lit, smokable); args.Handled = true; } - private void OnCigarSolutionEmptyEvent(EntityUid uid, CigarComponent component, SmokableSolutionEmptyEvent args) + private void OnCigarSolutionEmptyEvent(Entity entity, ref SmokableSolutionEmptyEvent args) { - SetSmokableState(uid, SmokableState.Burnt); + SetSmokableState(entity, SmokableState.Burnt); } } } diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs index 772847e8df..3950c73eb4 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs @@ -1,8 +1,8 @@ using Content.Server.Nutrition.Components; -using Content.Shared.Nutrition.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Containers.ItemSlots; using Content.Shared.Interaction; +using Content.Shared.Nutrition.Components; using Content.Shared.Smoking; using Content.Shared.Temperature; @@ -20,17 +20,17 @@ namespace Content.Server.Nutrition.EntitySystems SubscribeLocalEvent(OnComponentInit); } - public void OnComponentInit(EntityUid uid, SmokingPipeComponent pipe, ComponentInit args) + public void OnComponentInit(Entity entity, ref ComponentInit args) { - _itemSlotsSystem.AddItemSlot(uid, SmokingPipeComponent.BowlSlotId, pipe.BowlSlot); + _itemSlotsSystem.AddItemSlot(entity, SmokingPipeComponent.BowlSlotId, entity.Comp.BowlSlot); } - private void OnPipeInteractUsingEvent(EntityUid uid, SmokingPipeComponent component, InteractUsingEvent args) + private void OnPipeInteractUsingEvent(Entity entity, ref InteractUsingEvent args) { if (args.Handled) return; - if (!EntityManager.TryGetComponent(uid, out SmokableComponent? smokable)) + if (!EntityManager.TryGetComponent(entity, out SmokableComponent? smokable)) return; if (smokable.State != SmokableState.Unlit) @@ -42,17 +42,17 @@ namespace Content.Server.Nutrition.EntitySystems if (!isHotEvent.IsHot) return; - if (TryTransferReagents(component, smokable)) - SetSmokableState(uid, SmokableState.Lit, smokable); + if (TryTransferReagents(entity.Comp, smokable)) + SetSmokableState(entity, SmokableState.Lit, smokable); args.Handled = true; } - public void OnPipeAfterInteract(EntityUid uid, SmokingPipeComponent component, AfterInteractEvent args) + public void OnPipeAfterInteract(Entity entity, ref AfterInteractEvent args) { var targetEntity = args.Target; if (targetEntity == null || !args.CanReach || - !EntityManager.TryGetComponent(uid, out SmokableComponent? smokable) || + !EntityManager.TryGetComponent(entity, out SmokableComponent? smokable) || smokable.State == SmokableState.Lit) return; @@ -62,15 +62,15 @@ namespace Content.Server.Nutrition.EntitySystems if (!isHotEvent.IsHot) return; - if(TryTransferReagents(component, smokable)) - SetSmokableState(uid, SmokableState.Lit, smokable); + if (TryTransferReagents(entity.Comp, smokable)) + SetSmokableState(entity, SmokableState.Lit, smokable); args.Handled = true; } - private void OnPipeSolutionEmptyEvent(EntityUid uid, SmokingPipeComponent component, SmokableSolutionEmptyEvent args) + private void OnPipeSolutionEmptyEvent(Entity entity, ref SmokableSolutionEmptyEvent args) { - _itemSlotsSystem.SetLock(component.Owner, component.BowlSlot, false); - SetSmokableState(uid, SmokableState.Unlit); + _itemSlotsSystem.SetLock(entity, entity.Comp.BowlSlot, false); + SetSmokableState(entity, SmokableState.Unlit); } // Convert smokable item into reagents to be smoked @@ -82,12 +82,13 @@ namespace Content.Server.Nutrition.EntitySystems EntityUid contents = component.BowlSlot.Item.Value; if (!TryComp(contents, out var reagents) || - !_solutionContainerSystem.TryGetSolution(smokable.Owner, smokable.Solution, out var pipeSolution)) + !_solutionContainerSystem.TryGetSolution(smokable.Owner, smokable.Solution, out var pipeSolution, out _)) return false; - foreach (var reagentSolution in reagents.Solutions) + foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((contents, reagents))) { - _solutionContainerSystem.TryAddSolution(smokable.Owner, pipeSolution, reagentSolution.Value); + var reagentSolution = soln.Comp.Solution; + _solutionContainerSystem.TryAddSolution(pipeSolution.Value, reagentSolution); } EntityManager.DeleteEntity(contents); diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs index 4dd9aff9ac..fe0d1d0c16 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs @@ -1,18 +1,18 @@ -using Content.Server.Nutrition.Components; -using Content.Server.Body.Components; -using Content.Shared.Interaction; -using Content.Server.DoAfter; -using System.Threading; -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Damage; -using Content.Server.Popups; -using Content.Shared.IdentityManagement; -using Content.Shared.DoAfter; -using Content.Shared.Emag.Systems; -using Content.Shared.Emag.Components; -using Content.Shared.Nutrition; -using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Body.Components; +using Content.Server.DoAfter; +using Content.Server.Explosion.EntitySystems; +using Content.Server.Nutrition.Components; +using Content.Server.Popups; +using Content.Shared.Damage; +using Content.Shared.DoAfter; +using Content.Shared.Emag.Components; +using Content.Shared.Emag.Systems; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; +using Content.Shared.Nutrition; +using System.Threading; /// /// System for vapes @@ -35,16 +35,14 @@ namespace Content.Server.Nutrition.EntitySystems SubscribeLocalEvent(OnEmagged); } - private void OnVapeInteraction(EntityUid uid, VapeComponent comp, AfterInteractEvent args) + private void OnVapeInteraction(Entity entity, ref AfterInteractEvent args) { - _solutionContainerSystem.TryGetRefillableSolution(uid, out var solution); - - var delay = comp.Delay; + var delay = entity.Comp.Delay; var forced = true; var exploded = false; if (!args.CanReach - || solution == null + || !_solutionContainerSystem.TryGetRefillableSolution(entity.Owner, out _, out var solution) || !HasComp(args.Target) || _foodSystem.IsMouthBlocked(args.Target.Value, args.User)) { @@ -61,14 +59,14 @@ namespace Content.Server.Nutrition.EntitySystems if (args.Target == args.User) { - delay = comp.UserDelay; + delay = entity.Comp.UserDelay; forced = false; } - if (comp.ExplodeOnUse || HasComp(uid)) + if (entity.Comp.ExplodeOnUse || HasComp(entity.Owner)) { - _explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false); - EntityManager.DeleteEntity(uid); + _explosionSystem.QueueExplosion(entity.Owner, "Default", entity.Comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false); + EntityManager.DeleteEntity(entity); exploded = true; } else @@ -80,11 +78,11 @@ namespace Content.Server.Nutrition.EntitySystems // just re-use the existing RiggableSystem. foreach (var name in solution.Contents) { - if (name.Reagent.Prototype != comp.SolutionNeeded) + if (name.Reagent.Prototype != entity.Comp.SolutionNeeded) { exploded = true; - _explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false); - EntityManager.DeleteEntity(uid); + _explosionSystem.QueueExplosion(entity.Owner, "Default", entity.Comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false); + EntityManager.DeleteEntity(entity); break; } } @@ -113,7 +111,7 @@ namespace Content.Server.Nutrition.EntitySystems if (!exploded) { var vapeDoAfterEvent = new VapeDoAfterEvent(solution, forced); - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, delay, vapeDoAfterEvent, uid, target: args.Target, used: uid) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, delay, vapeDoAfterEvent, entity.Owner, target: args.Target, used: entity.Owner) { BreakOnTargetMove = true, BreakOnUserMove = false, @@ -121,9 +119,9 @@ namespace Content.Server.Nutrition.EntitySystems }); } args.Handled = true; - } + } - private void OnVapeDoAfter(EntityUid uid, VapeComponent comp, VapeDoAfterEvent args) + private void OnVapeDoAfter(Entity entity, ref VapeDoAfterEvent args) { if (args.Handled || args.Args.Target == null) @@ -136,10 +134,10 @@ namespace Content.Server.Nutrition.EntitySystems } //Smoking kills(your lungs, but there is no organ damage yet) - _damageableSystem.TryChangeDamage(args.Args.Target.Value, comp.Damage, true); + _damageableSystem.TryChangeDamage(args.Args.Target.Value, entity.Comp.Damage, true); - var merger = new GasMixture(1) { Temperature = args.Solution.Temperature}; - merger.SetMoles(comp.GasType, args.Solution.Volume.Value / comp.ReductionFactor); + var merger = new GasMixture(1) { Temperature = args.Solution.Temperature }; + merger.SetMoles(entity.Comp.GasType, args.Solution.Volume.Value / entity.Comp.ReductionFactor); _atmosphereSystem.Merge(environment, merger); @@ -165,9 +163,9 @@ namespace Content.Server.Nutrition.EntitySystems args.Args.Target.Value); } } - private void OnEmagged(EntityUid uid, VapeComponent component, ref GotEmaggedEvent args) + private void OnEmagged(Entity entity, ref GotEmaggedEvent args) { args.Handled = true; } - } + } } diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs index 63a558238b..a33c944c99 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs @@ -1,22 +1,22 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; using Content.Server.Body.Systems; -using Content.Shared.Nutrition.Components; +using Content.Server.Chemistry.Containers.EntitySystems; +using Content.Server.Forensics; using Content.Shared.Chemistry; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; using Content.Shared.FixedPoint; using Content.Shared.Inventory; +using Content.Shared.Inventory.Events; using Content.Shared.Item; +using Content.Shared.Nutrition.Components; using Content.Shared.Smoking; using Content.Shared.Temperature; using Robust.Server.GameObjects; using Robust.Shared.Containers; using System.Linq; -using Content.Shared.Inventory.Events; -using Content.Server.Forensics; namespace Content.Server.Nutrition.EntitySystems { @@ -79,21 +79,21 @@ namespace Content.Server.Nutrition.EntitySystems _active.Remove(uid); } - private void OnSmokableIsHotEvent(EntityUid uid, SmokableComponent component, IsHotEvent args) + private void OnSmokableIsHotEvent(Entity entity, ref IsHotEvent args) { - args.IsHot = component.State == SmokableState.Lit; + args.IsHot = entity.Comp.State == SmokableState.Lit; } - private void OnSmokableShutdownEvent(EntityUid uid, SmokableComponent component, ComponentShutdown args) + private void OnSmokableShutdownEvent(Entity entity, ref ComponentShutdown args) { - _active.Remove(uid); + _active.Remove(entity); } - private void OnSmokeableEquipEvent(EntityUid uid, SmokableComponent component, GotEquippedEvent args) + private void OnSmokeableEquipEvent(Entity entity, ref GotEquippedEvent args) { if (args.Slot == "mask") { - _forensics.TransferDna(uid, args.Equipee, false); + _forensics.TransferDna(entity.Owner, args.Equipee, false); } } @@ -113,7 +113,7 @@ namespace Content.Server.Nutrition.EntitySystems continue; } - if (!_solutionContainerSystem.TryGetSolution(uid, smokable.Solution, out var solution)) + if (!_solutionContainerSystem.TryGetSolution(uid, smokable.Solution, out var soln, out var solution)) { _active.Remove(uid); continue; @@ -123,14 +123,14 @@ namespace Content.Server.Nutrition.EntitySystems { var transform = Transform(uid); - if (transform.GridUid is {} gridUid) + if (transform.GridUid is { } gridUid) { var position = _transformSystem.GetGridOrMapTilePosition(uid, transform); _atmos.HotspotExpose(gridUid, position, smokable.ExposeTemperature, smokable.ExposeVolume, uid, true); } } - var inhaledSolution = _solutionContainerSystem.SplitSolution(uid, solution, smokable.InhaleAmount * _timer); + var inhaledSolution = _solutionContainerSystem.SplitSolution(soln.Value, smokable.InhaleAmount * _timer); if (solution.Volume == FixedPoint2.Zero) { diff --git a/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs b/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs index 22360b6492..249c6b5239 100644 --- a/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs +++ b/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.Components; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; @@ -15,37 +16,37 @@ namespace Content.Server.Nutrition.EntitySystems { base.Initialize(); SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); } - public void OnStartup(EntityUid uid, TrashOnSolutionEmptyComponent component, ComponentStartup args) + public void OnStartup(Entity entity, ref ComponentStartup args) { - CheckSolutions(component); + CheckSolutions(entity); } - public void OnSolutionChange(EntityUid uid, TrashOnSolutionEmptyComponent component, SolutionChangedEvent args) + public void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { - CheckSolutions(component); + CheckSolutions(entity); } - public void CheckSolutions(TrashOnSolutionEmptyComponent component) + public void CheckSolutions(Entity entity) { - if (!EntityManager.HasComponent((component).Owner)) + if (!EntityManager.HasComponent(entity)) return; - if (_solutionContainerSystem.TryGetSolution(component.Owner, component.Solution, out var solution)) - UpdateTags(component, solution); + if (_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var solution)) + UpdateTags(entity, solution); } - public void UpdateTags(TrashOnSolutionEmptyComponent component, Solution solution) + public void UpdateTags(Entity entity, Solution solution) { if (solution.Volume <= 0) { - _tagSystem.AddTag(component.Owner, "Trash"); + _tagSystem.AddTag(entity.Owner, "Trash"); return; } - if (_tagSystem.HasTag(component.Owner, "Trash")) - _tagSystem.RemoveTag(component.Owner, "Trash"); + if (_tagSystem.HasTag(entity.Owner, "Trash")) + _tagSystem.RemoveTag(entity.Owner, "Trash"); } } } diff --git a/Content.Server/Payload/EntitySystems/PayloadSystem.cs b/Content.Server/Payload/EntitySystems/PayloadSystem.cs index f57024087d..78a2de22d1 100644 --- a/Content.Server/Payload/EntitySystems/PayloadSystem.cs +++ b/Content.Server/Payload/EntitySystems/PayloadSystem.cs @@ -1,8 +1,7 @@ -using System.Linq; using Content.Server.Administration.Logs; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Explosion.EntitySystems; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.Examine; using Content.Shared.Payload.Components; @@ -10,14 +9,15 @@ using Content.Shared.Tag; using Robust.Shared.Containers; using Robust.Shared.Serialization.Manager; using Robust.Shared.Utility; +using System.Linq; namespace Content.Server.Payload.EntitySystems; public sealed class PayloadSystem : EntitySystem { [Dependency] private readonly TagSystem _tagSystem = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; - [Dependency] private readonly IAdminLogManager _adminLogger= default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly ISerializationManager _serializationManager = default!; @@ -33,7 +33,7 @@ public sealed class PayloadSystem : EntitySystem SubscribeLocalEvent(HandleChemicalPayloadTrigger); } - public IEnumerable GetAllPayloads(EntityUid uid, ContainerManagerComponent? contMan=null) + public IEnumerable GetAllPayloads(EntityUid uid, ContainerManagerComponent? contMan = null) { if (!Resolve(uid, ref contMan, false)) yield break; @@ -98,7 +98,7 @@ public sealed class PayloadSystem : EntitySystem var temp = (object) component; _serializationManager.CopyTo(data.Component, ref temp); - EntityManager.AddComponent(uid, (Component)temp!); + EntityManager.AddComponent(uid, (Component) temp!); trigger.GrantedComponents.Add(registration.Type); } @@ -137,14 +137,14 @@ public sealed class PayloadSystem : EntitySystem } } - private void HandleChemicalPayloadTrigger(EntityUid uid, ChemicalPayloadComponent component, TriggerEvent args) + private void HandleChemicalPayloadTrigger(Entity entity, ref TriggerEvent args) { - if (component.BeakerSlotA.Item is not EntityUid beakerA - || component.BeakerSlotB.Item is not EntityUid beakerB + if (entity.Comp.BeakerSlotA.Item is not EntityUid beakerA + || entity.Comp.BeakerSlotB.Item is not EntityUid beakerB || !TryComp(beakerA, out FitsInDispenserComponent? compA) || !TryComp(beakerB, out FitsInDispenserComponent? compB) - || !_solutionSystem.TryGetSolution(beakerA, compA.Solution, out var solutionA) - || !_solutionSystem.TryGetSolution(beakerB, compB.Solution, out var solutionB) + || !_solutionContainerSystem.TryGetSolution(beakerA, compA.Solution, out var solnA, out var solutionA) + || !_solutionContainerSystem.TryGetSolution(beakerB, compB.Solution, out var solnB, out var solutionB) || solutionA.Volume == 0 || solutionB.Volume == 0) { @@ -155,17 +155,17 @@ public sealed class PayloadSystem : EntitySystem var solStringB = SolutionContainerSystem.ToPrettyString(solutionB); _adminLogger.Add(LogType.ChemicalReaction, - $"Chemical bomb payload {ToPrettyString(uid):payload} at {Transform(uid).MapPosition:location} is combining two solutions: {solStringA:solutionA} and {solStringB:solutionB}"); + $"Chemical bomb payload {ToPrettyString(entity.Owner):payload} at {Transform(entity.Owner).MapPosition:location} is combining two solutions: {solStringA:solutionA} and {solStringB:solutionB}"); solutionA.MaxVolume += solutionB.MaxVolume; - _solutionSystem.TryAddSolution(beakerA, solutionA, solutionB); - _solutionSystem.RemoveAllSolution(beakerB, solutionB); + _solutionContainerSystem.TryAddSolution(solnA.Value, solutionB); + _solutionContainerSystem.RemoveAllSolution(solnB.Value); // The grenade might be a dud. Redistribute solution: - var tmpSol = _solutionSystem.SplitSolution(beakerA, solutionA, solutionA.Volume * solutionB.MaxVolume / solutionA.MaxVolume); - _solutionSystem.TryAddSolution(beakerB, solutionB, tmpSol); + var tmpSol = _solutionContainerSystem.SplitSolution(solnA.Value, solutionA.Volume * solutionB.MaxVolume / solutionA.MaxVolume); + _solutionContainerSystem.TryAddSolution(solnB.Value, tmpSol); solutionA.MaxVolume -= solutionB.MaxVolume; - _solutionSystem.UpdateChemicals(beakerA, solutionA, false); + _solutionContainerSystem.UpdateChemicals(solnA.Value); args.Handled = true; } diff --git a/Content.Server/Power/EntitySystems/RiggableSystem.cs b/Content.Server/Power/EntitySystems/RiggableSystem.cs index 995aeb7700..26eaca80fe 100644 --- a/Content.Server/Power/EntitySystems/RiggableSystem.cs +++ b/Content.Server/Power/EntitySystems/RiggableSystem.cs @@ -13,7 +13,6 @@ namespace Content.Server.Power.EntitySystems; /// public sealed class RiggableSystem : EntitySystem { - [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!; [Dependency] private readonly ExplosionSystem _explosionSystem = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; @@ -22,17 +21,17 @@ public sealed class RiggableSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnMicrowaved); - SubscribeLocalEvent(OnSolutionChanged); + SubscribeLocalEvent(OnSolutionChanged); } - private void OnRejuvenate(EntityUid uid, RiggableComponent component, RejuvenateEvent args) + private void OnRejuvenate(Entity entity, ref RejuvenateEvent args) { - component.IsRigged = false; + entity.Comp.IsRigged = false; } - private void OnMicrowaved(EntityUid uid, RiggableComponent component, BeingMicrowavedEvent args) + private void OnMicrowaved(Entity entity, ref BeingMicrowavedEvent args) { - if (TryComp(uid, out var batteryComponent)) + if (TryComp(entity, out var batteryComponent)) { if (batteryComponent.CurrentCharge == 0) return; @@ -41,21 +40,21 @@ public sealed class RiggableSystem : EntitySystem args.Handled = true; // What the fuck are you doing??? - Explode(uid, batteryComponent, args.User); + Explode(entity.Owner, batteryComponent, args.User); } - private void OnSolutionChanged(EntityUid uid, RiggableComponent component, SolutionChangedEvent args) + private void OnSolutionChanged(Entity entity, ref SolutionContainerChangedEvent args) { - if (args.SolutionId != component.Solution) + if (args.SolutionId != entity.Comp.Solution) return; - var wasRigged = component.IsRigged; - var quantity = args.Solution.GetReagentQuantity(component.RequiredQuantity.Reagent); - component.IsRigged = quantity >= component.RequiredQuantity.Quantity; + var wasRigged = entity.Comp.IsRigged; + var quantity = args.Solution.GetReagentQuantity(entity.Comp.RequiredQuantity.Reagent); + entity.Comp.IsRigged = quantity >= entity.Comp.RequiredQuantity.Quantity; - if (component.IsRigged && !wasRigged) + if (entity.Comp.IsRigged && !wasRigged) { - _adminLogger.Add(LogType.Explosion, LogImpact.Medium, $"{ToPrettyString(uid)} has been rigged up to explode when used."); + _adminLogger.Add(LogType.Explosion, LogImpact.Medium, $"{ToPrettyString(entity.Owner)} has been rigged up to explode when used."); } } diff --git a/Content.Server/Power/Generator/ChemicalFuelGeneratorAdapterComponent.cs b/Content.Server/Power/Generator/ChemicalFuelGeneratorAdapterComponent.cs index abaf1c4d94..20d7149332 100644 --- a/Content.Server/Power/Generator/ChemicalFuelGeneratorAdapterComponent.cs +++ b/Content.Server/Power/Generator/ChemicalFuelGeneratorAdapterComponent.cs @@ -1,5 +1,5 @@ -using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -20,11 +20,17 @@ public sealed partial class ChemicalFuelGeneratorAdapterComponent : Component public string Reagent = "WeldingFuel"; /// - /// The solution on the to use. + /// The name of . /// [DataField("solution")] [ViewVariables(VVAccess.ReadWrite)] - public string Solution = "tank"; + public string SolutionName = "tank"; + + /// + /// The solution on the to use. + /// + [DataField("solutionRef")] + public Entity? Solution = null; /// /// Value to multiply reagent amount by to get fuel amount. diff --git a/Content.Server/Power/Generator/GeneratorSystem.cs b/Content.Server/Power/Generator/GeneratorSystem.cs index 7d88061f62..a23b0b8eed 100644 --- a/Content.Server/Power/Generator/GeneratorSystem.cs +++ b/Content.Server/Power/Generator/GeneratorSystem.cs @@ -1,10 +1,10 @@ using Content.Server.Audio; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Materials; using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; using Content.Shared.Popups; using Content.Shared.Power.Generator; @@ -65,23 +65,23 @@ public sealed class GeneratorSystem : SharedGeneratorSystem _materialStorage.EjectAllMaterial(uid); } - private void ChemicalEmpty(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, GeneratorEmpty args) + private void ChemicalEmpty(Entity entity, ref GeneratorEmpty args) { - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution)) + if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution)) return; - var spillSolution = _solutionContainer.SplitSolution(uid, solution, solution.Volume); - _puddle.TrySpillAt(uid, spillSolution, out _); + var spillSolution = _solutionContainer.SplitSolution(entity.Comp.Solution.Value, solution.Volume); + _puddle.TrySpillAt(entity.Owner, spillSolution, out _); } - private void ChemicalGetClogged(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, ref GeneratorGetCloggedEvent args) + private void ChemicalGetClogged(Entity entity, ref GeneratorGetCloggedEvent args) { - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution)) + if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution)) return; foreach (var reagentQuantity in solution) { - if (reagentQuantity.Reagent.Prototype != component.Reagent) + if (reagentQuantity.Reagent.Prototype != entity.Comp.Reagent) { args.Clogged = true; return; @@ -89,32 +89,29 @@ public sealed class GeneratorSystem : SharedGeneratorSystem } } - private void ChemicalUseFuel(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, GeneratorUseFuel args) + private void ChemicalUseFuel(Entity entity, ref GeneratorUseFuel args) { - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution)) + if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution)) return; - var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Value; + var availableReagent = solution.GetTotalPrototypeQuantity(entity.Comp.Reagent).Value; var toRemove = RemoveFractionalFuel( - ref component.FractionalReagent, + ref entity.Comp.FractionalReagent, args.FuelUsed, - component.Multiplier * FixedPoint2.Epsilon.Float(), + entity.Comp.Multiplier * FixedPoint2.Epsilon.Float(), availableReagent); - solution.RemoveReagent(component.Reagent, FixedPoint2.FromCents(toRemove)); + _solutionContainer.RemoveReagent(entity.Comp.Solution.Value, entity.Comp.Reagent, FixedPoint2.FromCents(toRemove)); } - private void ChemicalGetFuel( - EntityUid uid, - ChemicalFuelGeneratorAdapterComponent component, - ref GeneratorGetFuelEvent args) + private void ChemicalGetFuel(Entity entity, ref GeneratorGetFuelEvent args) { - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution)) + if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution)) return; - var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Float(); - var reagent = component.FractionalReagent * FixedPoint2.Epsilon.Float() + availableReagent; - args.Fuel = reagent * component.Multiplier; + var availableReagent = solution.GetTotalPrototypeQuantity(entity.Comp.Reagent).Float(); + var reagent = entity.Comp.FractionalReagent * FixedPoint2.Epsilon.Float() + availableReagent; + args.Fuel = reagent * entity.Comp.Multiplier; } private void SolidUseFuel(EntityUid uid, SolidFuelGeneratorAdapterComponent component, GeneratorUseFuel args) diff --git a/Content.Server/Stunnable/Systems/StunbatonSystem.cs b/Content.Server/Stunnable/Systems/StunbatonSystem.cs index 2ed30d8942..8064434031 100644 --- a/Content.Server/Stunnable/Systems/StunbatonSystem.cs +++ b/Content.Server/Stunnable/Systems/StunbatonSystem.cs @@ -25,49 +25,50 @@ namespace Content.Server.Stunnable.Systems base.Initialize(); SubscribeLocalEvent(OnExamined); - SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnSolutionChange); SubscribeLocalEvent(OnStaminaHitAttempt); SubscribeLocalEvent(TryTurnOn); SubscribeLocalEvent(ToggleDone); } - private void OnStaminaHitAttempt(EntityUid uid, StunbatonComponent component, ref StaminaDamageOnHitAttemptEvent args) + private void OnStaminaHitAttempt(Entity entity, ref StaminaDamageOnHitAttemptEvent args) { - if (!_itemToggle.IsActivated(uid) || - !TryComp(uid, out var battery) || !_battery.TryUseCharge(uid, component.EnergyPerUse, battery)) + if (!_itemToggle.IsActivated(entity.Owner) || + !TryComp(entity.Owner, out var battery) || !_battery.TryUseCharge(entity.Owner, entity.Comp.EnergyPerUse, battery)) { args.Cancelled = true; return; } - if (battery.CurrentCharge < component.EnergyPerUse) + if (battery.CurrentCharge < entity.Comp.EnergyPerUse) { - _itemToggle.Toggle(uid, predicted: false); + _itemToggle.Toggle(entity.Owner, predicted: false); } } - private void OnExamined(EntityUid uid, BatteryComponent battery, ExaminedEvent args) + private void OnExamined(Entity entity, ref ExaminedEvent args) { - var onMsg = _itemToggle.IsActivated(uid) + var onMsg = _itemToggle.IsActivated(entity.Owner) ? Loc.GetString("comp-stunbaton-examined-on") : Loc.GetString("comp-stunbaton-examined-off"); args.PushMarkup(onMsg); var chargeMessage = Loc.GetString("stunbaton-component-on-examine-charge", - ("charge", (int) (battery.CurrentCharge / battery.MaxCharge * 100))); + ("charge", (int) (entity.Comp.CurrentCharge / entity.Comp.MaxCharge * 100))); args.PushMarkup(chargeMessage); } - private void ToggleDone(EntityUid uid, StunbatonComponent comp, ref ItemToggleDoneEvent args) + private void ToggleDone(Entity entity, ref ItemToggleDoneEvent args) { - if (!TryComp(uid, out var item)) + if (!TryComp(entity, out var item)) return; - _item.SetHeldPrefix(uid, args.Activated ? "on" : "off", item); + + _item.SetHeldPrefix(entity.Owner, args.Activated ? "on" : "off", item); } - private void TryTurnOn(EntityUid uid, StunbatonComponent comp, ref ItemToggleActivateAttemptEvent args) + private void TryTurnOn(Entity entity, ref ItemToggleActivateAttemptEvent args) { - if (!TryComp(uid, out var battery) || battery.CurrentCharge < comp.EnergyPerUse) + if (!TryComp(entity, out var battery) || battery.CurrentCharge < entity.Comp.EnergyPerUse) { args.Cancelled = true; if (args.User != null) @@ -77,22 +78,22 @@ namespace Content.Server.Stunnable.Systems return; } - if (TryComp(uid, out var rig) && rig.IsRigged) + if (TryComp(entity, out var rig) && rig.IsRigged) { - _riggableSystem.Explode(uid, battery, args.User); + _riggableSystem.Explode(entity.Owner, battery, args.User); } } // https://github.com/space-wizards/space-station-14/pull/17288#discussion_r1241213341 - private void OnSolutionChange(EntityUid uid, StunbatonComponent component, SolutionChangedEvent args) + private void OnSolutionChange(Entity entity, ref SolutionContainerChangedEvent args) { // Explode if baton is activated and rigged. - if (!TryComp(uid, out var riggable) || - !TryComp(uid, out var battery)) + if (!TryComp(entity, out var riggable) || + !TryComp(entity, out var battery)) return; - if (_itemToggle.IsActivated(uid) && riggable.IsRigged) - _riggableSystem.Explode(uid, battery); + if (_itemToggle.IsActivated(entity.Owner) && riggable.IsRigged) + _riggableSystem.Explode(entity.Owner, battery); } private void SendPowerPulse(EntityUid target, EntityUid? user, EntityUid used) diff --git a/Content.Server/Tools/Components/WelderComponent.cs b/Content.Server/Tools/Components/WelderComponent.cs index a620fa2ef4..b0db2c58e8 100644 --- a/Content.Server/Tools/Components/WelderComponent.cs +++ b/Content.Server/Tools/Components/WelderComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Content.Shared.Tools.Components; @@ -9,35 +10,41 @@ namespace Content.Server.Tools.Components [RegisterComponent] public sealed partial class WelderComponent : SharedWelderComponent { + /// + /// Name of . + /// + [DataField("fuelSolution"), ViewVariables(VVAccess.ReadWrite)] + public string FuelSolutionName = "Welder"; + /// /// Solution on the entity that contains the fuel. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public string FuelSolution { get; private set; } = "Welder"; + [DataField("fuelSolutionRef")] + public Entity? FuelSolution = null; /// /// Reagent that will be used as fuel for welding. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public ProtoId FuelReagent { get; private set; } = "WeldingFuel"; + public ProtoId FuelReagent = "WeldingFuel"; /// /// Fuel consumption per second while the welder is active. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 FuelConsumption { get; private set; } = FixedPoint2.New(2.0f); + public FixedPoint2 FuelConsumption = FixedPoint2.New(2.0f); /// /// A fuel amount to be consumed when the welder goes from being unlit to being lit. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 FuelLitCost { get; private set; } = FixedPoint2.New(0.5f); + public FixedPoint2 FuelLitCost = FixedPoint2.New(0.5f); /// /// Sound played when refilling the welder. /// [DataField] - public SoundSpecifier WelderRefill { get; private set; } = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); + public SoundSpecifier WelderRefill = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); /// /// Whether the item is safe to refill while lit without exploding the tank. diff --git a/Content.Server/Tools/ToolSystem.Welder.cs b/Content.Server/Tools/ToolSystem.Welder.cs index f4eca32a3d..88037cedb4 100644 --- a/Content.Server/Tools/ToolSystem.Welder.cs +++ b/Content.Server/Tools/ToolSystem.Welder.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Server.Chemistry.Components; using Content.Server.IgnitionSource; using Content.Server.Tools.Components; @@ -12,6 +11,7 @@ using Content.Shared.Item; using Content.Shared.Item.ItemToggle; using Content.Shared.Tools.Components; using Robust.Shared.GameStates; +using System.Linq; namespace Content.Server.Tools { @@ -38,66 +38,67 @@ namespace Content.Server.Tools public (FixedPoint2 fuel, FixedPoint2 capacity) GetWelderFuelAndCapacity(EntityUid uid, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null) { if (!Resolve(uid, ref welder, ref solutionContainer) - || !_solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var fuelSolution, solutionContainer)) + || !_solutionContainer.ResolveSolution((uid, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var fuelSolution)) return (FixedPoint2.Zero, FixedPoint2.Zero); - return (_solutionContainer.GetTotalPrototypeQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume); + return (fuelSolution.GetTotalPrototypeQuantity(welder.FuelReagent), fuelSolution.MaxVolume); } - public void TryTurnOn(EntityUid uid, WelderComponent welder, ref ItemToggleActivateAttemptEvent args) + public void TryTurnOn(Entity entity, ref ItemToggleActivateAttemptEvent args) { - if (!_solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var solution) || - !TryComp(uid, out var transform)) + if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var solution) || + !TryComp(entity, out var transform)) { args.Cancelled = true; return; } - var fuel = solution.GetTotalPrototypeQuantity(welder.FuelReagent); + + var fuel = solution.GetTotalPrototypeQuantity(entity.Comp.FuelReagent); // Not enough fuel to lit welder. - if (fuel == FixedPoint2.Zero || fuel < welder.FuelLitCost) + if (fuel == FixedPoint2.Zero || fuel < entity.Comp.FuelLitCost) { if (args.User != null) { - _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-message"), uid, (EntityUid) args.User); + _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-message"), entity, (EntityUid) args.User); } args.Cancelled = true; return; } - solution.RemoveReagent(welder.FuelReagent, welder.FuelLitCost); + _solutionContainer.RemoveReagent(entity.Comp.FuelSolution.Value, entity.Comp.FuelReagent, entity.Comp.FuelLitCost); // Logging - _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(uid):welder} on"); + _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(entity.Owner):welder} on"); - _ignitionSource.SetIgnited(uid); + _ignitionSource.SetIgnited(entity.Owner); if (transform.GridUid is { } gridUid) { - var position = _transformSystem.GetGridOrMapTilePosition(uid, transform); - _atmosphereSystem.HotspotExpose(gridUid, position, 700, 50, uid, true); + var position = _transformSystem.GetGridOrMapTilePosition(entity.Owner, transform); + _atmosphereSystem.HotspotExpose(gridUid, position, 700, 50, entity.Owner, true); } - Dirty(uid, welder); + Dirty(entity); - _activeWelders.Add(uid); + _activeWelders.Add(entity); } - public void TurnOff(EntityUid uid, WelderComponent welder, ref ItemToggleDeactivateAttemptEvent args) + public void TurnOff(Entity entity, ref ItemToggleDeactivateAttemptEvent args) { // Logging - _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(uid):welder} off"); + _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(entity.Owner):welder} off"); - _ignitionSource.SetIgnited(uid, false); + _ignitionSource.SetIgnited(entity.Owner, false); - Dirty(uid, welder); + Dirty(entity); - _activeWelders.Remove(uid); + _activeWelders.Remove(entity); } - private void OnWelderExamine(EntityUid uid, WelderComponent welder, ExaminedEvent args) + private void OnWelderExamine(Entity entity, ref ExaminedEvent args) { - if (_itemToggle.IsActivated(uid)) + if (_itemToggle.IsActivated(entity.Owner)) { args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message")); } @@ -108,7 +109,7 @@ namespace Content.Server.Tools if (args.IsInDetailsRange) { - var (fuel, capacity) = GetWelderFuelAndCapacity(uid, welder); + var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp); args.PushMarkup(Loc.GetString("welder-component-on-examine-detailed-message", ("colorName", fuel < capacity / FixedPoint2.New(4f) ? "darkorange" : "orange"), @@ -118,7 +119,7 @@ namespace Content.Server.Tools } } - private void OnWelderAfterInteract(EntityUid uid, WelderComponent welder, AfterInteractEvent args) + private void OnWelderAfterInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled) return; @@ -128,49 +129,49 @@ namespace Content.Server.Tools if (TryComp(target, out ReagentTankComponent? tank) && tank.TankType == ReagentTankType.Fuel - && _solutionContainer.TryGetDrainableSolution(target, out var targetSolution) - && _solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var welderSolution)) + && _solutionContainer.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution) + && _solutionContainer.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var welderSolution)) { var trans = FixedPoint2.Min(welderSolution.AvailableVolume, targetSolution.Volume); if (trans > 0) { - var drained = _solutionContainer.Drain(target, targetSolution, trans); - _solutionContainer.TryAddSolution(uid, welderSolution, drained); - _audio.PlayPvs(welder.WelderRefill, uid); - _popup.PopupEntity(Loc.GetString("welder-component-after-interact-refueled-message"), uid, args.User); + var drained = _solutionContainer.Drain(target, targetSoln.Value, trans); + _solutionContainer.TryAddSolution(entity.Comp.FuelSolution.Value, drained); + _audio.PlayPvs(entity.Comp.WelderRefill, entity); + _popup.PopupEntity(Loc.GetString("welder-component-after-interact-refueled-message"), entity, args.User); } else if (welderSolution.AvailableVolume <= 0) { - _popup.PopupEntity(Loc.GetString("welder-component-already-full"), uid, args.User); + _popup.PopupEntity(Loc.GetString("welder-component-already-full"), entity, args.User); } else { - _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), uid, args.User); + _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), entity, args.User); } } args.Handled = true; } - private void OnWelderToolUseAttempt(EntityUid uid, WelderComponent welder, DoAfterAttemptEvent args) + private void OnWelderToolUseAttempt(Entity entity, ref DoAfterAttemptEvent args) { var user = args.DoAfter.Args.User; - if (!_itemToggle.IsActivated(uid)) + if (!_itemToggle.IsActivated(entity.Owner)) { - _popup.PopupEntity(Loc.GetString("welder-component-welder-not-lit-message"), uid, user); + _popup.PopupEntity(Loc.GetString("welder-component-welder-not-lit-message"), entity, user); args.Cancel(); } } - private void OnWelderShutdown(EntityUid uid, WelderComponent welder, ComponentShutdown args) + private void OnWelderShutdown(Entity entity, ref ComponentShutdown args) { - _activeWelders.Remove(uid); + _activeWelders.Remove(entity); } - private void OnWelderGetState(EntityUid uid, WelderComponent welder, ref ComponentGetState args) + private void OnWelderGetState(Entity entity, ref ComponentGetState args) { - var (fuel, capacity) = GetWelderFuelAndCapacity(uid, welder); + var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp); args.State = new WelderComponentState(capacity.Float(), fuel.Float()); } @@ -188,10 +189,10 @@ namespace Content.Server.Tools || !TryComp(tool, out SolutionContainerManagerComponent? solutionContainer)) continue; - if (!_solutionContainer.TryGetSolution(tool, welder.FuelSolution, out var solution, solutionContainer)) + if (!_solutionContainer.ResolveSolution((tool, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var solution)) continue; - solution.RemoveReagent(welder.FuelReagent, welder.FuelConsumption * _welderTimer); + _solutionContainer.RemoveReagent(welder.FuelSolution.Value, welder.FuelReagent, welder.FuelConsumption * _welderTimer); if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero) { diff --git a/Content.Server/Tools/ToolSystem.cs b/Content.Server/Tools/ToolSystem.cs index 7366bfce40..6153b579a1 100644 --- a/Content.Server/Tools/ToolSystem.cs +++ b/Content.Server/Tools/ToolSystem.cs @@ -1,13 +1,11 @@ using Content.Server.Atmos.EntitySystems; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Popups; using Content.Server.Tools.Components; -using Content.Shared.Chemistry.EntitySystems; -using Content.Shared.Maps; -using Content.Shared.Tools; using Robust.Server.GameObjects; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; + using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; namespace Content.Server.Tools diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index 0e085cdfe0..1c672796c6 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -1,15 +1,13 @@ -using System.Linq; -using System.Numerics; using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chat.Systems; using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.CombatMode.Disarm; using Content.Server.Contests; using Content.Server.Movement.Systems; using Content.Shared.Actions.Events; using Content.Shared.Administration.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.CombatMode; using Content.Shared.Damage.Events; using Content.Shared.Damage.Systems; @@ -29,6 +27,8 @@ using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Random; +using System.Linq; +using System.Numerics; namespace Content.Server.Weapons.Melee; @@ -250,11 +250,11 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem } - private void OnChemicalInjectorHit(EntityUid owner, MeleeChemicalInjectorComponent comp, MeleeHitEvent args) + private void OnChemicalInjectorHit(Entity entity, ref MeleeHitEvent args) { if (!args.IsHit || !args.HitEntities.Any() || - !_solutions.TryGetSolution(owner, comp.Solution, out var solutionContainer)) + !_solutions.TryGetSolution(entity.Owner, entity.Comp.Solution, out var solutionContainer)) { return; } @@ -262,28 +262,28 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem var hitBloodstreams = new List<(EntityUid Entity, BloodstreamComponent Component)>(); var bloodQuery = GetEntityQuery(); - foreach (var entity in args.HitEntities) + foreach (var hit in args.HitEntities) { - if (Deleted(entity)) + if (Deleted(hit)) continue; // prevent deathnettles injecting through hardsuits - if (!comp.PierceArmor && _inventory.TryGetSlotEntity(entity, "outerClothing", out var suit) && _tag.HasTag(suit.Value, "Hardsuit")) + if (!entity.Comp.PierceArmor && _inventory.TryGetSlotEntity(hit, "outerClothing", out var suit) && _tag.HasTag(suit.Value, "Hardsuit")) { - PopupSystem.PopupEntity(Loc.GetString("melee-inject-failed-hardsuit", ("weapon", owner)), args.User, args.User, PopupType.SmallCaution); + PopupSystem.PopupEntity(Loc.GetString("melee-inject-failed-hardsuit", ("weapon", entity.Owner)), args.User, args.User, PopupType.SmallCaution); continue; } - if (bloodQuery.TryGetComponent(entity, out var bloodstream)) - hitBloodstreams.Add((entity, bloodstream)); + if (bloodQuery.TryGetComponent(hit, out var bloodstream)) + hitBloodstreams.Add((hit, bloodstream)); } if (!hitBloodstreams.Any()) return; - var removedSolution = solutionContainer.SplitSolution(comp.TransferAmount * hitBloodstreams.Count); + var removedSolution = _solutions.SplitSolution(solutionContainer.Value, entity.Comp.TransferAmount * hitBloodstreams.Count); var removedVol = removedSolution.Volume; - var solutionToInject = removedSolution.SplitSolution(removedVol * comp.TransferEfficiency); + var solutionToInject = removedSolution.SplitSolution(removedVol * entity.Comp.TransferEfficiency); var volPerBloodstream = solutionToInject.Volume * (1 / hitBloodstreams.Count); foreach (var (ent, bloodstream) in hitBloodstreams) diff --git a/Content.Server/Weapons/Ranged/Systems/ChemicalAmmoSystem.cs b/Content.Server/Weapons/Ranged/Systems/ChemicalAmmoSystem.cs index 3d8601cc8e..e896e2b373 100644 --- a/Content.Server/Weapons/Ranged/Systems/ChemicalAmmoSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/ChemicalAmmoSystem.cs @@ -1,34 +1,34 @@ -using System.Linq; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Weapons.Ranged.Components; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Weapons.Ranged.Events; +using System.Linq; namespace Content.Server.Weapons.Ranged.Systems { public sealed class ChemicalAmmoSystem : EntitySystem { - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; public override void Initialize() { SubscribeLocalEvent(OnFire); } - private void OnFire(EntityUid uid, ChemicalAmmoComponent component, AmmoShotEvent args) + private void OnFire(Entity entity, ref AmmoShotEvent args) { - if (!_solutionSystem.TryGetSolution(uid, component.SolutionName, out var ammoSolution)) + if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var ammoSoln, out var ammoSolution)) return; var projectiles = args.FiredProjectiles; - var projectileSolutionContainers = new List<(EntityUid, Solution)>(); + var projectileSolutionContainers = new List<(EntityUid, Entity)>(); foreach (var projectile in projectiles) { - if (_solutionSystem - .TryGetSolution(projectile, component.SolutionName, out var projectileSolutionContainer)) + if (_solutionContainerSystem + .TryGetSolution(projectile, entity.Comp.SolutionName, out var projectileSoln, out _)) { - projectileSolutionContainers.Add((uid, projectileSolutionContainer)); + projectileSolutionContainers.Add((projectile, projectileSoln.Value)); } } @@ -37,13 +37,13 @@ namespace Content.Server.Weapons.Ranged.Systems var solutionPerProjectile = ammoSolution.Volume * (1 / projectileSolutionContainers.Count); - foreach (var (projectileUid, projectileSolution) in projectileSolutionContainers) + foreach (var (_, projectileSolution) in projectileSolutionContainers) { - var solutionToTransfer = _solutionSystem.SplitSolution(uid, ammoSolution, solutionPerProjectile); - _solutionSystem.TryAddSolution(projectileUid, projectileSolution, solutionToTransfer); + var solutionToTransfer = _solutionContainerSystem.SplitSolution(ammoSoln.Value, solutionPerProjectile); + _solutionContainerSystem.TryAddSolution(projectileSolution, solutionToTransfer); } - _solutionSystem.RemoveAllSolution(uid, ammoSolution); + _solutionContainerSystem.RemoveAllSolution(ammoSoln.Value); } } } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Solution.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Solution.cs index 734a01602c..7ad4b15ffc 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Solution.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Solution.cs @@ -1,4 +1,5 @@ using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; @@ -18,29 +19,29 @@ public sealed partial class GunSystem base.InitializeSolution(); SubscribeLocalEvent(OnSolutionMapInit); - SubscribeLocalEvent(OnSolutionChanged); + SubscribeLocalEvent(OnSolutionChanged); } - private void OnSolutionMapInit(EntityUid uid, SolutionAmmoProviderComponent component, MapInitEvent args) + private void OnSolutionMapInit(Entity entity, ref MapInitEvent args) { - UpdateSolutionShots(uid, component); + UpdateSolutionShots(entity.Owner, entity.Comp); } - private void OnSolutionChanged(EntityUid uid, SolutionAmmoProviderComponent component, SolutionChangedEvent args) + private void OnSolutionChanged(Entity entity, ref SolutionContainerChangedEvent args) { - if (args.Solution.Name == component.SolutionId) - UpdateSolutionShots(uid, component, args.Solution); + if (args.Solution.Name == entity.Comp.SolutionId) + UpdateSolutionShots(entity.Owner, entity.Comp, args.Solution); } protected override void UpdateSolutionShots(EntityUid uid, SolutionAmmoProviderComponent component, Solution? solution = null) { var shots = 0; var maxShots = 0; - if (solution == null && !_solutionContainer.TryGetSolution(uid, component.SolutionId, out solution)) + if (solution == null && !_solutionContainer.TryGetSolution(uid, component.SolutionId, out _, out solution)) { component.Shots = shots; component.MaxShots = maxShots; - Dirty(component); + Dirty(uid, component); return; } @@ -49,7 +50,7 @@ public sealed partial class GunSystem component.Shots = shots; component.MaxShots = maxShots; - Dirty(component); + Dirty(uid, component); UpdateSolutionAppearance(uid, component); } @@ -58,10 +59,10 @@ public sealed partial class GunSystem { var (ent, shootable) = base.GetSolutionShot(uid, component, position); - if (!_solutionContainer.TryGetSolution(uid, component.SolutionId, out var solution)) + if (!_solutionContainer.TryGetSolution(uid, component.SolutionId, out var solution, out _)) return (ent, shootable); - var newSolution = _solutionContainer.SplitSolution(uid, solution, component.FireCost); + var newSolution = _solutionContainer.SplitSolution(solution.Value, component.FireCost); if (newSolution.Volume <= FixedPoint2.Zero) return (ent, shootable); @@ -73,9 +74,9 @@ public sealed partial class GunSystem } // Add the solution to the vapor and actually send the thing - if (_solutionContainer.TryGetSolution(ent, VaporComponent.SolutionName, out var vaporSolution)) + if (_solutionContainer.TryGetSolution(ent, VaporComponent.SolutionName, out var vaporSolution, out _)) { - _solutionContainer.TryAddSolution(ent, vaporSolution, newSolution); + _solutionContainer.TryAddSolution(vaporSolution.Value, newSolution); } return (ent, shootable); } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/ChemicalPuddleArtifactComponent.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/ChemicalPuddleArtifactComponent.cs index 1e40807f6e..3065b1c417 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/ChemicalPuddleArtifactComponent.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/ChemicalPuddleArtifactComponent.cs @@ -1,8 +1,6 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; diff --git a/Content.Shared/Administration/EditSolutionsEuiState.cs b/Content.Shared/Administration/EditSolutionsEuiState.cs index 782c4b84f2..12fae34962 100644 --- a/Content.Shared/Administration/EditSolutionsEuiState.cs +++ b/Content.Shared/Administration/EditSolutionsEuiState.cs @@ -1,6 +1,5 @@ using Content.Shared.Eui; using Robust.Shared.Serialization; -using Content.Shared.Chemistry.Components; namespace Content.Shared.Administration { @@ -8,9 +7,9 @@ namespace Content.Shared.Administration public sealed class EditSolutionsEuiState : EuiStateBase { public readonly NetEntity Target; - public readonly Dictionary? Solutions; + public readonly List<(string, NetEntity)>? Solutions; - public EditSolutionsEuiState(NetEntity target, Dictionary? solutions) + public EditSolutionsEuiState(NetEntity target, List<(string, NetEntity)>? solutions) { Target = target; Solutions = solutions; diff --git a/Content.Shared/Chemistry/Components/DrainableSolutionComponent.cs b/Content.Shared/Chemistry/Components/DrainableSolutionComponent.cs index 4cdff566f6..0a6ace0943 100644 --- a/Content.Shared/Chemistry/Components/DrainableSolutionComponent.cs +++ b/Content.Shared/Chemistry/Components/DrainableSolutionComponent.cs @@ -12,7 +12,6 @@ public sealed partial class DrainableSolutionComponent : Component /// /// Solution name that can be drained. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("solution")] - public string Solution { get; set; } = "default"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; } diff --git a/Content.Shared/Chemistry/Components/DumpableSolutionComponent.cs b/Content.Shared/Chemistry/Components/DumpableSolutionComponent.cs index ad9e1f19a6..43fbe137b6 100644 --- a/Content.Shared/Chemistry/Components/DumpableSolutionComponent.cs +++ b/Content.Shared/Chemistry/Components/DumpableSolutionComponent.cs @@ -12,14 +12,12 @@ public sealed partial class DumpableSolutionComponent : Component /// /// Solution name that can be dumped into. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("solution")] - public string Solution { get; set; } = "default"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; /// /// Whether the solution can be dumped into infinitely. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("unlimited")] - public bool Unlimited { get; set; } = false; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool Unlimited = false; } diff --git a/Content.Shared/Chemistry/Components/FitsInDispenserComponent.cs b/Content.Shared/Chemistry/Components/FitsInDispenserComponent.cs index a479dcdbe8..f295dcc5bd 100644 --- a/Content.Shared/Chemistry/Components/FitsInDispenserComponent.cs +++ b/Content.Shared/Chemistry/Components/FitsInDispenserComponent.cs @@ -1,23 +1,21 @@ using Robust.Shared.GameStates; -namespace Content.Shared.Chemistry.Components +namespace Content.Shared.Chemistry.Components; + +/// +/// Allows the entity with this component to be placed in a SharedReagentDispenserComponent. +/// Otherwise it's considered to be too large or the improper shape to fit. +/// Allows us to have obscenely large containers that are harder to abuse in chem dispensers +/// since they can't be placed directly in them. +/// +/// +[RegisterComponent] +[NetworkedComponent] // only needed for white-lists. Client doesn't actually need Solution data; +public sealed partial class FitsInDispenserComponent : Component { /// - /// Allows the entity with this component to be placed in a SharedReagentDispenserComponent. - /// Otherwise it's considered to be too large or the improper shape to fit. - /// Allows us to have obscenely large containers that are harder to abuse in chem dispensers - /// since they can't be placed directly in them. - /// + /// Solution name that will interact with ReagentDispenserComponent. /// - [RegisterComponent] - [NetworkedComponent] // only needed for white-lists. Client doesn't actually need Solution data; - public sealed partial class FitsInDispenserComponent : Component - { - /// - /// Solution name that will interact with ReagentDispenserComponent. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("solution")] - public string Solution { get; set; } = "default"; - } + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; } diff --git a/Content.Shared/Chemistry/Components/RefillableSolutionComponent.cs b/Content.Shared/Chemistry/Components/RefillableSolutionComponent.cs index cb5ab7679d..245b7398a7 100644 --- a/Content.Shared/Chemistry/Components/RefillableSolutionComponent.cs +++ b/Content.Shared/Chemistry/Components/RefillableSolutionComponent.cs @@ -14,14 +14,12 @@ public sealed partial class RefillableSolutionComponent : Component /// /// Solution name that can added to easily. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("solution")] - public string Solution { get; set; } = "default"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; /// /// The maximum amount that can be transferred to the solution at once /// - [DataField("maxRefill")] - [ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2? MaxRefill { get; set; } = null; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2? MaxRefill = null; } diff --git a/Content.Shared/Chemistry/Components/SmokeComponent.cs b/Content.Shared/Chemistry/Components/SmokeComponent.cs index 9d88fcac94..f07a77c1ac 100644 --- a/Content.Shared/Chemistry/Components/SmokeComponent.cs +++ b/Content.Shared/Chemistry/Components/SmokeComponent.cs @@ -13,6 +13,12 @@ public sealed partial class SmokeComponent : Component { public const string SolutionName = "solutionArea"; + /// + /// The solution on the entity with touch and ingestion reactions. + /// + [DataField] + public Entity? Solution = null; + /// /// The max amount of tiles this smoke cloud can spread to. /// diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs index ca597710d4..8598e1ad99 100644 --- a/Content.Shared/Chemistry/Components/Solution.cs +++ b/Content.Shared/Chemistry/Components/Solution.cs @@ -71,6 +71,7 @@ namespace Content.Shared.Chemistry.Components /// /// The name of this solution, if it is contained in some /// + [DataField] public string? Name; /// @@ -100,7 +101,7 @@ namespace Content.Shared.Chemistry.Components foreach (var (reagent, quantity) in Contents) { _heatCapacity += (float) quantity * - protoMan.Index(reagent.Prototype).SpecificHeat; + protoMan.Index(reagent.Prototype).SpecificHeat; } } @@ -158,10 +159,12 @@ namespace Content.Shared.Chemistry.Components public Solution(Solution solution) { + Contents = solution.Contents.ShallowClone(); Volume = solution.Volume; + MaxVolume = solution.MaxVolume; + Temperature = solution.Temperature; _heatCapacity = solution._heatCapacity; _heatCapacityDirty = solution._heatCapacityDirty; - Contents = solution.Contents.ShallowClone(); ValidateSolution(); } @@ -174,7 +177,7 @@ namespace Content.Shared.Chemistry.Components public void ValidateSolution() { // sandbox forbids: [Conditional("DEBUG")] -#if DEBUG + #if DEBUG // Correct volume DebugTools.Assert(Contents.Select(x => x.Quantity).Sum() == Volume); @@ -192,7 +195,7 @@ namespace Content.Shared.Chemistry.Components UpdateHeatCapacity(null); DebugTools.Assert(MathHelper.CloseTo(_heatCapacity, cur)); } -#endif + #endif } void ISerializationHooks.AfterDeserialization() diff --git a/Content.Shared/Chemistry/Components/SolutionComponent.cs b/Content.Shared/Chemistry/Components/SolutionComponent.cs new file mode 100644 index 0000000000..687a545b00 --- /dev/null +++ b/Content.Shared/Chemistry/Components/SolutionComponent.cs @@ -0,0 +1,22 @@ +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Materials; +using Robust.Shared.GameStates; + +namespace Content.Shared.Chemistry.Components; + +/// +/// Holds the composition of an entity made from reagents and its reagent temperature. +/// If the entity is used to represent a collection of reagents inside of a container such as a beaker, syringe, bloodstream, food, or similar the entity is tracked by a on the container and has a tracking which container it's in. +/// +/// +/// Once reagents and materials have been merged this component should be depricated in favor of using a combination of and . May require minor reworks to both. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class SolutionComponent : Component +{ + /// + /// The reagents the entity is composed of and their temperature. + /// + [DataField, AutoNetworkedField] + public Solution Solution = new(); +} diff --git a/Content.Shared/Chemistry/Components/SolutionManager/ContainedSolutionComponent.cs b/Content.Shared/Chemistry/Components/SolutionManager/ContainedSolutionComponent.cs new file mode 100644 index 0000000000..d648a9f00c --- /dev/null +++ b/Content.Shared/Chemistry/Components/SolutionManager/ContainedSolutionComponent.cs @@ -0,0 +1,31 @@ +using Content.Shared.Chemistry.EntitySystems; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chemistry.Components.SolutionManager; + +/// +/// Component used to relate a solution to its container. +/// +/// +/// When containers are finally ECS'd have this attach to the container entity. +/// The field should then be extracted out into this component. +/// Solution entities would just become an apporpriately composed entity hanging out in the container. +/// Will probably require entities in components being given a relation to associate themselves with their container. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedSolutionContainerSystem))] +public sealed partial class ContainedSolutionComponent : Component +{ + /// + /// The entity that the solution is contained in. + /// + [DataField(required: true), AutoNetworkedField] + public EntityUid Container; + + /// + /// The name/key of the container the solution is located in. + /// + [DataField(required: true), AutoNetworkedField] + public string ContainerName = default!; +} diff --git a/Content.Shared/Chemistry/Components/SolutionManager/DrawableSolutionComponent.cs b/Content.Shared/Chemistry/Components/SolutionManager/DrawableSolutionComponent.cs index f9cd6e8e8e..a949ae72e2 100644 --- a/Content.Shared/Chemistry/Components/SolutionManager/DrawableSolutionComponent.cs +++ b/Content.Shared/Chemistry/Components/SolutionManager/DrawableSolutionComponent.cs @@ -9,7 +9,6 @@ public sealed partial class DrawableSolutionComponent : Component /// /// Solution name that can be removed with syringes. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("solution")] - public string Solution { get; set; } = "default"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; } diff --git a/Content.Shared/Chemistry/Components/SolutionManager/ExaminableSolutionComponent.cs b/Content.Shared/Chemistry/Components/SolutionManager/ExaminableSolutionComponent.cs index b12a5bd6e4..76e7967db2 100644 --- a/Content.Shared/Chemistry/Components/SolutionManager/ExaminableSolutionComponent.cs +++ b/Content.Shared/Chemistry/Components/SolutionManager/ExaminableSolutionComponent.cs @@ -3,7 +3,6 @@ [RegisterComponent] public sealed partial class ExaminableSolutionComponent : Component { - [ViewVariables(VVAccess.ReadWrite)] - [DataField("solution")] - public string Solution { get; set; } = "default"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; } diff --git a/Content.Shared/Chemistry/Components/SolutionManager/InjectableSolutionComponent.cs b/Content.Shared/Chemistry/Components/SolutionManager/InjectableSolutionComponent.cs index a696244956..97266764dc 100644 --- a/Content.Shared/Chemistry/Components/SolutionManager/InjectableSolutionComponent.cs +++ b/Content.Shared/Chemistry/Components/SolutionManager/InjectableSolutionComponent.cs @@ -10,7 +10,6 @@ public sealed partial class InjectableSolutionComponent : Component /// /// Solution name which can be added with syringes. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("solution")] - public string Solution { get; set; } = "default"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; } diff --git a/Content.Shared/Chemistry/Components/SolutionManager/SolutionContainerManagerComponent.cs b/Content.Shared/Chemistry/Components/SolutionManager/SolutionContainerManagerComponent.cs index 9dfa4a71fd..fe62555f0d 100644 --- a/Content.Shared/Chemistry/Components/SolutionManager/SolutionContainerManagerComponent.cs +++ b/Content.Shared/Chemistry/Components/SolutionManager/SolutionContainerManagerComponent.cs @@ -1,12 +1,36 @@ using Content.Shared.Chemistry.EntitySystems; +using Robust.Shared.Containers; +using Robust.Shared.GameStates; namespace Content.Shared.Chemistry.Components.SolutionManager; -[RegisterComponent] -[Access(typeof(SolutionContainerSystem))] +/// +/// A map of the solution entities contained within this entity. +/// Every solution entity this maps should have a to track its state and a to track its container. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedSolutionContainerSystem))] public sealed partial class SolutionContainerManagerComponent : Component { - [DataField("solutions")] - [Access(typeof(SolutionContainerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public Dictionary Solutions = new(); + /// + /// The default amount of space that will be allocated for solutions in solution containers. + /// Most solution containers will only contain 1-2 solutions. + /// + public const int DefaultCapacity = 2; + + /// + /// The names of each solution container attached to this entity. + /// Actually accessing them must be done via . + /// + [DataField, AutoNetworkedField] + public HashSet Containers = new(DefaultCapacity); + + /// + /// The set of solutions to load onto this entity during mapinit. + /// + /// + /// Should be null after mapinit. + /// + [DataField(serverOnly: true)] // Needs to be serverOnly or these will get loaded on the client and never cleared. Can be reworked when entity spawning is predicted. + public Dictionary? Solutions = null; } diff --git a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerMixerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerMixerSystem.cs index 14c4560dd8..8795706612 100644 --- a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerMixerSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerMixerSystem.cs @@ -20,7 +20,7 @@ public abstract class SharedSolutionContainerMixerSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SolutionContainerSystem _solution = default!; + [Dependency] private readonly SharedSolutionContainerSystem _solution = default!; /// public override void Initialize() @@ -98,10 +98,10 @@ public abstract class SharedSolutionContainerMixerSystem : EntitySystem foreach (var ent in container.ContainedEntities) { - if (!_solution.TryGetFitsInDispenser(ent, out var solution)) + if (!_solution.TryGetFitsInDispenser(ent, out var soln, out _)) continue; - _solution.UpdateChemicals(ent, solution, true, reactionMixer); + _solution.UpdateChemicals(soln.Value, true, reactionMixer); } } diff --git a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Capabilities.cs b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Capabilities.cs new file mode 100644 index 0000000000..0d4912a504 --- /dev/null +++ b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Capabilities.cs @@ -0,0 +1,183 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.FixedPoint; +using Robust.Shared.Utility; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Content.Shared.Chemistry.EntitySystems; + +public abstract partial class SharedSolutionContainerSystem +{ + #region Solution Accessors + + public bool TryGetRefillableSolution(Entity entity, [NotNullWhen(true)] out Entity? soln, [NotNullWhen(true)] out Solution? solution) + { + if (!Resolve(entity, ref entity.Comp1, logMissing: false)) + { + (soln, solution) = (default!, null); + return false; + } + + return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution); + } + + public bool TryGetDrainableSolution(Entity entity, [NotNullWhen(true)] out Entity? soln, [NotNullWhen(true)] out Solution? solution) + { + if (!Resolve(entity, ref entity.Comp1, logMissing: false)) + { + (soln, solution) = (default!, null); + return false; + } + + return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution); + } + + public bool TryGetDumpableSolution(Entity entity, [NotNullWhen(true)] out Entity? soln, [NotNullWhen(true)] out Solution? solution) + { + if (!Resolve(entity, ref entity.Comp1, logMissing: false)) + { + (soln, solution) = (default!, null); + return false; + } + + return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution); + } + + public bool TryGetDrawableSolution(Entity entity, [NotNullWhen(true)] out Entity? soln, [NotNullWhen(true)] out Solution? solution) + { + if (!Resolve(entity, ref entity.Comp1, logMissing: false)) + { + (soln, solution) = (default!, null); + return false; + } + + return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution); + } + + public bool TryGetInjectableSolution(Entity entity, [NotNullWhen(true)] out Entity? soln, [NotNullWhen(true)] out Solution? solution) + { + if (!Resolve(entity, ref entity.Comp1, logMissing: false)) + { + (soln, solution) = (default!, null); + return false; + } + + return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution); + } + + public bool TryGetFitsInDispenser(Entity entity, [NotNullWhen(true)] out Entity? soln, [NotNullWhen(true)] out Solution? solution) + { + if (!Resolve(entity, ref entity.Comp1, logMissing: false)) + { + (soln, solution) = (default!, null); + return false; + } + + return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution); + } + + public bool TryGetMixableSolution(Entity container, [NotNullWhen(true)] out Entity? solution) + { + var getMixableSolutionAttempt = new GetMixableSolutionAttemptEvent(container); + RaiseLocalEvent(container, ref getMixableSolutionAttempt); + if (getMixableSolutionAttempt.MixedSolution != null) + { + solution = getMixableSolutionAttempt.MixedSolution; + return true; + } + + if (!Resolve(container, ref container.Comp, false)) + { + solution = default!; + return false; + } + + var tryGetSolution = EnumerateSolutions(container).FirstOrNull(x => x.Solution.Comp.Solution.CanMix); + if (tryGetSolution.HasValue) + { + solution = tryGetSolution.Value.Solution; + return true; + } + + solution = default!; + return false; + } + + #endregion Solution Accessors + + #region Solution Modifiers + + public void Refill(Entity entity, Entity soln, Solution refill) + { + if (!Resolve(entity, ref entity.Comp, logMissing: false)) + return; + + AddSolution(soln, refill); + } + + public void Inject(Entity entity, Entity soln, Solution inject) + { + if (!Resolve(entity, ref entity.Comp, logMissing: false)) + return; + + AddSolution(soln, inject); + } + + public Solution Drain(Entity entity, Entity soln, FixedPoint2 quantity) + { + if (!Resolve(entity, ref entity.Comp, logMissing: false)) + return new(); + + return SplitSolution(soln, quantity); + } + + public Solution Draw(Entity entity, Entity soln, FixedPoint2 quantity) + { + if (!Resolve(entity, ref entity.Comp, logMissing: false)) + return new(); + + return SplitSolution(soln, quantity); + } + + #endregion Solution Modifiers + + public float PercentFull(EntityUid uid) + { + if (!TryGetDrainableSolution(uid, out _, out var solution) || solution.MaxVolume.Equals(FixedPoint2.Zero)) + return 0; + + return solution.FillFraction * 100; + } + + #region Static Methods + + public static string ToPrettyString(Solution solution) + { + var sb = new StringBuilder(); + if (solution.Name == null) + sb.Append("["); + else + sb.Append($"{solution.Name}:["); + var first = true; + foreach (var (id, quantity) in solution.Contents) + { + if (first) + { + first = false; + } + else + { + sb.Append(", "); + } + + sb.AppendFormat("{0}: {1}u", id, quantity); + } + + sb.Append(']'); + return sb.ToString(); + } + + #endregion Static Methods +} diff --git a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Relays.cs b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Relays.cs new file mode 100644 index 0000000000..e6e96fa80a --- /dev/null +++ b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Relays.cs @@ -0,0 +1,148 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.FixedPoint; + +namespace Content.Shared.Chemistry.EntitySystems; + +#region Events + +/// +/// This event alerts system that the solution was changed +/// +[ByRefEvent] +public record struct SolutionContainerChangedEvent +{ + public readonly Solution Solution; + public readonly string SolutionId; + + public SolutionContainerChangedEvent(Solution solution, string solutionId) + { + SolutionId = solutionId; + Solution = solution; + } +} + +/// +/// An event raised when more reagents are added to a (managed) solution than it can hold. +/// +[ByRefEvent] +public record struct SolutionContainerOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow) +{ + /// The entity which contains the solution that has overflowed. + public readonly EntityUid SolutionEnt = SolutionEnt; + /// The solution that has overflowed. + public readonly Solution SolutionHolder = SolutionHolder; + /// The reagents that have overflowed the solution. + public readonly Solution Overflow = Overflow; + /// The volume by which the solution has overflowed. + public readonly FixedPoint2 OverflowVol = Overflow.Volume; + /// Whether some subscriber has taken care of the effects of the overflow. + public bool Handled = false; +} + +/// +/// Ref event used to relay events raised on solution entities to their containers. +/// +/// +/// The event that is being relayed. +/// The container entity that the event is being relayed to. +/// The name of the solution entity that the event is being relayed from. +[ByRefEvent] +public record struct SolutionRelayEvent(TEvent Event, EntityUid ContainerEnt, string Name) +{ + public readonly EntityUid ContainerEnt = ContainerEnt; + public readonly string Name = Name; + public TEvent Event = Event; +} + +/// +/// Ref event used to relay events raised on solution containers to their contained solutions. +/// +/// +/// The event that is being relayed. +/// The solution entity that the event is being relayed to. +/// The name of the solution entity that the event is being relayed to. +[ByRefEvent] +public record struct SolutionContainerRelayEvent(TEvent Event, Entity SolutionEnt, string Name) +{ + public readonly Entity SolutionEnt = SolutionEnt; + public readonly string Name = Name; + public TEvent Event = Event; +} + +#endregion Events + +public abstract partial class SharedSolutionContainerSystem +{ + protected void InitializeRelays() + { + SubscribeLocalEvent(OnSolutionChanged); + SubscribeLocalEvent(OnSolutionOverflow); + SubscribeLocalEvent(RelaySolutionRefEvent); + } + + #region Event Handlers + + protected virtual void OnSolutionChanged(Entity entity, ref SolutionChangedEvent args) + { + var (solutionId, solutionComp) = args.Solution; + var solution = solutionComp.Solution; + + UpdateAppearance(entity.Comp.Container, (solutionId, solutionComp, entity.Comp)); + + var relayEvent = new SolutionContainerChangedEvent(solution, entity.Comp.ContainerName); + RaiseLocalEvent(entity.Comp.Container, ref relayEvent); + } + + protected virtual void OnSolutionOverflow(Entity entity, ref SolutionOverflowEvent args) + { + var solution = args.Solution.Comp.Solution; + var overflow = solution.SplitSolution(args.Overflow); + var relayEv = new SolutionContainerOverflowEvent(entity.Owner, solution, overflow) + { + Handled = args.Handled, + }; + + RaiseLocalEvent(entity.Comp.Container, ref relayEv); + args.Handled = relayEv.Handled; + } + + #region Relay Event Handlers + + private void RelaySolutionValEvent(EntityUid uid, ContainedSolutionComponent comp, TEvent @event) + { + var relayEvent = new SolutionRelayEvent(@event, uid, comp.ContainerName); + RaiseLocalEvent(comp.Container, ref relayEvent); + } + + private void RelaySolutionRefEvent(Entity entity, ref TEvent @event) + { + var relayEvent = new SolutionRelayEvent(@event, entity.Owner, entity.Comp.ContainerName); + RaiseLocalEvent(entity.Comp.Container, ref relayEvent); + @event = relayEvent.Event; + } + + private void RelaySolutionContainerEvent(EntityUid uid, SolutionContainerManagerComponent comp, TEvent @event) + { + foreach (var (name, soln) in EnumerateSolutions((uid, comp))) + { + var relayEvent = new SolutionContainerRelayEvent(@event, soln, name!); + RaiseLocalEvent(soln, ref relayEvent); + } + } + + private void RelaySolutionContainerEvent(Entity entity, ref TEvent @event) + { + foreach (var (name, soln) in EnumerateSolutions((entity.Owner, entity.Comp))) + { + var relayEvent = new SolutionContainerRelayEvent(@event, soln, name!); + RaiseLocalEvent(soln, ref relayEvent); + @event = relayEvent.Event; + } + } + + #endregion Relay Event Handlers + + #endregion Event Handlers +} diff --git a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs new file mode 100644 index 0000000000..392b83fe97 --- /dev/null +++ b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs @@ -0,0 +1,857 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Verbs; +using JetBrains.Annotations; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using Dependency = Robust.Shared.IoC.DependencyAttribute; + +namespace Content.Shared.Chemistry.EntitySystems; + +/// +/// The event raised whenever a solution entity is modified. +/// +/// +/// Raised after chemcial reactions and are handled. +/// +/// The solution entity that has been modified. +[ByRefEvent] +public readonly partial record struct SolutionChangedEvent(Entity Solution); + +/// +/// The event raised whenever a solution entity is filled past its capacity. +/// +/// The solution entity that has been overfilled. +/// The amount by which the solution entity has been overfilled. +[ByRefEvent] +public partial record struct SolutionOverflowEvent(Entity Solution, FixedPoint2 Overflow) +{ + /// The solution entity that has been overfilled. + public readonly Entity Solution = Solution; + /// The amount by which the solution entity has been overfilled. + public readonly FixedPoint2 Overflow = Overflow; + /// Whether any of the event handlers for this event have handled overflow behaviour. + public bool Handled = false; +} + +/// +/// Part of Chemistry system deal with SolutionContainers +/// +[UsedImplicitly] +public abstract partial class SharedSolutionContainerSystem : EntitySystem +{ + [Dependency] protected readonly IPrototypeManager PrototypeManager = default!; + [Dependency] protected readonly ChemicalReactionSystem ChemicalReactionSystem = default!; + [Dependency] protected readonly ExamineSystemShared ExamineSystem = default!; + [Dependency] protected readonly SharedAppearanceSystem AppearanceSystem = default!; + [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + InitializeRelays(); + + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnComponentStartup); + SubscribeLocalEvent(OnComponentShutdown); + + SubscribeLocalEvent(OnComponentInit); + + SubscribeLocalEvent(OnExamineSolution); + SubscribeLocalEvent>(OnSolutionExaminableVerb); + } + + + /// + /// Attempts to resolve a solution associated with an entity. + /// + /// The entity that holdes the container the solution entity is in. + /// The name of the solution entities container. + /// A reference to a solution entity to load the associated solution entity into. Will be unchanged if not null. + /// Returns the solution state of the solution entity. + /// Whether the solution was successfully resolved. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ResolveSolution(Entity container, string? name, [NotNullWhen(true)] ref Entity? entity, [NotNullWhen(true)] out Solution? solution) + { + if (!ResolveSolution(container, name, ref entity)) + { + solution = null; + return false; + } + + solution = entity.Value.Comp.Solution; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ResolveSolution(Entity container, string? name, [NotNullWhen(true)] ref Entity? entity) + { + if (entity is not null) + { + DebugTools.Assert(TryGetSolution(container, name, out var debugEnt) + && debugEnt.Value.Owner == entity.Value.Owner); + return true; + } + + return TryGetSolution(container, name, out entity); + } + + /// + /// Attempts to fetch a solution entity associated with an entity. + /// + /// + /// If the solution entity will be frequently accessed please use the equivalent method and cache the result. + /// + /// The entity the solution entity should be associated with. + /// The name of the solution entity to fetch. + /// Returns the solution entity that was fetched. + /// Returns the solution state of the solution entity that was fetched. + /// + public bool TryGetSolution(Entity container, string? name, [NotNullWhen(true)] out Entity? entity, [NotNullWhen(true)] out Solution? solution) + { + if (!TryGetSolution(container, name, out entity)) + { + solution = null; + return false; + } + + solution = entity.Value.Comp.Solution; + return true; + } + + /// + public bool TryGetSolution(Entity container, string? name, [NotNullWhen(true)] out Entity? entity) + { + EntityUid uid; + if (name is null) + uid = container; + else if ( + ContainerSystem.TryGetContainer(container, $"solution@{name}", out var solutionContainer) && + solutionContainer is ContainerSlot solutionSlot && + solutionSlot.ContainedEntity is { } containedSolution + ) + uid = containedSolution; + else + { + entity = null; + return false; + } + + if (!TryComp(uid, out SolutionComponent? comp)) + { + entity = null; + return false; + } + + entity = (uid, comp); + return true; + } + + public IEnumerable<(string? Name, Entity Solution)> EnumerateSolutions(Entity container, bool includeSelf = true) + { + if (includeSelf && TryComp(container, out SolutionComponent? solutionComp)) + yield return (null, (container.Owner, solutionComp)); + + if (!Resolve(container, ref container.Comp, logMissing: false)) + yield break; + + foreach (var name in container.Comp.Containers) + { + if (ContainerSystem.GetContainer(container, $"solution@{name}") is ContainerSlot slot && slot.ContainedEntity is { } solutionId) + yield return (name, (solutionId, Comp(solutionId))); + } + } + + public IEnumerable<(string Name, Solution Solution)> EnumerateSolutions(SolutionContainerManagerComponent container) + { + if (container.Solutions is not { Count: > 0 } solutions) + yield break; + + foreach (var (name, solution) in solutions) + { + yield return (name, solution); + } + } + + + protected void UpdateAppearance(Entity container, Entity soln) + { + var (uid, appearanceComponent) = container; + if (!HasComp(uid) || !Resolve(uid, ref appearanceComponent, logMissing: false)) + return; + + var (_, comp, relation) = soln; + var solution = comp.Solution; + + AppearanceSystem.SetData(uid, SolutionContainerVisuals.FillFraction, solution.FillFraction, appearanceComponent); + AppearanceSystem.SetData(uid, SolutionContainerVisuals.Color, solution.GetColor(PrototypeManager), appearanceComponent); + AppearanceSystem.SetData(uid, SolutionContainerVisuals.SolutionName, relation.ContainerName, appearanceComponent); + + if (solution.GetPrimaryReagentId() is { } reagent) + AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, reagent.ToString(), appearanceComponent); + else + AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, string.Empty, appearanceComponent); + } + + + public FixedPoint2 GetTotalPrototypeQuantity(EntityUid owner, string reagentId) + { + var reagentQuantity = FixedPoint2.New(0); + if (EntityManager.EntityExists(owner) + && EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent)) + { + foreach (var (_, soln) in EnumerateSolutions((owner, managerComponent))) + { + var solution = soln.Comp.Solution; + reagentQuantity += solution.GetTotalPrototypeQuantity(reagentId); + } + } + + return reagentQuantity; + } + + + /// + /// Dirties a solution entity that has been modified and prompts updates to chemical reactions and overflow state. + /// Should be invoked whenever a solution entity is modified. + /// + /// + /// 90% of this system is ensuring that this proc is invoked whenever a solution entity is changed. The other 10% is this proc. + /// + /// + /// + /// + public void UpdateChemicals(Entity soln, bool needsReactionsProcessing = true, ReactionMixerComponent? mixerComponent = null) + { + Dirty(soln); + + var (uid, comp) = soln; + var solution = comp.Solution; + + // Process reactions + if (needsReactionsProcessing && solution.CanReact) + ChemicalReactionSystem.FullyReactSolution(soln, mixerComponent); + + var overflow = solution.Volume - solution.MaxVolume; + if (overflow > FixedPoint2.Zero) + { + var overflowEv = new SolutionOverflowEvent(soln, overflow); + RaiseLocalEvent(uid, ref overflowEv); + } + + UpdateAppearance((uid, comp, null)); + + var changedEv = new SolutionChangedEvent(soln); + RaiseLocalEvent(uid, ref changedEv); + } + + public void UpdateAppearance(Entity soln) + { + var (uid, comp, appearanceComponent) = soln; + var solution = comp.Solution; + + if (!EntityManager.EntityExists(uid) || !Resolve(uid, ref appearanceComponent, false)) + return; + + AppearanceSystem.SetData(uid, SolutionContainerVisuals.FillFraction, solution.FillFraction, appearanceComponent); + AppearanceSystem.SetData(uid, SolutionContainerVisuals.Color, solution.GetColor(PrototypeManager), appearanceComponent); + + if (solution.GetPrimaryReagentId() is { } reagent) + AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, reagent.ToString(), appearanceComponent); + else + AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, string.Empty, appearanceComponent); + } + + /// + /// Removes part of the solution in the container. + /// + /// + /// + /// the volume of solution to remove. + /// The solution that was removed. + public Solution SplitSolution(Entity soln, FixedPoint2 quantity) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + var splitSol = solution.SplitSolution(quantity); + UpdateChemicals(soln); + return splitSol; + } + + public Solution SplitStackSolution(Entity soln, FixedPoint2 quantity, int stackCount) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + var splitSol = solution.SplitSolution(quantity / stackCount); + solution.SplitSolution(quantity - splitSol.Volume); + UpdateChemicals(soln); + return splitSol; + } + + /// + /// Splits a solution without the specified reagent(s). + /// + public Solution SplitSolutionWithout(Entity soln, FixedPoint2 quantity, params string[] reagents) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + var splitSol = solution.SplitSolutionWithout(quantity, reagents); + UpdateChemicals(soln); + return splitSol; + } + + public void RemoveAllSolution(Entity soln) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (solution.Volume == 0) + return; + + solution.RemoveAllSolution(); + UpdateChemicals(soln); + } + + /// + /// Sets the capacity (maximum volume) of a solution to a new value. + /// + /// The entity containing the solution. + /// The solution to set the capacity of. + /// The value to set the capacity of the solution to. + public void SetCapacity(Entity soln, FixedPoint2 capacity) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (solution.MaxVolume == capacity) + return; + + solution.MaxVolume = capacity; + UpdateChemicals(soln); + } + + /// + /// Adds reagent of an Id to the container. + /// + /// + /// Container to which we are adding reagent + /// The reagent to add. + /// The amount of reagent successfully added. + /// If all the reagent could be added. + public bool TryAddReagent(Entity soln, ReagentQuantity reagentQuantity, out FixedPoint2 acceptedQuantity, float? temperature = null) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + acceptedQuantity = solution.AvailableVolume > reagentQuantity.Quantity + ? reagentQuantity.Quantity + : solution.AvailableVolume; + + if (acceptedQuantity <= 0) + return reagentQuantity.Quantity == 0; + + if (temperature == null) + { + solution.AddReagent(reagentQuantity.Reagent, acceptedQuantity); + } + else + { + var proto = PrototypeManager.Index(reagentQuantity.Reagent.Prototype); + solution.AddReagent(proto, acceptedQuantity, temperature.Value, PrototypeManager); + } + + UpdateChemicals(soln); + return acceptedQuantity == reagentQuantity.Quantity; + } + + /// + /// Adds reagent of an Id to the container. + /// + /// + /// Container to which we are adding reagent + /// The Id of the reagent to add. + /// The amount of reagent to add. + /// If all the reagent could be added. + [PublicAPI] + public bool TryAddReagent(Entity soln, string prototype, FixedPoint2 quantity, float? temperature = null, ReagentData? data = null) + => TryAddReagent(soln, new ReagentQuantity(prototype, quantity, data), out _, temperature); + + /// + /// Adds reagent of an Id to the container. + /// + /// + /// Container to which we are adding reagent + /// The Id of the reagent to add. + /// The amount of reagent to add. + /// The amount of reagent successfully added. + /// If all the reagent could be added. + public bool TryAddReagent(Entity soln, string prototype, FixedPoint2 quantity, out FixedPoint2 acceptedQuantity, float? temperature = null, ReagentData? data = null) + { + var reagent = new ReagentQuantity(prototype, quantity, data); + return TryAddReagent(soln, reagent, out acceptedQuantity, temperature); + } + + /// + /// Adds reagent of an Id to the container. + /// + /// + /// Container to which we are adding reagent + /// The reagent to add. + /// The amount of reagent to add. + /// The amount of reagent successfully added. + /// If all the reagent could be added. + public bool TryAddReagent(Entity soln, ReagentId reagentId, FixedPoint2 quantity, out FixedPoint2 acceptedQuantity, float? temperature = null) + { + var quant = new ReagentQuantity(reagentId, quantity); + return TryAddReagent(soln, quant, out acceptedQuantity, temperature); + } + + /// + /// Removes reagent from a container. + /// + /// + /// Solution container from which we are removing reagent + /// The reagent to remove. + /// If the reagent to remove was found in the container. + public bool RemoveReagent(Entity soln, ReagentQuantity reagentQuantity) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + var quant = solution.RemoveReagent(reagentQuantity); + if (quant <= FixedPoint2.Zero) + return false; + + UpdateChemicals(soln); + return true; + } + + /// + /// Removes reagent from a container. + /// + /// + /// Solution container from which we are removing reagent + /// The Id of the reagent to remove. + /// The amount of reagent to remove. + /// If the reagent to remove was found in the container. + public bool RemoveReagent(Entity soln, string prototype, FixedPoint2 quantity, ReagentData? data = null) + { + return RemoveReagent(soln, new ReagentQuantity(prototype, quantity, data)); + } + + /// + /// Removes reagent from a container. + /// + /// + /// Solution container from which we are removing reagent + /// The reagent to remove. + /// The amount of reagent to remove. + /// If the reagent to remove was found in the container. + public bool RemoveReagent(Entity soln, ReagentId reagentId, FixedPoint2 quantity) + { + return RemoveReagent(soln, new ReagentQuantity(reagentId, quantity)); + } + + /// + /// Moves some quantity of a solution from one solution to another. + /// + /// entity holding the source solution + /// entity holding the target solution + /// source solution + /// target solution + /// quantity of solution to move from source to target. If this is a negative number, the source & target roles are reversed. + public bool TryTransferSolution(Entity soln, Solution source, FixedPoint2 quantity) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (quantity < 0) + throw new InvalidOperationException("Quantity must be positive"); + + quantity = FixedPoint2.Min(quantity, solution.AvailableVolume, source.Volume); + if (quantity == 0) + return false; + + // TODO This should be made into a function that directly transfers reagents. + // Currently this is quite inefficient. + solution.AddSolution(source.SplitSolution(quantity), PrototypeManager); + + UpdateChemicals(soln); + return true; + } + + /// + /// Adds a solution to the container, if it can fully fit. + /// + /// entity holding targetSolution + /// entity holding targetSolution + /// solution being added + /// If the solution could be added. + public bool TryAddSolution(Entity soln, Solution toAdd) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (toAdd.Volume == FixedPoint2.Zero) + return true; + if (toAdd.Volume > solution.AvailableVolume) + return false; + + ForceAddSolution(soln, toAdd); + return true; + } + + /// + /// Adds as much of a solution to a container as can fit. + /// + /// The entity containing + /// The solution being added to. + /// The solution being added to + /// The quantity of the solution actually added. + public FixedPoint2 AddSolution(Entity soln, Solution toAdd) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (toAdd.Volume == FixedPoint2.Zero) + return FixedPoint2.Zero; + + var quantity = FixedPoint2.Max(FixedPoint2.Zero, FixedPoint2.Min(toAdd.Volume, solution.AvailableVolume)); + if (quantity < toAdd.Volume) + TryTransferSolution(soln, toAdd, quantity); + else + ForceAddSolution(soln, toAdd); + + return quantity; + } + + /// + /// Adds a solution to a container and updates the container. + /// + /// The entity containing + /// The solution being added to. + /// The solution being added to + /// Whether any reagents were added to the solution. + public bool ForceAddSolution(Entity soln, Solution toAdd) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (toAdd.Volume == FixedPoint2.Zero) + return false; + + solution.AddSolution(toAdd, PrototypeManager); + UpdateChemicals(soln); + return true; + } + + /// + /// Adds a solution to the container, removing the overflow. + /// Unlike it will ignore size limits. + /// + /// The entity containing + /// The solution being added to. + /// The solution being added to + /// The combined volume above which the overflow will be returned. + /// If the combined volume is below this an empty solution is returned. + /// Solution that exceeded overflowThreshold + /// Whether any reagents were added to . + public bool TryMixAndOverflow(Entity soln, Solution toAdd, FixedPoint2 overflowThreshold, [MaybeNullWhen(false)] out Solution overflowingSolution) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (toAdd.Volume == 0 || overflowThreshold > solution.MaxVolume) + { + overflowingSolution = null; + return false; + } + + solution.AddSolution(toAdd, PrototypeManager); + overflowingSolution = solution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, solution.Volume - overflowThreshold)); + UpdateChemicals(soln); + return true; + } + + /// + /// Removes an amount from all reagents in a solution, adding it to a new solution. + /// + /// The entity containing the solution. + /// The solution to remove reagents from. + /// The amount to remove from every reagent in the solution. + /// A new solution containing every removed reagent from the original solution. + public Solution RemoveEachReagent(Entity soln, FixedPoint2 quantity) + { + var (uid, comp) = soln; + var solution = comp.Solution; + + if (quantity <= 0) + return new Solution(); + + var removedSolution = new Solution(); + + // RemoveReagent does a RemoveSwap, meaning we don't have to copy the list if we iterate it backwards. + for (var i = solution.Contents.Count - 1; i >= 0; i--) + { + var (reagent, _) = solution.Contents[i]; + var removedQuantity = solution.RemoveReagent(reagent, quantity); + removedSolution.AddReagent(reagent, removedQuantity); + } + + UpdateChemicals(soln); + return removedSolution; + } + + // Thermal energy and temperature management. + + #region Thermal Energy and Temperature + + /// + /// Sets the temperature of a solution to a new value and then checks for reaction processing. + /// + /// The entity in which the solution is located. + /// The solution to set the temperature of. + /// The new value to set the temperature to. + public void SetTemperature(Entity soln, float temperature) + { + var (_, comp) = soln; + var solution = comp.Solution; + + if (temperature == solution.Temperature) + return; + + solution.Temperature = temperature; + UpdateChemicals(soln); + } + + /// + /// Sets the thermal energy of a solution to a new value and then checks for reaction processing. + /// + /// The entity in which the solution is located. + /// The solution to set the thermal energy of. + /// The new value to set the thermal energy to. + public void SetThermalEnergy(Entity soln, float thermalEnergy) + { + var (_, comp) = soln; + var solution = comp.Solution; + + var heatCap = solution.GetHeatCapacity(PrototypeManager); + solution.Temperature = heatCap == 0 ? 0 : thermalEnergy / heatCap; + UpdateChemicals(soln); + } + + /// + /// Adds some thermal energy to a solution and then checks for reaction processing. + /// + /// The entity in which the solution is located. + /// The solution to set the thermal energy of. + /// The new value to set the thermal energy to. + public void AddThermalEnergy(Entity soln, float thermalEnergy) + { + var (_, comp) = soln; + var solution = comp.Solution; + + if (thermalEnergy == 0.0f) + return; + + var heatCap = solution.GetHeatCapacity(PrototypeManager); + solution.Temperature += heatCap == 0 ? 0 : thermalEnergy / heatCap; + UpdateChemicals(soln); + } + + #endregion Thermal Energy and Temperature + + #region Event Handlers + + private void OnComponentInit(Entity entity, ref ComponentInit args) + { + entity.Comp.Solution.ValidateSolution(); + } + + private void OnComponentStartup(Entity entity, ref ComponentStartup args) + { + UpdateChemicals(entity); + } + + private void OnComponentShutdown(Entity entity, ref ComponentShutdown args) + { + RemoveAllSolution(entity); + } + + private void OnComponentInit(Entity entity, ref ComponentInit args) + { + if (entity.Comp.Containers is not { Count: > 0 } containers) + return; + + var containerManager = EnsureComp(entity); + foreach (var name in containers) + { + // The actual solution entity should be directly held within the corresponding slot. + ContainerSystem.EnsureContainer(entity.Owner, $"solution@{name}", containerManager); + } + } + + private void OnExamineSolution(Entity entity, ref ExaminedEvent args) + { + if (!TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var solution)) + { + return; + } + + var primaryReagent = solution.GetPrimaryReagentId(); + + if (string.IsNullOrEmpty(primaryReagent?.Prototype)) + { + args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container")); + return; + } + + if (!PrototypeManager.TryIndex(primaryReagent.Value.Prototype, out ReagentPrototype? primary)) + { + Log.Error($"{nameof(Solution)} could not find the prototype associated with {primaryReagent}."); + return; + } + + var colorHex = solution.GetColor(PrototypeManager) + .ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable. + var messageString = "shared-solution-container-component-on-examine-main-text"; + + args.PushMarkup(Loc.GetString(messageString, + ("color", colorHex), + ("wordedAmount", Loc.GetString(solution.Contents.Count == 1 + ? "shared-solution-container-component-on-examine-worded-amount-one-reagent" + : "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")), + ("desc", primary.LocalizedPhysicalDescription))); + + var reagentPrototypes = solution.GetReagentPrototypes(PrototypeManager); + + // Sort the reagents by amount, descending then alphabetically + var sortedReagentPrototypes = reagentPrototypes + .OrderByDescending(pair => pair.Value.Value) + .ThenBy(pair => pair.Key.LocalizedName); + + // Add descriptions of immediately recognizable reagents, like water or beer + var recognized = new List(); + foreach (var keyValuePair in sortedReagentPrototypes) + { + var proto = keyValuePair.Key; + if (!proto.Recognizable) + { + continue; + } + + recognized.Add(proto); + } + + // Skip if there's nothing recognizable + if (recognized.Count == 0) + return; + + var msg = new StringBuilder(); + foreach (var reagent in recognized) + { + string part; + if (reagent == recognized[0]) + { + part = "examinable-solution-recognized-first"; + } + else if (reagent == recognized[^1]) + { + // this loc specifically requires space to be appended, fluent doesnt support whitespace + msg.Append(' '); + part = "examinable-solution-recognized-last"; + } + else + { + part = "examinable-solution-recognized-next"; + } + + msg.Append(Loc.GetString(part, ("color", reagent.SubstanceColor.ToHexNoAlpha()), + ("chemical", reagent.LocalizedName))); + } + + args.PushMarkup(Loc.GetString("examinable-solution-has-recognizable-chemicals", ("recognizedString", msg.ToString()))); + } + + private void OnSolutionExaminableVerb(Entity entity, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var scanEvent = new SolutionScanEvent(); + RaiseLocalEvent(args.User, scanEvent); + if (!scanEvent.CanScan) + { + return; + } + + if (!TryGetSolution(args.Target, entity.Comp.Solution, out _, out var solutionHolder)) + { + return; + } + + var target = args.Target; + var user = args.User; + var verb = new ExamineVerb() + { + Act = () => + { + var markup = GetSolutionExamine(solutionHolder); + ExamineSystem.SendExamineTooltip(user, target, markup, false, false); + }, + Text = Loc.GetString("scannable-solution-verb-text"), + Message = Loc.GetString("scannable-solution-verb-message"), + Category = VerbCategory.Examine, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")), + }; + + args.Verbs.Add(verb); + } + + private FormattedMessage GetSolutionExamine(Solution solution) + { + var msg = new FormattedMessage(); + + if (solution.Volume == 0) + { + msg.AddMarkup(Loc.GetString("scannable-solution-empty-container")); + return msg; + } + + msg.AddMarkup(Loc.GetString("scannable-solution-main-text")); + + var reagentPrototypes = solution.GetReagentPrototypes(PrototypeManager); + + // Sort the reagents by amount, descending then alphabetically + var sortedReagentPrototypes = reagentPrototypes + .OrderByDescending(pair => pair.Value.Value) + .ThenBy(pair => pair.Key.LocalizedName); + + foreach (var (proto, quantity) in sortedReagentPrototypes) + { + msg.PushNewline(); + msg.AddMarkup(Loc.GetString("scannable-solution-chemical" + , ("type", proto.LocalizedName) + , ("color", proto.SubstanceColor.ToHexNoAlpha()) + , ("amount", quantity))); + } + + return msg; + } + + #endregion Event Handlers +} diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.Capabilities.cs b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.Capabilities.cs deleted file mode 100644 index 3647ddb852..0000000000 --- a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.Capabilities.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text; -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.FixedPoint; - -namespace Content.Shared.Chemistry.EntitySystems; - -public sealed partial class SolutionContainerSystem -{ - public void Refill(EntityUid targetUid, Solution targetSolution, Solution addedSolution, - RefillableSolutionComponent? refillableSolution = null) - { - if (!Resolve(targetUid, ref refillableSolution, false)) - return; - - TryAddSolution(targetUid, targetSolution, addedSolution); - } - - public void Inject(EntityUid targetUid, Solution targetSolution, Solution addedSolution, - InjectableSolutionComponent? injectableSolution = null) - { - if (!Resolve(targetUid, ref injectableSolution, false)) - return; - - TryAddSolution(targetUid, targetSolution, addedSolution); - } - - public Solution Draw(EntityUid targetUid, Solution solution, FixedPoint2 amount, - DrawableSolutionComponent? drawableSolution = null) - { - if (!Resolve(targetUid, ref drawableSolution, false)) - return new Solution(); - - return SplitSolution(targetUid, solution, amount); - } - - public Solution Drain(EntityUid targetUid, Solution targetSolution, FixedPoint2 amount, - DrainableSolutionComponent? drainableSolution = null) - { - if (!Resolve(targetUid, ref drainableSolution, false)) - return new Solution(); - - return SplitSolution(targetUid, targetSolution, amount); - } - - public bool TryGetInjectableSolution(EntityUid targetUid, - [NotNullWhen(true)] out Solution? solution, - InjectableSolutionComponent? injectable = null, - SolutionContainerManagerComponent? manager = null - ) - { - if (!Resolve(targetUid, ref manager, ref injectable, false) - || !manager.Solutions.TryGetValue(injectable.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public bool TryGetRefillableSolution(EntityUid targetUid, - [NotNullWhen(true)] out Solution? solution, - SolutionContainerManagerComponent? solutionManager = null, - RefillableSolutionComponent? refillable = null) - { - if (!Resolve(targetUid, ref solutionManager, ref refillable, false) - || !solutionManager.Solutions.TryGetValue(refillable.Solution, out var refillableSolution)) - { - solution = null; - return false; - } - - solution = refillableSolution; - return true; - } - - public bool TryGetDrainableSolution(EntityUid uid, - [NotNullWhen(true)] out Solution? solution, - DrainableSolutionComponent? drainable = null, - SolutionContainerManagerComponent? manager = null) - { - if (!Resolve(uid, ref drainable, ref manager, false) - || !manager.Solutions.TryGetValue(drainable.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public bool TryGetDumpableSolution(EntityUid uid, - [NotNullWhen(true)] out Solution? solution, - DumpableSolutionComponent? dumpable = null, - SolutionContainerManagerComponent? manager = null) - { - if (!Resolve(uid, ref dumpable, ref manager, false) - || !manager.Solutions.TryGetValue(dumpable.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public bool TryGetDrawableSolution(EntityUid uid, - [NotNullWhen(true)] out Solution? solution, - DrawableSolutionComponent? drawable = null, - SolutionContainerManagerComponent? manager = null) - { - if (!Resolve(uid, ref drawable, ref manager, false) - || !manager.Solutions.TryGetValue(drawable.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public FixedPoint2 DrainAvailable(EntityUid uid) - { - return !TryGetDrainableSolution(uid, out var solution) - ? FixedPoint2.Zero - : solution.Volume; - } - - public float PercentFull(EntityUid uid) - { - if (!TryGetDrainableSolution(uid, out var solution) || solution.MaxVolume.Equals(FixedPoint2.Zero)) - return 0; - - return solution.FillFraction * 100; - } - - public bool TryGetFitsInDispenser(EntityUid owner, - [NotNullWhen(true)] out Solution? solution, - FitsInDispenserComponent? dispenserFits = null, - SolutionContainerManagerComponent? solutionManager = null) - { - if (!Resolve(owner, ref dispenserFits, ref solutionManager, false) - || !solutionManager.Solutions.TryGetValue(dispenserFits.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public static string ToPrettyString(Solution solution) - { - var sb = new StringBuilder(); - if (solution.Name == null) - sb.Append("["); - else - sb.Append($"{solution.Name}:["); - var first = true; - foreach (var (id, quantity) in solution.Contents) - { - if (first) - { - first = false; - } - else - { - sb.Append(", "); - } - - sb.AppendFormat("{0}: {1}u", id, quantity); - } - - sb.Append(']'); - return sb.ToString(); - } -} diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs deleted file mode 100644 index f8fcbf996e..0000000000 --- a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs +++ /dev/null @@ -1,871 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.Reaction; -using Content.Shared.Chemistry.Reagent; -using Content.Shared.Examine; -using Content.Shared.FixedPoint; -using Content.Shared.Verbs; -using JetBrains.Annotations; -using Robust.Shared.Audio; -using Robust.Shared.Prototypes; -using Robust.Shared.Utility; - -namespace Content.Shared.Chemistry.EntitySystems; - -/// -/// This event alerts system that the solution was changed -/// -public sealed class SolutionChangedEvent : EntityEventArgs -{ - public readonly Solution Solution; - public readonly string SolutionId; - - public SolutionChangedEvent(Solution solution, string solutionId) - { - SolutionId = solutionId; - Solution = solution; - } -} - -/// -/// An event raised when more reagents are added to a (managed) solution than it can hold. -/// -[ByRefEvent] -public record struct SolutionOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow) -{ - /// The entity which contains the solution that has overflowed. - public readonly EntityUid SolutionEnt = SolutionEnt; - /// The solution that has overflowed. - public readonly Solution SolutionHolder = SolutionHolder; - /// The reagents that have overflowed the solution. - public readonly Solution Overflow = Overflow; - /// The volume by which the solution has overflowed. - public readonly FixedPoint2 OverflowVol = Overflow.Volume; - /// Whether some subscriber has taken care of the effects of the overflow. - public bool Handled = false; -} - -/// -/// Part of Chemistry system deal with SolutionContainers -/// -[UsedImplicitly] -public sealed partial class SolutionContainerSystem : EntitySystem -{ - [Dependency] private readonly ChemicalReactionSystem _chemistrySystem = default!; - - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly ExamineSystemShared _examine = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(InitSolution); - SubscribeLocalEvent(OnExamineSolution); - SubscribeLocalEvent>(OnSolutionExaminableVerb); - } - - private void InitSolution(EntityUid uid, SolutionContainerManagerComponent component, ComponentInit args) - { - foreach (var (name, solutionHolder) in component.Solutions) - { - solutionHolder.Name = name; - solutionHolder.ValidateSolution(); - UpdateAppearance(uid, solutionHolder); - } - } - - private void OnSolutionExaminableVerb(EntityUid uid, ExaminableSolutionComponent component, GetVerbsEvent args) - { - if (!args.CanInteract || !args.CanAccess) - return; - - var scanEvent = new SolutionScanEvent(); - RaiseLocalEvent(args.User, scanEvent); - if (!scanEvent.CanScan) - { - return; - } - - SolutionContainerManagerComponent? solutionsManager = null; - if (!Resolve(args.Target, ref solutionsManager) - || !solutionsManager.Solutions.TryGetValue(component.Solution, out var solutionHolder)) - { - return; - } - - var verb = new ExamineVerb() - { - Act = () => - { - var markup = GetSolutionExamine(solutionHolder); - _examine.SendExamineTooltip(args.User, uid, markup, false, false); - }, - Text = Loc.GetString("scannable-solution-verb-text"), - Message = Loc.GetString("scannable-solution-verb-message"), - Category = VerbCategory.Examine, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")), - }; - - args.Verbs.Add(verb); - } - - private FormattedMessage GetSolutionExamine(Solution solution) - { - var msg = new FormattedMessage(); - - if (solution.Volume == 0) - { - msg.AddMarkup(Loc.GetString("scannable-solution-empty-container")); - return msg; - } - - msg.AddMarkup(Loc.GetString("scannable-solution-main-text")); - - foreach (var (proto, quantity) in solution.GetReagentPrototypes(_prototypeManager)) - { - msg.PushNewline(); - msg.AddMarkup(Loc.GetString("scannable-solution-chemical" - , ("type", proto.LocalizedName) - , ("color", proto.SubstanceColor.ToHexNoAlpha()) - , ("amount", quantity))); - } - - return msg; - } - - private void OnExamineSolution(EntityUid uid, ExaminableSolutionComponent examinableComponent, - ExaminedEvent args) - { - SolutionContainerManagerComponent? solutionsManager = null; - if (!Resolve(args.Examined, ref solutionsManager) - || !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solution)) - { - return; - } - - var primaryReagent = solution.GetPrimaryReagentId(); - - if (string.IsNullOrEmpty(primaryReagent?.Prototype)) - { - args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container")); - return; - } - - if (!_prototypeManager.TryIndex(primaryReagent.Value.Prototype, out ReagentPrototype? primary)) - { - Log.Error($"{nameof(Solution)} could not find the prototype associated with {primaryReagent}."); - return; - } - - var colorHex = solution.GetColor(_prototypeManager) - .ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable. - var messageString = "shared-solution-container-component-on-examine-main-text"; - - args.PushMarkup(Loc.GetString(messageString, - ("color", colorHex), - ("wordedAmount", Loc.GetString(solution.Contents.Count == 1 - ? "shared-solution-container-component-on-examine-worded-amount-one-reagent" - : "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")), - ("desc", primary.LocalizedPhysicalDescription))); - - - var reagentPrototypes = solution.GetReagentPrototypes(_prototypeManager); - - // Sort the reagents by amount, descending then alphabetically - var sortedReagentPrototypes = reagentPrototypes - .OrderByDescending(pair => pair.Value.Value) - .ThenBy(pair => pair.Key.LocalizedName); - - // Add descriptions of immediately recognizable reagents, like water or beer - var recognized = new List(); - foreach (var keyValuePair in sortedReagentPrototypes) - { - var proto = keyValuePair.Key; - if (!proto.Recognizable) - { - continue; - } - - recognized.Add(proto); - } - - // Skip if there's nothing recognizable - if (recognized.Count == 0) - return; - - var msg = new StringBuilder(); - foreach (var reagent in recognized) - { - string part; - if (reagent == recognized[0]) - { - part = "examinable-solution-recognized-first"; - } - else if (reagent == recognized[^1]) - { - // this loc specifically requires space to be appended, fluent doesnt support whitespace - msg.Append(' '); - part = "examinable-solution-recognized-last"; - } - else - { - part = "examinable-solution-recognized-next"; - } - - msg.Append(Loc.GetString(part, ("color", reagent.SubstanceColor.ToHexNoAlpha()), - ("chemical", reagent.LocalizedName))); - } - - args.PushMarkup(Loc.GetString("examinable-solution-has-recognizable-chemicals", ("recognizedString", msg.ToString()))); - } - - public void UpdateAppearance(EntityUid uid, Solution solution, - AppearanceComponent? appearanceComponent = null) - { - if (!HasComp(uid) || !Resolve(uid, ref appearanceComponent, false)) - return; - - _appearance.SetData(uid, SolutionContainerVisuals.FillFraction, solution.FillFraction, appearanceComponent); - _appearance.SetData(uid, SolutionContainerVisuals.Color, solution.GetColor(_prototypeManager), appearanceComponent); - if (solution.Name != null) - { - _appearance.SetData(uid, SolutionContainerVisuals.SolutionName, solution.Name, appearanceComponent); - } - - if (solution.GetPrimaryReagentId() is { } reagent) - { - _appearance.SetData(uid, SolutionContainerVisuals.BaseOverride, reagent.ToString(), appearanceComponent); - } - else - { - _appearance.SetData(uid, SolutionContainerVisuals.BaseOverride, string.Empty, appearanceComponent); - } - } - - /// - /// Removes part of the solution in the container. - /// - /// - /// - /// the volume of solution to remove. - /// The solution that was removed. - public Solution SplitSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity) - { - var splitSol = solutionHolder.SplitSolution(quantity); - UpdateChemicals(targetUid, solutionHolder); - return splitSol; - } - - public Solution SplitStackSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity, int stackCount) - { - var splitSol = solutionHolder.SplitSolution(quantity / stackCount); - solutionHolder.SplitSolution(quantity - splitSol.Volume); - UpdateChemicals(targetUid, solutionHolder); - return splitSol; - } - - /// - /// Splits a solution without the specified reagent(s). - /// - public Solution SplitSolutionWithout(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity, - params string[] reagents) - { - var splitSol = solutionHolder.SplitSolutionWithout(quantity, reagents); - UpdateChemicals(targetUid, solutionHolder); - return splitSol; - } - - public void UpdateChemicals(EntityUid uid, Solution solutionHolder, bool needsReactionsProcessing = false, ReactionMixerComponent? mixerComponent = null) - { - DebugTools.Assert(solutionHolder.Name != null && TryGetSolution(uid, solutionHolder.Name, out var tmp) && tmp == solutionHolder); - - // Process reactions - if (needsReactionsProcessing && solutionHolder.CanReact) - { - _chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume, mixerComponent); - } - - var overflowVol = solutionHolder.Volume - solutionHolder.MaxVolume; - if (overflowVol > FixedPoint2.Zero) - { - var overflow = solutionHolder.SplitSolution(overflowVol); - var overflowEv = new SolutionOverflowEvent(uid, solutionHolder, overflow); - RaiseLocalEvent(uid, ref overflowEv); - } - - UpdateAppearance(uid, solutionHolder); - RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name)); - } - - public void RemoveAllSolution(EntityUid uid, Solution solutionHolder) - { - if (solutionHolder.Volume == 0) - return; - - solutionHolder.RemoveAllSolution(); - UpdateChemicals(uid, solutionHolder); - } - - public void RemoveAllSolution(EntityUid uid, SolutionContainerManagerComponent? solutionContainerManager = null) - { - if (!Resolve(uid, ref solutionContainerManager)) - return; - - foreach (var solution in solutionContainerManager.Solutions.Values) - { - RemoveAllSolution(uid, solution); - } - } - - /// - /// Sets the capacity (maximum volume) of a solution to a new value. - /// - /// The entity containing the solution. - /// The solution to set the capacity of. - /// The value to set the capacity of the solution to. - public void SetCapacity(EntityUid targetUid, Solution targetSolution, FixedPoint2 capacity) - { - if (targetSolution.MaxVolume == capacity) - return; - - targetSolution.MaxVolume = capacity; - if (capacity < targetSolution.Volume) - targetSolution.RemoveSolution(targetSolution.Volume - capacity); - - UpdateChemicals(targetUid, targetSolution); - } - - /// - /// Adds reagent of an Id to the container. - /// - /// - /// Container to which we are adding reagent - /// The reagent to add. - /// The amount of reagent successfully added. - /// If all the reagent could be added. - public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, ReagentQuantity reagentQuantity, - out FixedPoint2 acceptedQuantity, float? temperature = null) - { - acceptedQuantity = targetSolution.AvailableVolume > reagentQuantity.Quantity - ? reagentQuantity.Quantity - : targetSolution.AvailableVolume; - - if (acceptedQuantity <= 0) - return reagentQuantity.Quantity == 0; - - if (temperature == null) - { - targetSolution.AddReagent(reagentQuantity.Reagent, acceptedQuantity); - } - else - { - var proto = _prototypeManager.Index(reagentQuantity.Reagent.Prototype); - targetSolution.AddReagent(proto, acceptedQuantity, temperature.Value, _prototypeManager); - } - - UpdateChemicals(targetUid, targetSolution, true); - return acceptedQuantity == reagentQuantity.Quantity; - } - - /// - /// Adds reagent of an Id to the container. - /// - /// - /// Container to which we are adding reagent - /// The Id of the reagent to add. - /// The amount of reagent to add. - /// If all the reagent could be added. - [PublicAPI] - public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string prototype, FixedPoint2 quantity, - float? temperature = null, ReagentData? data = null) - { - var reagent = new ReagentQuantity(prototype, quantity, data); - return TryAddReagent(targetUid, targetSolution, reagent, out _, temperature); - } - - /// - /// Adds reagent of an Id to the container. - /// - /// - /// Container to which we are adding reagent - /// The Id of the reagent to add. - /// The amount of reagent to add. - /// The amount of reagent successfully added. - /// If all the reagent could be added. - public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string prototype, FixedPoint2 quantity, - out FixedPoint2 acceptedQuantity, float? temperature = null, ReagentData? data = null) - { - var reagent = new ReagentQuantity(prototype, quantity, data); - return TryAddReagent(targetUid, targetSolution, reagent, out acceptedQuantity, temperature); - } - - /// - /// Adds reagent of an Id to the container. - /// - /// - /// Container to which we are adding reagent - /// The reagent to add. - /// The amount of reagent to add. - /// The amount of reagent successfully added. - /// If all the reagent could be added. - public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, ReagentId reagentId, FixedPoint2 quantity, - out FixedPoint2 acceptedQuantity, float? temperature = null) - { - var quant = new ReagentQuantity(reagentId, quantity); - return TryAddReagent(targetUid, targetSolution, quant, out acceptedQuantity, temperature); - } - - /// - /// Removes reagent from a container. - /// - /// - /// Solution container from which we are removing reagent - /// The reagent to remove. - /// If the reagent to remove was found in the container. - public bool RemoveReagent(EntityUid targetUid, Solution? container, ReagentQuantity reagentQuantity) - { - if (container == null) - return false; - - var quant = container.RemoveReagent(reagentQuantity); - if (quant <= FixedPoint2.Zero) - return false; - - UpdateChemicals(targetUid, container); - return true; - } - - /// - /// Removes reagent from a container. - /// - /// - /// Solution container from which we are removing reagent - /// The Id of the reagent to remove. - /// The amount of reagent to remove. - /// If the reagent to remove was found in the container. - public bool RemoveReagent(EntityUid targetUid, Solution? container, string prototype, FixedPoint2 quantity, ReagentData? data = null) - { - return RemoveReagent(targetUid, container, new ReagentQuantity(prototype, quantity, data)); - } - - /// - /// Removes reagent from a container. - /// - /// - /// Solution container from which we are removing reagent - /// The reagent to remove. - /// The amount of reagent to remove. - /// If the reagent to remove was found in the container. - public bool RemoveReagent(EntityUid targetUid, Solution? container, ReagentId reagentId, FixedPoint2 quantity) - { - return RemoveReagent(targetUid, container, new ReagentQuantity(reagentId, quantity)); - } - - /// - /// Moves some quantity of a solution from one solution to another. - /// - /// entity holding the source solution - /// entity holding the target solution - /// source solution - /// target solution - /// quantity of solution to move from source to target. If this is a negative number, the source & target roles are reversed. - public bool TryTransferSolution(EntityUid sourceUid, EntityUid targetUid, Solution source, Solution target, FixedPoint2 quantity) - { - if (!TryTransferSolution(targetUid, target, source, quantity)) - return false; - - UpdateChemicals(sourceUid, source, false); - return true; - } - - /// - /// Moves some quantity of a solution from one solution to another. - /// - /// entity holding the source solution - /// entity holding the target solution - /// source solution - /// target solution - /// quantity of solution to move from source to target. If this is a negative number, the source & target roles are reversed. - public bool TryTransferSolution(EntityUid targetUid, Solution target, Solution source, FixedPoint2 quantity) - { - if (quantity < 0) - throw new InvalidOperationException("Quantity must be positive"); - - quantity = FixedPoint2.Min(quantity, target.AvailableVolume, source.Volume); - if (quantity == 0) - return false; - - // TODO This should be made into a function that directly transfers reagents. - // Currently this is quite inefficient. - target.AddSolution(source.SplitSolution(quantity), _prototypeManager); - - UpdateChemicals(targetUid, target, true); - return true; - } - - /// - /// Moves some quantity of a solution from one solution to another. - /// - /// entity holding the source solution - /// entity holding the target solution - /// source solution - /// target solution - /// quantity of solution to move from source to target. If this is a negative number, the source & target roles are reversed. - public bool TryTransferSolution(EntityUid sourceUid, EntityUid targetUid, string source, string target, FixedPoint2 quantity) - { - if (!TryGetSolution(sourceUid, source, out var sourceSoln)) - return false; - - if (!TryGetSolution(targetUid, target, out var targetSoln)) - return false; - - return TryTransferSolution(sourceUid, targetUid, sourceSoln, targetSoln, quantity); - } - - /// - /// Adds a solution to the container, if it can fully fit. - /// - /// entity holding targetSolution - /// entity holding targetSolution - /// solution being added - /// If the solution could be added. - public bool TryAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd) - { - if (toAdd.Volume == FixedPoint2.Zero) - return true; - if (toAdd.Volume > targetSolution.AvailableVolume) - return false; - - ForceAddSolution(targetUid, targetSolution, toAdd); - return true; - } - - /// - /// Adds as much of a solution to a container as can fit. - /// - /// The entity containing - /// The solution being added to. - /// The solution being added to - /// The quantity of the solution actually added. - public FixedPoint2 AddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd) - { - if (toAdd.Volume == FixedPoint2.Zero) - return FixedPoint2.Zero; - - var quantity = FixedPoint2.Max(FixedPoint2.Zero, FixedPoint2.Min(toAdd.Volume, targetSolution.AvailableVolume)); - if (quantity < toAdd.Volume) - TryTransferSolution(targetUid, targetSolution, toAdd, quantity); - else - ForceAddSolution(targetUid, targetSolution, toAdd); - - return quantity; - } - - /// - /// Adds a solution to a container and updates the container. - /// - /// The entity containing - /// The solution being added to. - /// The solution being added to - /// Whether any reagents were added to the solution. - public bool ForceAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd) - { - if (toAdd.Volume == FixedPoint2.Zero) - return false; - - targetSolution.AddSolution(toAdd, _prototypeManager); - UpdateChemicals(targetUid, targetSolution, needsReactionsProcessing: true); - return true; - } - - /// - /// Adds a solution to the container, removing the overflow. - /// Unlike it will ignore size limits. - /// - /// The entity containing - /// The solution being added to. - /// The solution being added to - /// The combined volume above which the overflow will be returned. - /// If the combined volume is below this an empty solution is returned. - /// Solution that exceeded overflowThreshold - /// Whether any reagents were added to . - public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution, - Solution toAdd, - FixedPoint2 overflowThreshold, - [NotNullWhen(true)] out Solution? overflowingSolution) - { - if (toAdd.Volume == 0 || overflowThreshold > targetSolution.MaxVolume) - { - overflowingSolution = null; - return false; - } - - targetSolution.AddSolution(toAdd, _prototypeManager); - overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, targetSolution.Volume - overflowThreshold)); - UpdateChemicals(targetUid, targetSolution, true); - return true; - } - - public bool TryGetSolution([NotNullWhen(true)] EntityUid? uid, string name, - [NotNullWhen(true)] out Solution? solution, - SolutionContainerManagerComponent? solutionsMgr = null) - { - if (uid == null || !Resolve(uid.Value, ref solutionsMgr, false)) - { - solution = null; - return false; - } - - return solutionsMgr.Solutions.TryGetValue(name, out solution); - } - - - /// - /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager - /// - /// EntityUid to which to add solution - /// name for the solution - /// solution components used in resolves - /// true if the solution already existed - /// solution - public Solution EnsureSolution(EntityUid uid, string name, out bool existed, - SolutionContainerManagerComponent? solutionsMgr = null) - { - if (!Resolve(uid, ref solutionsMgr, false)) - { - solutionsMgr = EntityManager.EnsureComponent(uid); - } - - if (!solutionsMgr.Solutions.TryGetValue(name, out var existing)) - { - var newSolution = new Solution() { Name = name }; - solutionsMgr.Solutions.Add(name, newSolution); - existed = false; - return newSolution; - } - - existed = true; - return existing; - } - - /// - /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager - /// - /// EntityUid to which to add solution - /// name for the solution - /// solution components used in resolves - /// solution - public Solution EnsureSolution(EntityUid uid, string name, SolutionContainerManagerComponent? solutionsMgr = null) - => EnsureSolution(uid, name, out _, solutionsMgr); - - /// - /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager - /// - /// EntityUid to which to add solution - /// name for the solution - /// Ensures that the solution's maximum volume is larger than this value. - /// solution components used in resolves - /// solution - public Solution EnsureSolution(EntityUid uid, string name, FixedPoint2 minVol, out bool existed, - SolutionContainerManagerComponent? solutionsMgr = null) - { - if (!Resolve(uid, ref solutionsMgr, false)) - { - solutionsMgr = EntityManager.EnsureComponent(uid); - } - - if (!solutionsMgr.Solutions.TryGetValue(name, out var existing)) - { - var newSolution = new Solution() { Name = name }; - solutionsMgr.Solutions.Add(name, newSolution); - existed = false; - newSolution.MaxVolume = minVol; - return newSolution; - } - - existed = true; - existing.MaxVolume = FixedPoint2.Max(existing.MaxVolume, minVol); - return existing; - } - - public Solution EnsureSolution(EntityUid uid, string name, - IEnumerable reagents, - bool setMaxVol = true, - SolutionContainerManagerComponent? solutionsMgr = null) - { - if (!Resolve(uid, ref solutionsMgr, false)) - solutionsMgr = EntityManager.EnsureComponent(uid); - - if (!solutionsMgr.Solutions.TryGetValue(name, out var existing)) - { - var newSolution = new Solution(reagents, setMaxVol); - solutionsMgr.Solutions.Add(name, newSolution); - return newSolution; - } - - existing.SetContents(reagents, setMaxVol); - return existing; - } - /// - /// Removes an amount from all reagents in a solution, adding it to a new solution. - /// - /// The entity containing the solution. - /// The solution to remove reagents from. - /// The amount to remove from every reagent in the solution. - /// A new solution containing every removed reagent from the original solution. - public Solution RemoveEachReagent(EntityUid uid, Solution solution, FixedPoint2 quantity) - { - if (quantity <= 0) - return new Solution(); - - var removedSolution = new Solution(); - - // RemoveReagent does a RemoveSwap, meaning we don't have to copy the list if we iterate it backwards. - for (var i = solution.Contents.Count - 1; i >= 0; i--) - { - var (reagent, _) = solution.Contents[i]; - var removedQuantity = solution.RemoveReagent(reagent, quantity); - removedSolution.AddReagent(reagent, removedQuantity); - } - - UpdateChemicals(uid, solution); - return removedSolution; - } - - public FixedPoint2 GetTotalPrototypeQuantity(EntityUid owner, string reagentId) - { - var reagentQuantity = FixedPoint2.New(0); - if (EntityManager.EntityExists(owner) - && EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent)) - { - foreach (var solution in managerComponent.Solutions.Values) - { - reagentQuantity += solution.GetTotalPrototypeQuantity(reagentId); - } - } - - return reagentQuantity; - } - - public bool TryGetMixableSolution(EntityUid uid, - [NotNullWhen(true)] out Solution? solution, - SolutionContainerManagerComponent? solutionsMgr = null) - { - - if (!Resolve(uid, ref solutionsMgr, false)) - { - solution = null; - return false; - } - - var getMixableSolutionAttempt = new GetMixableSolutionAttemptEvent(uid); - RaiseLocalEvent(uid, ref getMixableSolutionAttempt); - if (getMixableSolutionAttempt.MixedSolution != null) - { - solution = getMixableSolutionAttempt.MixedSolution; - return true; - } - - var tryGetSolution = solutionsMgr.Solutions.FirstOrNull(x => x.Value.CanMix); - if (tryGetSolution.HasValue) - { - solution = tryGetSolution.Value.Value; - return true; - } - - solution = null; - return false; - } - - /// - /// Gets the most common reagent across all solutions by volume. - /// - /// - public ReagentPrototype? GetMaxReagent(SolutionContainerManagerComponent component) - { - if (component.Solutions.Count == 0) - return null; - - var reagentCounts = new Dictionary(); - - foreach (var solution in component.Solutions.Values) - { - foreach (var (reagent, quantity) in solution.Contents) - { - reagentCounts.TryGetValue(reagent, out var existing); - existing += quantity; - reagentCounts[reagent] = existing; - } - } - - var max = reagentCounts.Max(); - - return _prototypeManager.Index(max.Key.Prototype); - } - - public SoundSpecifier? GetSound(SolutionContainerManagerComponent component) - { - var max = GetMaxReagent(component); - return max?.FootstepSound; - } - - // Thermal energy and temperature management. - - #region Thermal Energy and Temperature - - /// - /// Sets the temperature of a solution to a new value and then checks for reaction processing. - /// - /// The entity in which the solution is located. - /// The solution to set the temperature of. - /// The new value to set the temperature to. - public void SetTemperature(EntityUid owner, Solution solution, float temperature) - { - if (temperature == solution.Temperature) - return; - - solution.Temperature = temperature; - UpdateChemicals(owner, solution, true); - } - - /// - /// Sets the thermal energy of a solution to a new value and then checks for reaction processing. - /// - /// The entity in which the solution is located. - /// The solution to set the thermal energy of. - /// The new value to set the thermal energy to. - public void SetThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy) - { - var heatCap = solution.GetHeatCapacity(_prototypeManager); - solution.Temperature = heatCap == 0 ? 0 : thermalEnergy / heatCap; - UpdateChemicals(owner, solution, true); - } - - /// - /// Adds some thermal energy to a solution and then checks for reaction processing. - /// - /// The entity in which the solution is located. - /// The solution to set the thermal energy of. - /// The new value to set the thermal energy to. - public void AddThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy) - { - if (thermalEnergy == 0.0f) - return; - - var heatCap = solution.GetHeatCapacity(_prototypeManager); - solution.Temperature += heatCap == 0 ? 0 : thermalEnergy / heatCap; - UpdateChemicals(owner, solution, true); - } - - #endregion Thermal Energy and Temperature - - #region Event Handlers - - #endregion Event Handlers -} diff --git a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs index 05e176da5b..dcd135e3ab 100644 --- a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs +++ b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs @@ -1,14 +1,13 @@ -using System.Collections.Frozen; -using System.Linq; using Content.Shared.Administration.Logs; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.FixedPoint; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Utility; +using System.Collections.Frozen; +using System.Linq; namespace Content.Shared.Chemistry.Reaction { @@ -49,7 +48,7 @@ namespace Content.Shared.Chemistry.Reaction { // Construct single-reaction dictionary. var dict = new Dictionary>(); - foreach(var reaction in _prototypeManager.EnumeratePrototypes()) + foreach (var reaction in _prototypeManager.EnumeratePrototypes()) { // For this dictionary we only need to cache based on the first reagent. var reagent = reaction.Reactants.Keys.First(); @@ -59,7 +58,7 @@ namespace Content.Shared.Chemistry.Reaction _reactionsSingle = dict.ToFrozenDictionary(); dict.Clear(); - foreach(var reaction in _prototypeManager.EnumeratePrototypes()) + foreach (var reaction in _prototypeManager.EnumeratePrototypes()) { foreach (var reagent in reaction.Reactants.Keys) { @@ -87,8 +86,10 @@ namespace Content.Shared.Chemistry.Reaction /// The reaction to check. /// How many times this reaction can occur. /// - private bool CanReact(Solution solution, ReactionPrototype reaction, EntityUid owner, ReactionMixerComponent? mixerComponent, out FixedPoint2 lowestUnitReactions) + private bool CanReact(Entity soln, ReactionPrototype reaction, ReactionMixerComponent? mixerComponent, out FixedPoint2 lowestUnitReactions) { + var solution = soln.Comp.Solution; + lowestUnitReactions = FixedPoint2.MaxValue; if (solution.Temperature < reaction.MinimumTemperature) { @@ -101,15 +102,15 @@ namespace Content.Shared.Chemistry.Reaction return false; } - if((mixerComponent == null && reaction.MixingCategories != null) || + if ((mixerComponent == null && reaction.MixingCategories != null) || mixerComponent != null && reaction.MixingCategories != null && reaction.MixingCategories.Except(mixerComponent.ReactionTypes).Any()) { lowestUnitReactions = FixedPoint2.Zero; return false; } - var attempt = new ReactionAttemptEvent(reaction, solution); - RaiseLocalEvent(owner, attempt); + var attempt = new ReactionAttemptEvent(reaction, soln); + RaiseLocalEvent(soln, ref attempt); if (attempt.Cancelled) { lowestUnitReactions = FixedPoint2.Zero; @@ -155,8 +156,11 @@ namespace Content.Shared.Chemistry.Reaction /// Perform a reaction on a solution. This assumes all reaction criteria are met. /// Removes the reactants from the solution, adds products, and returns a list of products. /// - private List PerformReaction(Solution solution, EntityUid owner, ReactionPrototype reaction, FixedPoint2 unitReactions) + private List PerformReaction(Entity soln, ReactionPrototype reaction, FixedPoint2 unitReactions) { + var (uid, comp) = soln; + var solution = comp.Solution; + var energy = reaction.ConserveEnergy ? solution.GetThermalEnergy(_prototypeManager) : 0; //Remove reactants @@ -184,20 +188,20 @@ namespace Content.Shared.Chemistry.Reaction solution.Temperature = energy / newCap; } - OnReaction(solution, reaction, null, owner, unitReactions); + OnReaction(soln, reaction, null, unitReactions); return products; } - private void OnReaction(Solution solution, ReactionPrototype reaction, ReagentPrototype? reagent, EntityUid owner, FixedPoint2 unitReactions) + private void OnReaction(Entity soln, ReactionPrototype reaction, ReagentPrototype? reagent, FixedPoint2 unitReactions) { - var args = new ReagentEffectArgs(owner, null, solution, + var args = new ReagentEffectArgs(soln, null, soln.Comp.Solution, reagent, unitReactions, EntityManager, null, 1f); - var coordinates = Transform(owner).Coordinates; + var coordinates = Transform(soln).Coordinates; _adminLogger.Add(LogType.ChemicalReaction, reaction.Impact, - $"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(owner):metabolizer} at {coordinates}"); + $"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(soln):metabolizer} at {coordinates}"); foreach (var effect in reaction.Effects) { @@ -214,7 +218,7 @@ namespace Content.Shared.Chemistry.Reaction effect.Effect(args); } - _audio.PlayPvs(reaction.Sound, owner); + _audio.PlayPvs(reaction.Sound, soln); } /// @@ -222,7 +226,7 @@ namespace Content.Shared.Chemistry.Reaction /// Removes the reactants from the solution, then returns a solution with all products. /// WARNING: Does not trigger reactions between solution and new products. /// - private bool ProcessReactions(Solution solution, EntityUid owner, FixedPoint2 maxVolume, SortedSet reactions, ReactionMixerComponent? mixerComponent) + private bool ProcessReactions(Entity soln, SortedSet reactions, ReactionMixerComponent? mixerComponent) { HashSet toRemove = new(); List? products = null; @@ -230,13 +234,13 @@ namespace Content.Shared.Chemistry.Reaction // attempt to perform any applicable reaction foreach (var reaction in reactions) { - if (!CanReact(solution, reaction, owner, mixerComponent, out var unitReactions)) + if (!CanReact(soln, reaction, mixerComponent, out var unitReactions)) { toRemove.Add(reaction); continue; } - products = PerformReaction(solution, owner, reaction, unitReactions); + products = PerformReaction(soln, reaction, unitReactions); break; } @@ -261,11 +265,11 @@ namespace Content.Shared.Chemistry.Reaction /// /// Continually react a solution until no more reactions occur, with a volume constraint. /// - public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent = null) + public void FullyReactSolution(Entity soln, ReactionMixerComponent? mixerComponent = null) { // construct the initial set of reactions to check. SortedSet reactions = new(); - foreach (var reactant in solution.Contents) + foreach (var reactant in soln.Comp.Solution.Contents) { if (_reactionsSingle.TryGetValue(reactant.Reagent.Prototype, out var reactantReactions)) reactions.UnionWith(reactantReactions); @@ -275,11 +279,11 @@ namespace Content.Shared.Chemistry.Reaction // exceed the iteration limit. for (var i = 0; i < MaxReactionIterations; i++) { - if (!ProcessReactions(solution, owner, maxVolume, reactions, mixerComponent)) + if (!ProcessReactions(soln, reactions, mixerComponent)) return; } - Log.Error($"{nameof(Solution)} {owner} could not finish reacting in under {MaxReactionIterations} loops."); + Log.Error($"{nameof(Solution)} {soln.Owner} could not finish reacting in under {MaxReactionIterations} loops."); } } @@ -289,15 +293,11 @@ namespace Content.Shared.Chemistry.Reaction /// /// Some solution containers (e.g., bloodstream, smoke, foam) use this to block certain reactions from occurring. /// - public sealed class ReactionAttemptEvent : CancellableEntityEventArgs + [ByRefEvent] + public record struct ReactionAttemptEvent(ReactionPrototype Reaction, Entity Solution) { - public readonly ReactionPrototype Reaction; - public readonly Solution Solution; - - public ReactionAttemptEvent(ReactionPrototype reaction, Solution solution) - { - Reaction = reaction; - Solution = solution; - } + public readonly ReactionPrototype Reaction = Reaction; + public readonly Entity Solution = Solution; + public bool Cancelled = false; } } diff --git a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs index a88bf02bf8..ede73c4969 100644 --- a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs +++ b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs @@ -27,4 +27,4 @@ public record struct MixingAttemptEvent(EntityUid Mixed, bool Cancelled = false) public readonly record struct AfterMixingEvent(EntityUid Mixed, EntityUid Mixer); [ByRefEvent] -public record struct GetMixableSolutionAttemptEvent(EntityUid Mixed, Solution? MixedSolution = null); +public record struct GetMixableSolutionAttemptEvent(EntityUid Mixed, Entity? MixedSolution = null); diff --git a/Content.Shared/Chemistry/ReactiveSystem.cs b/Content.Shared/Chemistry/ReactiveSystem.cs index 4881a6bf96..57b008de0c 100644 --- a/Content.Shared/Chemistry/ReactiveSystem.cs +++ b/Content.Shared/Chemistry/ReactiveSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; -using Content.Shared.FixedPoint; using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Random; diff --git a/Content.Shared/Chemistry/SharedChemMaster.cs b/Content.Shared/Chemistry/SharedChemMaster.cs index 027002098e..762131d761 100644 --- a/Content.Shared/Chemistry/SharedChemMaster.cs +++ b/Content.Shared/Chemistry/SharedChemMaster.cs @@ -1,4 +1,3 @@ -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Serialization; diff --git a/Content.Shared/Fluids/Components/DrainComponent.cs b/Content.Shared/Fluids/Components/DrainComponent.cs index 84331851d1..4fb4fe9438 100644 --- a/Content.Shared/Fluids/Components/DrainComponent.cs +++ b/Content.Shared/Fluids/Components/DrainComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Chemistry.Components; using Content.Shared.Tag; using Robust.Shared.Audio; @@ -19,6 +20,9 @@ public sealed partial class DrainComponent : Component [ValidatePrototypeId] public const string PlungerTag = "Plunger"; + [DataField] + public Entity? Solution = null; + [DataField("accumulator")] public float Accumulator = 0f; diff --git a/Content.Shared/Fluids/Components/PuddleComponent.cs b/Content.Shared/Fluids/Components/PuddleComponent.cs index 4abacf1ac9..bc40e9960c 100644 --- a/Content.Shared/Fluids/Components/PuddleComponent.cs +++ b/Content.Shared/Fluids/Components/PuddleComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Chemistry.Components; using Content.Shared.FixedPoint; using Robust.Shared.Audio; using Robust.Shared.GameStates; @@ -17,5 +18,8 @@ namespace Content.Shared.Fluids.Components public FixedPoint2 OverflowVolume = FixedPoint2.New(20); [DataField("solution")] public string SolutionName = "puddle"; + + [DataField("solutionRef")] + public Entity? Solution; } } diff --git a/Content.Shared/Fluids/SharedPuddleSystem.cs b/Content.Shared/Fluids/SharedPuddleSystem.cs index 056c3ba919..08a7624c4a 100644 --- a/Content.Shared/Fluids/SharedPuddleSystem.cs +++ b/Content.Shared/Fluids/SharedPuddleSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Chemistry.Components; using Content.Shared.DragDrop; -using Content.Shared.Fluids.Components; namespace Content.Shared.Fluids; @@ -22,12 +21,12 @@ public abstract class SharedPuddleSystem : EntitySystem SubscribeLocalEvent(OnRefillableCanDropDragged); } - private void OnRefillableCanDrag(EntityUid uid, RefillableSolutionComponent component, ref CanDragEvent args) + private void OnRefillableCanDrag(Entity entity, ref CanDragEvent args) { args.Handled = true; } - private void OnDumpCanDropTarget(EntityUid uid, DumpableSolutionComponent component, ref CanDropTargetEvent args) + private void OnDumpCanDropTarget(Entity entity, ref CanDropTargetEvent args) { if (HasComp(args.Dragged)) { @@ -36,7 +35,7 @@ public abstract class SharedPuddleSystem : EntitySystem } } - private void OnDrainCanDropTarget(EntityUid uid, DrainableSolutionComponent component, ref CanDropTargetEvent args) + private void OnDrainCanDropTarget(Entity entity, ref CanDropTargetEvent args) { if (HasComp(args.Dragged)) { @@ -45,7 +44,7 @@ public abstract class SharedPuddleSystem : EntitySystem } } - private void OnRefillableCanDropDragged(EntityUid uid, RefillableSolutionComponent component, ref CanDropDraggedEvent args) + private void OnRefillableCanDropDragged(Entity entity, ref CanDropDraggedEvent args) { if (!HasComp(args.Target) && !HasComp(args.Target)) return; diff --git a/Content.Shared/Kitchen/Components/SharedMicrowave.cs b/Content.Shared/Kitchen/Components/SharedMicrowave.cs index e86ecf01c5..ed07fd1287 100644 --- a/Content.Shared/Kitchen/Components/SharedMicrowave.cs +++ b/Content.Shared/Kitchen/Components/SharedMicrowave.cs @@ -1,4 +1,3 @@ -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Robust.Shared.Serialization; diff --git a/Content.Shared/Kitchen/SharedReagentGrinder.cs b/Content.Shared/Kitchen/SharedReagentGrinder.cs index dc94884288..f5d679c293 100644 --- a/Content.Shared/Kitchen/SharedReagentGrinder.cs +++ b/Content.Shared/Kitchen/SharedReagentGrinder.cs @@ -1,4 +1,3 @@ -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Robust.Shared.Serialization; diff --git a/Content.Shared/Materials/MaterialReclaimerComponent.cs b/Content.Shared/Materials/MaterialReclaimerComponent.cs index eda5cc4058..91bd59614a 100644 --- a/Content.Shared/Materials/MaterialReclaimerComponent.cs +++ b/Content.Shared/Materials/MaterialReclaimerComponent.cs @@ -1,5 +1,4 @@ -using Content.Shared.Chemistry.Components; -using Content.Shared.Construction.Prototypes; +using Content.Shared.Construction.Prototypes; using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; @@ -84,12 +83,6 @@ public sealed partial class MaterialReclaimerComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public string SolutionContainerId = "output"; - /// - /// The solution itself. - /// - [ViewVariables(VVAccess.ReadWrite)] - public Solution OutputSolution = default!; - /// /// a whitelist for what entities can be inserted into this reclaimer /// diff --git a/Content.Shared/Nutrition/Events.cs b/Content.Shared/Nutrition/Events.cs index 97d96e7bff..e27603763f 100644 --- a/Content.Shared/Nutrition/Events.cs +++ b/Content.Shared/Nutrition/Events.cs @@ -1,6 +1,6 @@ -using Content.Shared.DoAfter; +using Content.Shared.Chemistry.Components; +using Content.Shared.DoAfter; using Robust.Shared.Serialization; -using Content.Shared.Chemistry.Components; namespace Content.Shared.Nutrition; @@ -47,8 +47,8 @@ public sealed partial class VapeDoAfterEvent : DoAfterEvent public VapeDoAfterEvent(Solution solution, bool forced) { - Solution = solution; - Forced = forced; + Solution = solution; + Forced = forced; } public override DoAfterEvent Clone() => this; diff --git a/Content.Tests/Shared/Chemistry/SolutionTests.cs b/Content.Tests/Shared/Chemistry/SolutionTests.cs index 0fa23d2491..7f6e335b36 100644 --- a/Content.Tests/Shared/Chemistry/SolutionTests.cs +++ b/Content.Tests/Shared/Chemistry/SolutionTests.cs @@ -1,9 +1,8 @@ using Content.Shared.Chemistry.Components; using Content.Shared.FixedPoint; +using NUnit.Framework; using Robust.Shared.IoC; using Robust.Shared.Prototypes; -using NUnit.Framework; -using Robust.Shared.Utility; namespace Content.Tests.Shared.Chemistry;