diff --git a/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs b/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs
index 7e46cb0ab2..6c070d3c2e 100644
--- a/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs
+++ b/Content.Client/Administration/UI/ManageSolutions/EditSolutionsWindow.xaml.cs
@@ -1,4 +1,5 @@
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
@@ -176,16 +177,16 @@ namespace Content.Client.Administration.UI.ManageSolutions
///
/// Add a single reagent entry to the list
///
- private void AddReagentEntry(Solution.ReagentQuantity reagent)
+ private void AddReagentEntry(ReagentQuantity reagentQuantity)
{
var box = new BoxContainer();
var spin = new FloatSpinBox(1, 2);
- spin.Value = reagent.Quantity.Float();
- spin.OnValueChanged += (args) => SetReagent(args, reagent.ReagentId);
+ spin.Value = reagentQuantity.Quantity.Float();
+ spin.OnValueChanged += (args) => SetReagent(args, reagentQuantity.Reagent.Prototype);
spin.HorizontalExpand = true;
- box.AddChild(new Label() { Text = reagent.ReagentId , HorizontalExpand = true});
+ box.AddChild(new Label() { Text = reagentQuantity.Reagent.Prototype , HorizontalExpand = true});
box.AddChild(spin);
ReagentList.AddChild(box);
@@ -194,18 +195,18 @@ namespace Content.Client.Administration.UI.ManageSolutions
///
/// Execute a command to modify the reagents in the solution.
///
- private void SetReagent(FloatSpinBox.FloatSpinBoxEventArgs args, string reagentId)
+ private void SetReagent(FloatSpinBox.FloatSpinBoxEventArgs args, string prototype)
{
if (_solutions == null || _selectedSolution == null)
return;
- var current = _solutions[_selectedSolution].GetReagentQuantity(reagentId);
+ var current = _solutions[_selectedSolution].GetTotalPrototypeQuantity(prototype);
var delta = args.Value - current.Float();
if (MathF.Abs(delta) < 0.01)
return;
- var command = $"addreagent {_target} {_selectedSolution} {reagentId} {delta}";
+ var command = $"addreagent {_target} {_selectedSolution} {prototype} {delta}";
_consoleHost.ExecuteCommand(command);
}
diff --git a/Content.Client/Chemistry/UI/ChemMasterWindow.xaml.cs b/Content.Client/Chemistry/UI/ChemMasterWindow.xaml.cs
index bf68a55d00..5eace08a7f 100644
--- a/Content.Client/Chemistry/UI/ChemMasterWindow.xaml.cs
+++ b/Content.Client/Chemistry/UI/ChemMasterWindow.xaml.cs
@@ -11,6 +11,7 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
using System.Numerics;
+using Content.Shared.FixedPoint;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Chemistry.UI
@@ -87,7 +88,7 @@ namespace Content.Client.Chemistry.UI
Tabs.SetTabTitle(1, Loc.GetString("chem-master-window-output-tab"));
}
- private ReagentButton MakeReagentButton(string text, ChemMasterReagentAmount amount, string id, bool isBuffer, string styleClass)
+ private ReagentButton MakeReagentButton(string text, ChemMasterReagentAmount amount, ReagentId id, bool isBuffer, string styleClass)
{
var button = new ReagentButton(text, amount, id, isBuffer, styleClass);
button.OnPressed += args
@@ -112,11 +113,11 @@ namespace Content.Client.Chemistry.UI
InputEjectButton.Disabled = castState.InputContainerInfo is null;
OutputEjectButton.Disabled = output is null;
- CreateBottleButton.Disabled = output is null || !output.HoldsReagents;
- CreatePillButton.Disabled = output is null || output.HoldsReagents;
+ CreateBottleButton.Disabled = output?.Reagents == null;
+ CreatePillButton.Disabled = output?.Entities == null;
var remainingCapacity = output is null ? 0 : (output.MaxVolume - output.CurrentVolume).Int();
- var holdsReagents = output?.HoldsReagents ?? false;
+ var holdsReagents = output?.Reagents != null;
var pillNumberMax = holdsReagents ? 0 : remainingCapacity;
var bottleAmountMax = holdsReagents ? remainingCapacity : 0;
@@ -139,13 +140,10 @@ namespace Content.Client.Chemistry.UI
{
if (state.BufferCurrentVolume == 0)
return "";
- else
- {
- var reagent = state.BufferReagents.OrderBy(r => r.Quantity).First();
- _prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? proto);
- return proto?.LocalizedName ?? "";
- }
+ var reagent = state.BufferReagents.OrderBy(r => r.Quantity).First().Reagent;
+ _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
+ return proto?.LocalizedName ?? "";
}
///
@@ -184,10 +182,10 @@ namespace Content.Client.Chemistry.UI
};
bufferHBox.AddChild(bufferVol);
- foreach (var reagent in state.BufferReagents)
+ foreach (var (reagent, quantity) in state.BufferReagents)
{
// Try to get the prototype for the given reagent. This gives us its name.
- _prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? proto);
+ _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
if (proto != null)
@@ -200,20 +198,20 @@ namespace Content.Client.Chemistry.UI
new Label {Text = $"{name}: "},
new Label
{
- Text = $"{reagent.Quantity}u",
+ Text = $"{quantity}u",
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
},
// Padding
new Control {HorizontalExpand = true},
- MakeReagentButton("1", ChemMasterReagentAmount.U1, reagent.ReagentId, true, StyleBase.ButtonOpenRight),
- MakeReagentButton("5", ChemMasterReagentAmount.U5, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
- MakeReagentButton("10", ChemMasterReagentAmount.U10, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
- MakeReagentButton("25", ChemMasterReagentAmount.U25, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
- MakeReagentButton("50", ChemMasterReagentAmount.U50, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
- MakeReagentButton("100", ChemMasterReagentAmount.U100, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
- MakeReagentButton(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, reagent.ReagentId, true, StyleBase.ButtonOpenLeft),
+ MakeReagentButton("1", ChemMasterReagentAmount.U1, reagent, true, StyleBase.ButtonOpenRight),
+ MakeReagentButton("5", ChemMasterReagentAmount.U5, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("10", ChemMasterReagentAmount.U10, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("25", ChemMasterReagentAmount.U25, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("50", ChemMasterReagentAmount.U50, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("100", ChemMasterReagentAmount.U100, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, reagent, true, StyleBase.ButtonOpenLeft),
}
});
}
@@ -248,20 +246,29 @@ namespace Content.Client.Chemistry.UI
}
});
- var contents = info.Contents
- .Select(lineItem =>
- {
- if (!info.HoldsReagents)
- return (lineItem.Id, lineItem.Id, lineItem.Quantity);
+ IEnumerable<(string Name, ReagentId Id, FixedPoint2 Quantity)> contents;
- // Try to get the prototype for the given reagent. This gives us its name.
- _prototypeManager.TryIndex(lineItem.Id, out ReagentPrototype? proto);
- var name = proto?.LocalizedName
- ?? Loc.GetString("chem-master-window-unknown-reagent-text");
+ if (info.Entities != null)
+ {
+ contents = info.Entities.Select(x => (x.Id, default(ReagentId), x.Quantity));
+ }
+ else if (info.Reagents != null)
+ {
+ contents = info.Reagents.Select(x =>
+ {
+ _prototypeManager.TryIndex(x.Reagent.Prototype, out ReagentPrototype? proto);
+ var name = proto?.LocalizedName
+ ?? Loc.GetString("chem-master-window-unknown-reagent-text");
+
+ return (name, Id: x.Reagent, x.Quantity);
+ })
+ .OrderBy(r => r.Item1);
+ }
+ else
+ {
+ return;
+ }
- return (name, lineItem.Id, lineItem.Quantity);
- })
- .OrderBy(r => r.Item1);
foreach (var (name, id, quantity) in contents)
{
@@ -326,8 +333,8 @@ namespace Content.Client.Chemistry.UI
{
public ChemMasterReagentAmount Amount { get; set; }
public bool IsBuffer = true;
- public string Id { get; set; }
- public ReagentButton(string text, ChemMasterReagentAmount amount, string id, bool isBuffer, string styleClass)
+ public ReagentId Id { get; set; }
+ public ReagentButton(string text, ChemMasterReagentAmount amount, ReagentId id, bool isBuffer, string styleClass)
{
AddStyleClass(styleClass);
Text = text;
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
index 64b5f5ddd2..bf08d4978e 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
+++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
@@ -48,17 +48,17 @@ namespace Content.Client.Chemistry.UI
/// Update the button grid of reagents which can be dispensed.
///
/// Reagents which can be dispensed by this dispenser
- public void UpdateReagentsList(List inventory)
+ public void UpdateReagentsList(List inventory)
{
- if (ChemicalList == null) return;
- if (inventory == null) return;
+ if (ChemicalList == null)
+ return;
ChemicalList.Children.Clear();
foreach (var entry in inventory
- .OrderBy(r => {_prototypeManager.TryIndex(r, out ReagentPrototype? p); return p?.LocalizedName;}))
+ .OrderBy(r => {_prototypeManager.TryIndex(r.Prototype, out ReagentPrototype? p); return p?.LocalizedName;}))
{
- var localizedName = _prototypeManager.TryIndex(entry, out ReagentPrototype? p)
+ var localizedName = _prototypeManager.TryIndex(entry.Prototype, out ReagentPrototype? p)
? p.LocalizedName
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
@@ -123,7 +123,7 @@ namespace Content.Client.Chemistry.UI
/// State data for the dispenser.
/// Prototype ID of the reagent whose dispense button is currently being mouse hovered,
/// or null if no button is being hovered.
- public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state, string? highlightedReagentId = null)
+ public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state, ReagentId? highlightedReagentId = null)
{
ContainerInfo.Children.Clear();
@@ -147,22 +147,22 @@ namespace Content.Client.Chemistry.UI
}
});
- foreach (var reagent in state.OutputContainer.Contents)
+ foreach (var (reagent, quantity) in state.OutputContainer.Reagents!)
{
// Try get to the prototype for the given reagent. This gives us its name.
- var localizedName = _prototypeManager.TryIndex(reagent.Id, out ReagentPrototype? p)
+ var localizedName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? p)
? p.LocalizedName
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
var nameLabel = new Label {Text = $"{localizedName}: "};
var quantityLabel = new Label
{
- Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", reagent.Quantity)),
+ Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity)),
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor},
};
// Check if the reagent is being moused over. If so, color it green.
- if (reagent.Id == highlightedReagentId) {
+ if (reagent == highlightedReagentId) {
nameLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
quantityLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
}
@@ -181,9 +181,9 @@ namespace Content.Client.Chemistry.UI
}
public sealed class DispenseReagentButton : Button {
- public string ReagentId { get; }
+ public ReagentId ReagentId { get; }
- public DispenseReagentButton(string reagentId, string text)
+ public DispenseReagentButton(ReagentId reagentId, string text)
{
ReagentId = reagentId;
Text = text;
diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
index a2237e5f09..79f212bbf6 100644
--- a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
+++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
@@ -83,7 +83,7 @@ namespace Content.Client.Kitchen.UI
}
}
- private void RefreshContentsDisplay(IList? reagents, IReadOnlyList containedSolids, bool isBeakerAttached)
+ private void RefreshContentsDisplay(IList? reagents, IReadOnlyList containedSolids, bool isBeakerAttached)
{
//Refresh chamber contents
_chamberVisualContents.Clear();
@@ -118,9 +118,11 @@ namespace Content.Client.Kitchen.UI
}
else
{
- foreach (var reagent in reagents)
+ foreach (var (reagent, quantity) in reagents)
{
- var reagentName = _prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? proto) ? Loc.GetString($"{reagent.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 87f77e24f7..968d9f30a2 100644
--- a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs
+++ b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs
@@ -1,4 +1,5 @@
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.Kitchen.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
@@ -17,7 +18,7 @@ namespace Content.Client.Kitchen.UI
private readonly Dictionary _solids = new();
[ViewVariables]
- private readonly Dictionary _reagents = new();
+ private readonly Dictionary _reagents = new();
public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
diff --git a/Content.IntegrationTests/Tests/Chemistry/ReagentDataTest.cs b/Content.IntegrationTests/Tests/Chemistry/ReagentDataTest.cs
new file mode 100644
index 0000000000..f488734655
--- /dev/null
+++ b/Content.IntegrationTests/Tests/Chemistry/ReagentDataTest.cs
@@ -0,0 +1,30 @@
+using Content.IntegrationTests.Tests.Interaction;
+using Content.Shared.Chemistry.Reagent;
+using Robust.Shared.Reflection;
+using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
+
+namespace Content.IntegrationTests.Tests.Chemistry;
+
+[TestFixture]
+[TestOf(typeof(ReagentData))]
+public sealed class ReagentDataTest : InteractionTest
+{
+ [Test]
+ public async Task ReagentDataIsSerializable()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+ var reflection = pair.Server.ResolveDependency();
+
+ Assert.Multiple(() =>
+ {
+ foreach (var instance in reflection.GetAllChildren(typeof(ReagentData)))
+ {
+ Assert.That(instance.HasCustomAttribute(), $"{instance} must have the NetSerializable attribute.");
+ Assert.That(instance.HasCustomAttribute(), $"{instance} must have the serializable attribute.");
+ }
+ });
+
+ await pair.CleanReturnAsync();
+ }
+}
diff --git a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs
index a319bc08e0..8d0bbbd067 100644
--- a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs
+++ b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs
@@ -73,8 +73,8 @@ public sealed class SolutionSystemTests
Assert.That(containerSystem
.TryAddSolution(beaker, solution, oilAdded));
- solution.TryGetReagent("Water", out var water);
- solution.TryGetReagent("Oil", out var oil);
+ var water = solution.GetTotalPrototypeQuantity("Water");
+ var oil = solution.GetTotalPrototypeQuantity("Oil");
Assert.Multiple(() =>
{
Assert.That(water, Is.EqualTo(waterQuantity));
@@ -118,8 +118,8 @@ public sealed class SolutionSystemTests
Assert.That(containerSystem
.TryAddSolution(beaker, solution, oilAdded), Is.False);
- solution.TryGetReagent("Water", out var water);
- solution.TryGetReagent("Oil", out var oil);
+ var water = solution.GetTotalPrototypeQuantity("Water");
+ var oil = solution.GetTotalPrototypeQuantity("Oil");
Assert.Multiple(() =>
{
Assert.That(water, Is.EqualTo(waterQuantity));
@@ -168,15 +168,15 @@ public sealed class SolutionSystemTests
{
Assert.That(solution.Volume, Is.EqualTo(FixedPoint2.New(threshold)));
- solution.TryGetReagent("Water", out var waterMix);
- solution.TryGetReagent("Oil", out var oilMix);
+ var waterMix = solution.GetTotalPrototypeQuantity("Water");
+ var oilMix = solution.GetTotalPrototypeQuantity("Oil");
Assert.That(waterMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1))));
Assert.That(oilMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1) * ratio)));
Assert.That(overflowingSolution.Volume, Is.EqualTo(FixedPoint2.New(80)));
- overflowingSolution.TryGetReagent("Water", out var waterOverflow);
- overflowingSolution.TryGetReagent("Oil", out var oilOverFlow);
+ var waterOverflow = overflowingSolution.GetTotalPrototypeQuantity("Water");
+ var oilOverFlow = overflowingSolution.GetTotalPrototypeQuantity("Oil");
Assert.That(waterOverflow, Is.EqualTo(waterQuantity - waterMix));
Assert.That(oilOverFlow, Is.EqualTo(oilQuantity - oilMix));
});
diff --git a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs
index deb3b95a93..30c15e8da3 100644
--- a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs
+++ b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs
@@ -79,9 +79,9 @@ 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 in component.Contents)
+ foreach (var (reagent, quantity) in component.Contents)
{
- Assert.That(foundProductsMap.TryFirstOrNull(x => x.Key.Key == reagent.ReagentId && x.Key.Value == reagent.Quantity, out var foundProduct));
+ 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.Server/Administration/Commands/AddReagent.cs b/Content.Server/Administration/Commands/AddReagent.cs
index aef7f04d46..795de6f91f 100644
--- a/Content.Server/Administration/Commands/AddReagent.cs
+++ b/Content.Server/Administration/Commands/AddReagent.cs
@@ -62,7 +62,7 @@ namespace Content.Server.Administration.Commands
if (quantityFloat > 0)
EntitySystem.Get().TryAddReagent(uid, solution, args[2], quantity, out var _);
else
- EntitySystem.Get().TryRemoveReagent(uid, solution, args[2], quantity);
+ EntitySystem.Get().RemoveReagent(uid, solution, args[2], quantity);
}
}
}
diff --git a/Content.Server/Administration/Toolshed/SolutionCommand.cs b/Content.Server/Administration/Toolshed/SolutionCommand.cs
index 90149ca1dd..5cbd931a70 100644
--- a/Content.Server/Administration/Toolshed/SolutionCommand.cs
+++ b/Content.Server/Administration/Toolshed/SolutionCommand.cs
@@ -59,7 +59,7 @@ public sealed class SolutionCommand : ToolshedCommand
}
else if (amount < 0)
{
- _solutionContainer.TryRemoveReagent(input.Owner, input.Solution, name.Value.ID, -amount);
+ _solutionContainer.RemoveReagent(input.Owner, input.Solution, name.Value.ID, -amount);
}
return input;
diff --git a/Content.Server/Body/Components/StomachComponent.cs b/Content.Server/Body/Components/StomachComponent.cs
index b476e298a6..30f9791525 100644
--- a/Content.Server/Body/Components/StomachComponent.cs
+++ b/Content.Server/Body/Components/StomachComponent.cs
@@ -1,5 +1,7 @@
using Content.Server.Body.Systems;
using Content.Server.Nutrition.EntitySystems;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Content.Shared.Whitelist;
@@ -46,14 +48,12 @@ namespace Content.Server.Body.Components
///
public sealed class ReagentDelta
{
- public readonly string ReagentId;
- public readonly FixedPoint2 Quantity;
+ public readonly ReagentQuantity ReagentQuantity;
public float Lifetime { get; private set; }
- public ReagentDelta(string reagentId, FixedPoint2 quantity)
+ public ReagentDelta(ReagentQuantity reagentQuantity)
{
- ReagentId = reagentId;
- Quantity = quantity;
+ ReagentQuantity = reagentQuantity;
Lifetime = 0.0f;
}
diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs
index 33cb59775b..9ed92da8fc 100644
--- a/Content.Server/Body/Systems/BloodstreamSystem.cs
+++ b/Content.Server/Body/Systems/BloodstreamSystem.cs
@@ -274,9 +274,9 @@ public sealed class BloodstreamSystem : EntitySystem
for (var i = component.ChemicalSolution.Contents.Count - 1; i >= 0; i--)
{
var (reagentId, _) = component.ChemicalSolution.Contents[i];
- if (reagentId != excludedReagentID)
+ if (reagentId.Prototype != excludedReagentID)
{
- _solutionContainerSystem.TryRemoveReagent(uid, component.ChemicalSolution, reagentId, quantity);
+ _solutionContainerSystem.RemoveReagent(uid, component.ChemicalSolution, reagentId, quantity);
}
}
diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs
index 89ffff718b..de06fdc81f 100644
--- a/Content.Server/Body/Systems/MetabolizerSystem.cs
+++ b/Content.Server/Body/Systems/MetabolizerSystem.cs
@@ -128,9 +128,9 @@ namespace Content.Server.Body.Systems
_random.Shuffle(list);
int reagents = 0;
- foreach (var reagent in list)
+ foreach (var (reagent, quantity) in list)
{
- if (!_prototypeManager.TryIndex(reagent.ReagentId, out var proto))
+ if (!_prototypeManager.TryIndex(reagent.Prototype, out var proto))
continue;
var mostToRemove = FixedPoint2.Zero;
@@ -138,7 +138,7 @@ namespace Content.Server.Body.Systems
{
if (meta.RemoveEmpty)
{
- _solutionContainerSystem.TryRemoveReagent(solutionEntityUid.Value, solution, reagent.ReagentId,
+ _solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent,
FixedPoint2.New(1));
}
@@ -168,7 +168,7 @@ namespace Content.Server.Body.Systems
mostToRemove *= group.MetabolismRateModifier;
- mostToRemove = FixedPoint2.Clamp(mostToRemove, 0, reagent.Quantity);
+ mostToRemove = FixedPoint2.Clamp(mostToRemove, 0, quantity);
float scale = (float) mostToRemove / (float) entry.MetabolismRate;
@@ -204,8 +204,7 @@ namespace Content.Server.Body.Systems
// remove a certain amount of reagent
if (mostToRemove > FixedPoint2.Zero)
{
- _solutionContainerSystem.TryRemoveReagent(solutionEntityUid.Value, solution, reagent.ReagentId,
- mostToRemove);
+ _solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent, mostToRemove);
}
}
}
diff --git a/Content.Server/Body/Systems/StomachSystem.cs b/Content.Server/Body/Systems/StomachSystem.cs
index b5d1282465..e33931315a 100644
--- a/Content.Server/Body/Systems/StomachSystem.cs
+++ b/Content.Server/Body/Systems/StomachSystem.cs
@@ -45,14 +45,13 @@ namespace Content.Server.Body.Systems
delta.Increment(stomach.UpdateInterval);
if (delta.Lifetime > stomach.DigestionDelay)
{
- if (stomachSolution.TryGetReagent(delta.ReagentId, out var quant))
+ if (stomachSolution.TryGetReagent(delta.ReagentQuantity.Reagent, out var reagent))
{
- if (quant > delta.Quantity)
- quant = delta.Quantity;
+ if (reagent.Quantity > delta.ReagentQuantity.Quantity)
+ reagent = new(reagent.Reagent, delta.ReagentQuantity.Quantity);
- _solutionContainerSystem.TryRemoveReagent((stomach).Owner, stomachSolution,
- delta.ReagentId, quant);
- transferSolution.AddReagent(delta.ReagentId, quant);
+ _solutionContainerSystem.RemoveReagent((stomach).Owner, stomachSolution, reagent);
+ transferSolution.AddReagent(reagent);
}
queue.Add(delta);
@@ -116,7 +115,7 @@ namespace Content.Server.Body.Systems
// Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach
foreach (var reagent in solution.Contents)
{
- stomach.ReagentDeltas.Add(new StomachComponent.ReagentDelta(reagent.ReagentId, reagent.Quantity));
+ stomach.ReagentDeltas.Add(new StomachComponent.ReagentDelta(reagent));
}
return true;
diff --git a/Content.Server/Botany/Systems/PlantHolderSystem.cs b/Content.Server/Botany/Systems/PlantHolderSystem.cs
index 1c0582e5f4..43255170b2 100644
--- a/Content.Server/Botany/Systems/PlantHolderSystem.cs
+++ b/Content.Server/Botany/Systems/PlantHolderSystem.cs
@@ -824,10 +824,10 @@ namespace Content.Server.Botany.Systems
if (solution.Volume > 0 && component.MutationLevel < 25)
{
var amt = FixedPoint2.New(1);
- foreach (var (reagentId, quantity) in _solutionSystem.RemoveEachReagent(uid, solution, amt))
+ foreach (var entry in _solutionSystem.RemoveEachReagent(uid, solution, amt))
{
- var reagentProto = _prototype.Index(reagentId);
- reagentProto.ReactionPlant(uid, new Solution.ReagentQuantity(reagentId, quantity), solution);
+ 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 e8e9909a2a..1f6d941b6b 100644
--- a/Content.Server/Cargo/Systems/PricingSystem.cs
+++ b/Content.Server/Cargo/Systems/PricingSystem.cs
@@ -110,11 +110,13 @@ public sealed class PricingSystem : EntitySystem
foreach (var solution in component.Solutions.Values)
{
- foreach (var reagent in solution.Contents)
+ foreach (var (reagent, quantity) in solution.Contents)
{
- if (!_prototypeManager.TryIndex(reagent.ReagentId, out var reagentProto))
+ if (!_prototypeManager.TryIndex(reagent.Prototype, out var reagentProto))
continue;
- price += (float) reagent.Quantity * reagentProto.PricePerUnit;
+
+ // TODO check ReagentData for price information?
+ price += (float) quantity * reagentProto.PricePerUnit;
}
}
diff --git a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs
index 2ec7ad5c49..3e5250d8bd 100644
--- a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs
@@ -8,6 +8,7 @@ using Content.Server.Storage.EntitySystems;
using Content.Shared.Administration.Logs;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
@@ -117,7 +118,7 @@ namespace Content.Server.Chemistry.EntitySystems
ClickSound(chemMaster);
}
- private void TransferReagents(ChemMasterComponent chemMaster, string reagentId, FixedPoint2 amount, bool fromBuffer)
+ private void TransferReagents(ChemMasterComponent chemMaster, ReagentId id, FixedPoint2 amount, bool fromBuffer)
{
var container = _itemSlotsSystem.GetItemOrNull(chemMaster.Owner, SharedChemMaster.InputSlotName);
if (container is null ||
@@ -130,26 +131,26 @@ namespace Content.Server.Chemistry.EntitySystems
if (fromBuffer) // Buffer to container
{
amount = FixedPoint2.Min(amount, containerSolution.AvailableVolume);
- amount = bufferSolution.RemoveReagent(reagentId, amount);
- _solutionContainerSystem.TryAddReagent(container.Value, containerSolution, reagentId, amount, out var _);
+ amount = bufferSolution.RemoveReagent(id, amount);
+ _solutionContainerSystem.TryAddReagent(container.Value, containerSolution, id, amount, out var _);
}
else // Container to buffer
{
- amount = FixedPoint2.Min(amount, containerSolution.GetReagentQuantity(reagentId));
- _solutionContainerSystem.TryRemoveReagent(container.Value, containerSolution, reagentId, amount);
- bufferSolution.AddReagent(reagentId, amount);
+ amount = FixedPoint2.Min(amount, containerSolution.GetReagentQuantity(id));
+ _solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount);
+ bufferSolution.AddReagent(id, amount);
}
UpdateUiState(chemMaster, updateLabel: true);
}
- private void DiscardReagents(ChemMasterComponent chemMaster, string reagentId, FixedPoint2 amount, bool fromBuffer)
+ private void DiscardReagents(ChemMasterComponent chemMaster, ReagentId id, FixedPoint2 amount, bool fromBuffer)
{
if (fromBuffer)
{
if (_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out var bufferSolution))
- bufferSolution.RemoveReagent(reagentId, amount);
+ bufferSolution.RemoveReagent(id, amount);
else
return;
}
@@ -159,7 +160,7 @@ namespace Content.Server.Chemistry.EntitySystems
if (container is not null &&
_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution))
{
- _solutionContainerSystem.TryRemoveReagent(container.Value, containerSolution, reagentId, amount);
+ _solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount);
}
else
return;
@@ -349,17 +350,21 @@ namespace Content.Server.Chemistry.EntitySystems
return (Name(pill), quantity);
})).ToList();
- return pills is null
- ? null
- : new ContainerInfo(name, false, storage.StorageUsed, storage.StorageCapacityMax, pills);
+ if (pills == null)
+ return null;
+
+ return new ContainerInfo(name, storage.StorageUsed, storage.StorageCapacityMax)
+ {
+ Entities = pills
+ };
}
private static ContainerInfo BuildContainerInfo(string name, Solution solution)
{
- var reagents = solution.Contents
- .Select(reagent => (reagent.ReagentId, reagent.Quantity)).ToList();
-
- return new ContainerInfo(name, true, solution.Volume, solution.MaxVolume, reagents);
+ return new ContainerInfo(name, solution.Volume, solution.MaxVolume)
+ {
+ Reagents = solution.Contents
+ };
}
}
}
diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
index 9a1d560f34..a84dff49d8 100644
--- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
@@ -3,6 +3,7 @@ using Content.Server.Administration.Logs;
using Content.Server.Chemistry.Components;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Dispenser;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
using Content.Shared.Emag.Components;
@@ -63,28 +64,30 @@ namespace Content.Server.Chemistry.EntitySystems
if (_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var solution))
{
- var reagents = solution.Contents.Select(reagent => (reagent.ReagentId, reagent.Quantity)).ToList();
- return new ContainerInfo(Name(container.Value), true, solution.Volume, solution.MaxVolume, reagents);
+ return new ContainerInfo(Name(container.Value), solution.Volume, solution.MaxVolume)
+ {
+ Reagents = solution.Contents
+ };
}
return null;
}
- private List GetInventory(ReagentDispenserComponent reagentDispenser)
+ private List GetInventory(ReagentDispenserComponent reagentDispenser)
{
- var inventory = new List();
+ var inventory = new List();
if (reagentDispenser.PackPrototypeId is not null
&& _prototypeManager.TryIndex(reagentDispenser.PackPrototypeId, out ReagentDispenserInventoryPrototype? packPrototype))
{
- inventory.AddRange(packPrototype.Inventory);
+ inventory.AddRange(packPrototype.Inventory.Select(x => new ReagentId(x, null)));
}
if (HasComp(reagentDispenser.Owner)
&& reagentDispenser.EmagPackPrototypeId is not null
&& _prototypeManager.TryIndex(reagentDispenser.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype))
{
- inventory.AddRange(emagPackPrototype.Inventory);
+ inventory.AddRange(emagPackPrototype.Inventory.Select(x => new ReagentId(x, null)));
}
return inventory;
diff --git a/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs b/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs
index 3dd1c6ae58..85f823f7aa 100644
--- a/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/RehydratableSystem.cs
@@ -20,7 +20,7 @@ public sealed class RehydratableSystem : EntitySystem
private void OnSolutionChange(EntityUid uid, RehydratableComponent comp, SolutionChangedEvent args)
{
- var quantity = _solutions.GetReagentQuantity(uid, comp.CatalystPrototype);
+ var quantity = _solutions.GetTotalPrototypeQuantity(uid, comp.CatalystPrototype);
if (quantity != FixedPoint2.Zero && quantity >= comp.CatalystMinimum)
{
Expand(uid, comp);
diff --git a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs
index 61da862be9..3ab07cc49b 100644
--- a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs
@@ -23,9 +23,11 @@ namespace Content.Server.Chemistry.EntitySystems;
public sealed class SolutionChangedEvent : EntityEventArgs
{
public readonly Solution Solution;
+ public readonly string SolutionId;
- public SolutionChangedEvent(Solution solution)
+ public SolutionChangedEvent(Solution solution, string solutionId)
{
+ SolutionId = solutionId;
Solution = solution;
}
}
@@ -103,7 +105,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
{
var msg = new FormattedMessage();
- if (solution.Contents.Count == 0) //TODO: better way to see if empty?
+ if (solution.Volume == 0)
{
msg.AddMarkup(Loc.GetString("scannable-solution-empty-container"));
return msg;
@@ -111,17 +113,13 @@ public sealed partial class SolutionContainerSystem : EntitySystem
msg.AddMarkup(Loc.GetString("scannable-solution-main-text"));
- foreach (var reagent in solution)
+ foreach (var (proto, quantity) in solution.GetReagentPrototypes(_prototypeManager))
{
- if (!_prototypeManager.TryIndex(reagent.ReagentId, out var proto))
- {
- continue;
- }
msg.PushNewline();
msg.AddMarkup(Loc.GetString("scannable-solution-chemical"
, ("type", proto.LocalizedName)
, ("color", proto.SubstanceColor.ToHexNoAlpha())
- , ("amount", reagent.Quantity)));
+ , ("amount", quantity)));
}
return msg;
@@ -132,46 +130,41 @@ public sealed partial class SolutionContainerSystem : EntitySystem
{
SolutionContainerManagerComponent? solutionsManager = null;
if (!Resolve(args.Examined, ref solutionsManager)
- || !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solutionHolder))
+ || !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solution))
{
return;
}
- var primaryReagent = solutionHolder.GetPrimaryReagentId();
+ var primaryReagent = solution.GetPrimaryReagentId();
- if (string.IsNullOrEmpty(primaryReagent))
+ if (string.IsNullOrEmpty(primaryReagent?.Prototype))
{
args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container"));
return;
}
- if (!_prototypeManager.TryIndex(primaryReagent, out ReagentPrototype? primary))
+ if (!_prototypeManager.TryIndex(primaryReagent.Value.Prototype, out ReagentPrototype? primary))
{
Logger.Error(
$"{nameof(Solution)} could not find the prototype associated with {primaryReagent}.");
return;
}
- var colorHex = solutionHolder.GetColor(_prototypeManager)
+ 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(solutionHolder.Contents.Count == 1
+ ("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)));
// Add descriptions of immediately recognizable reagents, like water or beer
var recognized = new List();
- foreach (var (id, _) in solutionHolder)
+ foreach (var proto in solution.GetReagentPrototypes(_prototypeManager).Keys)
{
- if (!_prototypeManager.TryIndex(id, out var proto))
- {
- continue;
- }
-
if (!proto.Recognizable)
{
continue;
@@ -278,7 +271,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
}
UpdateAppearance(uid, solutionHolder);
- RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder));
+ RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name));
}
public void RemoveAllSolution(EntityUid uid, Solution solutionHolder)
@@ -324,46 +317,111 @@ public sealed partial class SolutionContainerSystem : EntitySystem
///
///
/// Container to which we are adding reagent
- /// The Id of the reagent to add.
+ /// 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.
/// The amount of reagent successfully added.
/// If all the reagent could be added.
- public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string reagentId, FixedPoint2 quantity,
- out FixedPoint2 acceptedQuantity, float? temperature = null)
+ public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string prototype, FixedPoint2 quantity,
+ out FixedPoint2 acceptedQuantity, float? temperature = null, ReagentData? data = null)
{
- acceptedQuantity = targetSolution.AvailableVolume > quantity ? quantity : targetSolution.AvailableVolume;
-
- if (acceptedQuantity <= 0)
- return quantity == 0;
-
- if (temperature == null)
- targetSolution.AddReagent(reagentId, acceptedQuantity);
- else
- targetSolution.AddReagent(_prototypeManager.Index(reagentId), acceptedQuantity, temperature.Value, _prototypeManager);
-
- UpdateChemicals(targetUid, targetSolution, true);
- return acceptedQuantity == quantity;
+ 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 of an Id to the container.
+ /// 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.
+ /// The reagent to remove.
/// If the reagent to remove was found in the container.
- public bool TryRemoveReagent(EntityUid targetUid, Solution? container, string reagentId, FixedPoint2 quantity)
+ public bool RemoveReagent(EntityUid targetUid, Solution? container, ReagentQuantity reagentQuantity)
{
- if (container == null || !container.ContainsReagent(reagentId))
+ if (container == null)
+ return false;
+
+ var quant = container.RemoveReagent(reagentQuantity);
+ if (quant <= FixedPoint2.Zero)
return false;
- container.RemoveReagent(reagentId, quantity);
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));
+ }
+
///
/// Adds a solution to the container, if it can fully fit.
///
@@ -391,19 +449,35 @@ public sealed partial class SolutionContainerSystem : EntitySystem
/// 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)
- return TryTransferSolution(targetUid, sourceUid, target, source, -quantity);
+ 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.
+ // TODO This should be made into a function that directly transfers reagents.
+ // Currently this is quite inefficient.
target.AddSolution(source.SplitSolution(quantity), _prototypeManager);
- UpdateChemicals(sourceUid, source, false);
UpdateChemicals(targetUid, target, true);
return true;
}
@@ -540,7 +614,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
}
public Solution EnsureSolution(EntityUid uid, string name,
- IEnumerable reagents,
+ IEnumerable reagents,
bool setMaxVol = true,
SolutionContainerManagerComponent? solutionsMgr = null)
{
@@ -574,19 +648,16 @@ public sealed partial class SolutionContainerSystem : EntitySystem
// 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 (reagentId, _) = solution.Contents[i];
-
- var removedQuantity = solution.RemoveReagent(reagentId, quantity);
-
- if(removedQuantity > 0)
- removedSolution.AddReagent(reagentId, removedQuantity);
+ var (reagent, _) = solution.Contents[i];
+ var removedQuantity = solution.RemoveReagent(reagent, quantity);
+ removedSolution.AddReagent(reagent, removedQuantity);
}
UpdateChemicals(uid, solution);
return removedSolution;
}
- public FixedPoint2 GetReagentQuantity(EntityUid owner, string reagentId)
+ public FixedPoint2 GetTotalPrototypeQuantity(EntityUid owner, string reagentId)
{
var reagentQuantity = FixedPoint2.New(0);
if (EntityManager.EntityExists(owner)
@@ -594,7 +665,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
{
foreach (var solution in managerComponent.Solutions.Values)
{
- reagentQuantity += solution.GetReagentQuantity(reagentId);
+ reagentQuantity += solution.GetTotalPrototypeQuantity(reagentId);
}
}
@@ -640,21 +711,21 @@ public sealed partial class SolutionContainerSystem : EntitySystem
if (component.Solutions.Count == 0)
return null;
- var reagentCounts = new Dictionary();
+ var reagentCounts = new Dictionary();
foreach (var solution in component.Solutions.Values)
{
- foreach (var reagent in solution.Contents)
+ foreach (var (reagent, quantity) in solution.Contents)
{
- reagentCounts.TryGetValue(reagent.ReagentId, out var existing);
- existing += reagent.Quantity;
- reagentCounts[reagent.ReagentId] = existing;
+ reagentCounts.TryGetValue(reagent, out var existing);
+ existing += quantity;
+ reagentCounts[reagent] = existing;
}
}
var max = reagentCounts.Max();
- return _prototypeManager.Index(max.Key);
+ return _prototypeManager.Index(max.Key.Prototype);
}
public SoundSpecifier? GetSound(SolutionContainerManagerComponent component)
diff --git a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs
index 41ab11aab0..13246c22e1 100644
--- a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs
@@ -47,14 +47,14 @@ public sealed class TransformableContainerSystem : EntitySystem
var reagentId = solution.GetPrimaryReagentId();
//If biggest reagent didn't changed - don't change anything at all
- if (component.CurrentReagent != null && component.CurrentReagent.ID == reagentId)
+ if (component.CurrentReagent != null && component.CurrentReagent.ID == reagentId?.Prototype)
{
return;
}
//Only reagents with spritePath property can change appearance of transformable containers!
- if (!string.IsNullOrWhiteSpace(reagentId)
- && _prototypeManager.TryIndex(reagentId, out ReagentPrototype? proto))
+ if (!string.IsNullOrWhiteSpace(reagentId?.Prototype)
+ && _prototypeManager.TryIndex(reagentId.Value.Prototype, out ReagentPrototype? proto))
{
var metadata = MetaData(owner);
var val = Loc.GetString("transformable-container-component-glass", ("name", proto.LocalizedName));
diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs
index 92ba44b2c6..7288a993d3 100644
--- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs
@@ -1,18 +1,17 @@
using System.Numerics;
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Content.Shared.Physics;
using Content.Shared.Spawners.Components;
using Content.Shared.Throwing;
-using Content.Shared.Vapor;
using JetBrains.Annotations;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
-using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
@@ -27,6 +26,7 @@ namespace Content.Server.Chemistry.EntitySystems
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
+ [Dependency] private readonly ReactiveSystem _reactive = default!;
private const float ReactTime = 0.125f;
@@ -45,7 +45,7 @@ namespace Content.Server.Chemistry.EntitySystems
foreach (var value in contents.Solutions.Values)
{
- value.DoEntityReaction(args.OtherEntity, ReactionMethod.Touch);
+ _reactive.DoEntityReaction(args.OtherEntity, value, ReactionMethod.Touch);
}
// Check for collision with a impassable object (e.g. wall) and stop
@@ -120,18 +120,18 @@ namespace Content.Server.Chemistry.EntitySystems
foreach (var reagentQuantity in contents.Contents.ToArray())
{
if (reagentQuantity.Quantity == FixedPoint2.Zero) continue;
- var reagent = _protoManager.Index(reagentQuantity.ReagentId);
+ var reagent = _protoManager.Index(reagentQuantity.Reagent.Prototype);
var reaction =
reagent.ReactionTile(tile, (reagentQuantity.Quantity / vapor.TransferAmount) * 0.25f);
if (reaction > reagentQuantity.Quantity)
{
- _sawmill.Error($"Tried to tile react more than we have for reagent {reagentQuantity.ReagentId}. Found {reaction} and we only have {reagentQuantity.Quantity}");
+ _sawmill.Error($"Tried to tile react more than we have for reagent {reagentQuantity}. Found {reaction} and we only have {reagentQuantity.Quantity}");
reaction = reagentQuantity.Quantity;
}
- _solutionContainerSystem.TryRemoveReagent(vapor.Owner, contents, reagentQuantity.ReagentId, reaction);
+ _solutionContainerSystem.RemoveReagent(vapor.Owner, contents, reagentQuantity.Reagent, reaction);
}
}
diff --git a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs
index 87e1e683a8..203656be73 100644
--- a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs
+++ b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs
@@ -19,6 +19,7 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
[DataField("max")]
public FixedPoint2 Max = FixedPoint2.MaxValue;
+ // TODO use ReagentId
[DataField("reagent")]
public string? Reagent;
@@ -29,10 +30,8 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
return true; // No condition to apply.
var quant = FixedPoint2.Zero;
- if (args.Source != null && args.Source.ContainsReagent(reagent))
- {
- quant = args.Source.GetReagentQuantity(reagent);
- }
+ if (args.Source != null)
+ quant = args.Source.GetTotalPrototypeQuantity(reagent);
return quant >= Min && quant <= Max;
}
diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs
index 00c6a91046..c79dd24332 100644
--- a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs
+++ b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs
@@ -16,6 +16,7 @@ namespace Content.Server.Chemistry.ReagentEffects
///
[DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer))]
public string? Reagent = null;
+ // TODO use ReagentId
///
/// The metabolism group to remove, if the reagent satisfies any.
@@ -38,8 +39,8 @@ namespace Content.Server.Chemistry.ReagentEffects
if (Reagent != null)
{
- if (amount < 0 && args.Source.ContainsReagent(Reagent))
- solutionSys.TryRemoveReagent(args.SolutionEntity, args.Source, Reagent, -amount);
+ 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 _);
}
@@ -48,13 +49,13 @@ namespace Content.Server.Chemistry.ReagentEffects
var prototypeMan = IoCManager.Resolve();
foreach (var quant in args.Source.Contents.ToArray())
{
- var proto = prototypeMan.Index(quant.ReagentId);
+ var proto = prototypeMan.Index(quant.Reagent.Prototype);
if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
{
if (amount < 0)
- solutionSys.TryRemoveReagent(args.SolutionEntity, args.Source, quant.ReagentId, amount);
+ solutionSys.RemoveReagent(args.SolutionEntity, args.Source, quant.Reagent, amount);
if (amount > 0)
- solutionSys.TryAddReagent(args.SolutionEntity, args.Source, quant.ReagentId, amount, out _);
+ solutionSys.TryAddReagent(args.SolutionEntity, args.Source, quant.Reagent, amount, out _);
}
}
}
diff --git a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs
index db58430e39..58757af660 100644
--- a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs
+++ b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs
@@ -55,7 +55,8 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
var oldProgress = component.Progress.ShallowClone();
component.Progress.Clear();
- if (solution.TryGetReagent(PuddleSystem.EvaporationReagent, out var water))
+ var water = solution.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagent);
+ if (water > FixedPoint2.Zero)
{
component.Progress[_prototype.Index(PuddleSystem.EvaporationReagent).SubstanceColor] = water.Float();
}
@@ -230,7 +231,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
}
// Check if we have any evaporative reagents on our absorber to transfer
- absorberSoln.TryGetReagent(PuddleSystem.EvaporationReagent, out var available);
+ var available = absorberSoln.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagent);
// No material
if (available == FixedPoint2.Zero)
diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs
index 429f128810..1392a23356 100644
--- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs
+++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs
@@ -25,7 +25,7 @@ public sealed partial class PuddleSystem
return;
}
- if (solution.ContainsReagent(EvaporationReagent))
+ if (solution.ContainsPrototype(EvaporationReagent))
{
var evaporation = AddComp(uid);
evaporation.NextTick = _timing.CurTime + EvaporationCooldown;
@@ -51,7 +51,7 @@ public sealed partial class PuddleSystem
continue;
var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds;
- _solutionContainerSystem.TryRemoveReagent(uid, puddleSolution, EvaporationReagent, reagentTick);
+ _solutionContainerSystem.RemoveReagent(uid, puddleSolution, EvaporationReagent, reagentTick);
// Despawn if we're done
if (puddleSolution.Volume == FixedPoint2.Zero)
@@ -65,6 +65,6 @@ public sealed partial class PuddleSystem
public bool CanFullyEvaporate(Solution solution)
{
- return solution.Contents.Count == 1 && solution.ContainsReagent(EvaporationReagent);
+ return solution.Contents.Count == 1 && solution.ContainsPrototype(EvaporationReagent);
}
}
diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
index 991bbac6de..614e685456 100644
--- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
+++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
@@ -56,6 +56,17 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
[Dependency] private readonly SlowContactsSystem _slowContacts = default!;
[Dependency] private readonly TileFrictionController _tile = default!;
+ [ValidatePrototypeId]
+ private const string Blood = "Blood";
+
+ [ValidatePrototypeId]
+ private const string Slime = "Slime";
+
+ [ValidatePrototypeId]
+ private const string SpiderBlood = "SpiderBlood";
+
+ private static string[] _standoutReagents = new[] { Blood, Slime, SpiderBlood };
+
public static float PuddleVolume = 1000;
// Using local deletion queue instead of the standard queue so that we can easily "undelete" if a puddle
@@ -272,14 +283,14 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
// Make blood stand out more
// Kinda EH
// Could potentially do alpha per-solution but future problem.
- var standoutReagents = new string[] { "Blood", "Slime", "SpiderBlood" };
- color = solution.GetColorWithout(_prototypeManager, standoutReagents);
+ color = solution.GetColorWithout(_prototypeManager, _standoutReagents);
color = color.WithAlpha(0.7f);
- foreach (var standout in standoutReagents)
+ foreach (var standout in _standoutReagents)
{
- if (!solution.TryGetReagent(standout, out var quantity))
+ var quantity = solution.GetTotalPrototypeQuantity(standout);
+ if (quantity <= FixedPoint2.Zero)
continue;
var interpolateValue = quantity.Float() / solution.Volume.Float();
@@ -298,13 +309,13 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
var amountRequired = FixedPoint2.New(component.OverflowVolume.Float() * LowThreshold);
var slipperyAmount = FixedPoint2.Zero;
- foreach (var reagent in solution.Contents)
+ foreach (var (reagent, quantity) in solution.Contents)
{
- var reagentProto = _prototypeManager.Index(reagent.ReagentId);
+ var reagentProto = _prototypeManager.Index(reagent.Prototype);
if (reagentProto.Slippery)
{
- slipperyAmount += reagent.Quantity;
+ slipperyAmount += quantity;
if (slipperyAmount > amountRequired)
{
@@ -331,9 +342,9 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
private void UpdateSlow(EntityUid uid, Solution solution)
{
var maxViscosity = 0f;
- foreach (var reagent in solution.Contents)
+ foreach (var (reagent, _) in solution.Contents)
{
- var reagentProto = _prototypeManager.Index(reagent.ReagentId);
+ var reagentProto = _prototypeManager.Index(reagent.Prototype);
maxViscosity = Math.Max(maxViscosity, reagentProto.Viscosity);
}
if (maxViscosity > 0)
@@ -362,7 +373,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
{
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
}
- else if (solution?.ContainsReagent(EvaporationReagent) == true)
+ else if (solution?.ContainsPrototype(EvaporationReagent) == true)
{
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
}
@@ -588,15 +599,15 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
if (tileReact)
{
// First, do all tile reactions
- for (var i = 0; i < solution.Contents.Count; i++)
+ for (var i = solution.Contents.Count - 1; i >= 0; i--)
{
- var (reagentId, quantity) = solution.Contents[i];
- var proto = _prototypeManager.Index(reagentId);
+ var (reagent, quantity) = solution.Contents[i];
+ var proto = _prototypeManager.Index(reagent.Prototype);
var removed = proto.ReactionTile(tileRef, quantity);
if (removed <= FixedPoint2.Zero)
continue;
- solution.RemoveReagent(reagentId, removed);
+ solution.RemoveReagent(reagent, removed);
}
}
diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
index 41a32775d9..cee2e6ce49 100644
--- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
+++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
@@ -113,6 +113,8 @@ namespace Content.Server.Kitchen.EntitySystems
private void SubtractContents(MicrowaveComponent component, FoodRecipePrototype recipe)
{
+ // TODO Turn recipe.IngredientsReagents into a ReagentQuantity[]
+
var totalReagentsToRemove = new Dictionary(recipe.IngredientsReagents);
// this is spaghetti ngl
@@ -130,10 +132,7 @@ namespace Content.Server.Kitchen.EntitySystems
if (!totalReagentsToRemove.ContainsKey(reagent))
continue;
- if (!solution.ContainsReagent(reagent))
- continue;
-
- var quant = solution.GetReagentQuantity(reagent);
+ var quant = solution.GetTotalPrototypeQuantity(reagent);
if (quant >= totalReagentsToRemove[reagent])
{
@@ -145,7 +144,7 @@ namespace Content.Server.Kitchen.EntitySystems
totalReagentsToRemove[reagent] -= quant;
}
- _solutionContainer.TryRemoveReagent(item, solution, reagent, quant);
+ _solutionContainer.RemoveReagent(item, solution, reagent, quant);
}
}
}
@@ -324,6 +323,8 @@ namespace Content.Server.Kitchen.EntitySystems
var solidsDict = new Dictionary();
var reagentDict = new Dictionary();
+ // TODO use lists of Reagent quantities instead of reagent prototype ids.
+
foreach (var item in component.Storage.ContainedEntities)
{
// special behavior when being microwaved ;)
@@ -370,12 +371,12 @@ namespace Content.Server.Kitchen.EntitySystems
foreach (var (_, solution) in solMan.Solutions)
{
- foreach (var reagent in solution.Contents)
+ foreach (var (reagent, quantity) in solution.Contents)
{
- if (reagentDict.ContainsKey(reagent.ReagentId))
- reagentDict[reagent.ReagentId] += reagent.Quantity;
+ if (reagentDict.ContainsKey(reagent.Prototype))
+ reagentDict[reagent.Prototype] += quantity;
else
- reagentDict.Add(reagent.ReagentId, reagent.Quantity);
+ reagentDict.Add(reagent.Prototype, quantity);
}
}
}
@@ -417,6 +418,7 @@ namespace Content.Server.Kitchen.EntitySystems
foreach (var reagent in recipe.IngredientsReagents)
{
+ // TODO Turn recipe.IngredientsReagents into a ReagentQuantity[]
if (!reagents.ContainsKey(reagent.Key))
return (recipe, 0);
diff --git a/Content.Server/Materials/MaterialReclaimerSystem.cs b/Content.Server/Materials/MaterialReclaimerSystem.cs
index caac0ae577..fe6f9dcc9d 100644
--- a/Content.Server/Materials/MaterialReclaimerSystem.cs
+++ b/Content.Server/Materials/MaterialReclaimerSystem.cs
@@ -220,14 +220,16 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
if (!Resolve(reclaimer, ref reclaimerComponent, ref xform))
return;
- var overflow = new Solution();
- var totalChemicals = new Dictionary();
+ efficiency *= reclaimerComponent.Efficiency;
+
+ var totalChemicals = new Solution();
if (Resolve(item, ref composition, false))
{
foreach (var (key, value) in composition.ChemicalComposition)
{
- totalChemicals[key] = totalChemicals.GetValueOrDefault(key) + value;
+ // TODO use ReagentQuantity
+ totalChemicals.AddReagent(key, value * efficiency, false);
}
}
@@ -238,27 +240,15 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
{
foreach (var quantity in solution.Contents)
{
- totalChemicals[quantity.ReagentId] =
- totalChemicals.GetValueOrDefault(quantity.ReagentId) + quantity.Quantity;
+ totalChemicals.AddReagent(quantity.Reagent.Prototype, quantity.Quantity * efficiency, false);
}
}
}
- foreach (var (reagent, amount) in totalChemicals)
+ _solutionContainer.TryTransferSolution(reclaimer, reclaimerComponent.OutputSolution, totalChemicals, totalChemicals.Volume);
+ if (totalChemicals.Volume > 0)
{
- var outputAmount = amount * efficiency * reclaimerComponent.Efficiency;
- _solutionContainer.TryAddReagent(reclaimer, reclaimerComponent.OutputSolution, reagent, outputAmount,
- out var accepted);
- var overflowAmount = outputAmount - accepted;
- if (overflowAmount > 0)
- {
- overflow.AddReagent(reagent, overflowAmount);
- }
- }
-
- if (overflow.Volume > 0)
- {
- _puddle.TrySpillAt(reclaimer, overflow, out _, transformComponent: xform);
+ _puddle.TrySpillAt(reclaimer, totalChemicals, out _, transformComponent: xform);
}
}
}
diff --git a/Content.Server/Nutrition/Components/VapeComponent.cs b/Content.Server/Nutrition/Components/VapeComponent.cs
index a3d583cffd..41b03edfb4 100644
--- a/Content.Server/Nutrition/Components/VapeComponent.cs
+++ b/Content.Server/Nutrition/Components/VapeComponent.cs
@@ -1,12 +1,8 @@
-using System.Threading;
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Atmos;
-///
-/// Component for vapes
-///
-namespace Content.Server.Nutrition.Components
+namespace Content.Server.Nutrition.Components // Vapes are very nutritious.
{
[RegisterComponent, Access(typeof(SmokingSystem))]
public sealed partial class VapeComponent : Component
@@ -23,6 +19,7 @@ namespace Content.Server.Nutrition.Components
[ViewVariables(VVAccess.ReadWrite)]
public float ExplosionIntensity { get; set; } = 2.5f;
+ // TODO use RiggableComponent.
[DataField("explodeOnUse")]
[ViewVariables(VVAccess.ReadWrite)]
public bool ExplodeOnUse { get; set; } = false;
@@ -42,10 +39,9 @@ namespace Content.Server.Nutrition.Components
[ViewVariables(VVAccess.ReadWrite)]
public float ReductionFactor { get; set; } = 300f;
+ // TODO when this gets fixed, use prototype serializers
[DataField("solutionNeeded")]
[ViewVariables(VVAccess.ReadWrite)]
public string SolutionNeeded = "Water";
-
- public CancellationTokenSource? CancelToken;
}
}
diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs
index 36521568a1..980c08d4bc 100644
--- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs
+++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs
@@ -101,7 +101,7 @@ public sealed class DrinkSystem : EntitySystem
var total = 0f;
foreach (var quantity in solution.Contents)
{
- var reagent = _proto.Index(quantity.ReagentId);
+ var reagent = _proto.Index(quantity.Reagent.Prototype);
if (reagent.Metabolisms == null)
continue;
diff --git a/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs b/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs
index 9e20484c31..e01f199ae1 100644
--- a/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs
+++ b/Content.Server/Nutrition/EntitySystems/FlavorProfileSystem.cs
@@ -84,9 +84,9 @@ public sealed class FlavorProfileSystem : EntitySystem
private HashSet GetFlavorsFromReagents(Solution solution, int desiredAmount, HashSet? toIgnore = null)
{
var flavors = new HashSet();
- foreach (var reagent in solution.Contents)
+ foreach (var (reagent, quantity) in solution.GetReagentPrototypes(_prototypeManager))
{
- if (toIgnore != null && toIgnore.Contains(reagent.ReagentId))
+ if (toIgnore != null && toIgnore.Contains(reagent.ID))
{
continue;
}
@@ -96,15 +96,14 @@ public sealed class FlavorProfileSystem : EntitySystem
break;
}
- var proto = _prototypeManager.Index(reagent.ReagentId);
// don't care if the quantity is negligible
- if (reagent.Quantity < proto.FlavorMinimum)
+ if (quantity < reagent.FlavorMinimum)
{
continue;
}
- if (proto.Flavor != null)
- flavors.Add(proto.Flavor);
+ if (reagent.Flavor != null)
+ flavors.Add(reagent.Flavor);
}
return flavors;
diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
index 07fb24cd20..5b1ced8b18 100644
--- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
+++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
@@ -35,7 +35,7 @@ namespace Content.Server.Nutrition.EntitySystems
SubscribeLocalEvent(OnEmagged);
}
- private void OnVapeInteraction(EntityUid uid, VapeComponent comp, AfterInteractEvent args)
+ private void OnVapeInteraction(EntityUid uid, VapeComponent comp, AfterInteractEvent args)
{
_solutionContainerSystem.TryGetRefillableSolution(uid, out var solution);
@@ -44,11 +44,12 @@ namespace Content.Server.Nutrition.EntitySystems
var exploded = false;
if (!args.CanReach
- || solution == null
- || comp.CancelToken != null
- || !TryComp(args.Target, out var _)
- || _foodSystem.IsMouthBlocked(args.Target.Value, args.User))
+ || solution == null
+ || !HasComp(args.Target)
+ || _foodSystem.IsMouthBlocked(args.Target.Value, args.User))
+ {
return;
+ }
if (solution.Contents.Count == 0)
{
@@ -72,9 +73,14 @@ namespace Content.Server.Nutrition.EntitySystems
}
else
{
+ // All vapes explode if they contain anything other than pure water???
+ // WTF is this? Why is this? Am I going insane?
+ // Who the fuck vapes pure water?
+ // If this isn't how this is meant to work and this is meant to be for vapes with plasma or something,
+ // just re-use the existing RiggableSystem.
foreach (var name in solution.Contents)
{
- if (name.ReagentId != comp.SolutionNeeded)
+ if (name.Reagent.Prototype != comp.SolutionNeeded)
{
exploded = true;
_explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
@@ -92,7 +98,7 @@ namespace Content.Server.Nutrition.EntitySystems
_popupSystem.PopupEntity(
Loc.GetString("vape-component-try-use-vape-forced", ("user", userName)), args.Target.Value,
args.Target.Value);
-
+
_popupSystem.PopupEntity(
Loc.GetString("vape-component-try-use-vape-forced-user", ("target", targetName)), args.User,
args.User);
@@ -106,8 +112,6 @@ namespace Content.Server.Nutrition.EntitySystems
if (!exploded)
{
- comp.CancelToken = new CancellationTokenSource();
-
var vapeDoAfterEvent = new VapeDoAfterEvent(solution, forced);
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(args.User, delay, vapeDoAfterEvent, uid, target: args.Target, used: uid)
{
@@ -121,14 +125,6 @@ namespace Content.Server.Nutrition.EntitySystems
private void OnVapeDoAfter(EntityUid uid, VapeComponent comp, VapeDoAfterEvent args)
{
- if (args.Cancelled)
- {
- comp.CancelToken = null;
- return;
- }
-
- comp.CancelToken = null;
-
if (args.Handled
|| args.Args.Target == null)
return;
@@ -148,7 +144,7 @@ namespace Content.Server.Nutrition.EntitySystems
_atmosphereSystem.Merge(environment, merger);
args.Solution.RemoveAllSolution();
-
+
if (args.Forced)
{
var targetName = Identity.Entity(args.Args.Target.Value, EntityManager);
@@ -157,7 +153,7 @@ namespace Content.Server.Nutrition.EntitySystems
_popupSystem.PopupEntity(
Loc.GetString("vape-component-vape-success-forced", ("user", userName)), args.Args.Target.Value,
args.Args.Target.Value);
-
+
_popupSystem.PopupEntity(
Loc.GetString("vape-component-vape-success-user-forced", ("target", targetName)), args.Args.User,
args.Args.Target.Value);
diff --git a/Content.Server/Power/Components/RiggableComponent.cs b/Content.Server/Power/Components/RiggableComponent.cs
index eaf216fd5f..797c8c81f4 100644
--- a/Content.Server/Power/Components/RiggableComponent.cs
+++ b/Content.Server/Power/Components/RiggableComponent.cs
@@ -1,11 +1,20 @@
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+
namespace Content.Server.Power.Components;
[RegisterComponent]
public sealed partial class RiggableComponent : Component
{
- public const string SolutionName = "battery";
-
[ViewVariables(VVAccess.ReadWrite)]
[DataField("isRigged")]
public bool IsRigged;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution = "battery";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("reagent")]
+ public ReagentQuantity RequiredQuantity = new("Plasma", FixedPoint2.New(5), null);
}
diff --git a/Content.Server/Power/EntitySystems/RiggableSystem.cs b/Content.Server/Power/EntitySystems/RiggableSystem.cs
index 9d988f00b9..b35d936ace 100644
--- a/Content.Server/Power/EntitySystems/RiggableSystem.cs
+++ b/Content.Server/Power/EntitySystems/RiggableSystem.cs
@@ -4,6 +4,7 @@ using Content.Server.Explosion.EntitySystems;
using Content.Server.Kitchen.Components;
using Content.Server.Power.Components;
using Content.Server.Stunnable.Components;
+using Content.Shared.Chemistry.Components;
using Content.Shared.Database;
using Content.Shared.Rejuvenate;
@@ -47,27 +48,19 @@ public sealed class RiggableSystem : EntitySystem
private void OnSolutionChanged(EntityUid uid, RiggableComponent component, SolutionChangedEvent args)
{
- if (TryComp(uid, out var battery))
- {
- IsRigged(uid, args);
- }
+ if (args.SolutionId != component.Solution)
+ return;
- if (component.IsRigged)
+ var wasRigged = component.IsRigged;
+ var quantity = args.Solution.GetReagentQuantity(component.RequiredQuantity.Reagent);
+ component.IsRigged = quantity >= component.RequiredQuantity.Quantity;
+
+ if (component.IsRigged && !wasRigged)
{
_adminLogger.Add(LogType.Explosion, LogImpact.Medium, $"{ToPrettyString(uid)} has been rigged up to explode when used.");
}
}
- public void IsRigged(EntityUid uid, SolutionChangedEvent args)
- {
- if (TryComp(uid, out var riggableComp))
- {
- riggableComp.IsRigged = _solutionsSystem.TryGetSolution(uid, RiggableComponent.SolutionName, out var solution)
- && solution.TryGetReagent("Plasma", out var plasma)
- && plasma >= 5;
- }
- }
-
public void Explode(EntityUid uid, BatteryComponent? battery = null, EntityUid? cause = null)
{
if (!Resolve(uid, ref battery))
diff --git a/Content.Server/Power/Generator/GeneratorSystem.cs b/Content.Server/Power/Generator/GeneratorSystem.cs
index e3b678584b..591fd7f300 100644
--- a/Content.Server/Power/Generator/GeneratorSystem.cs
+++ b/Content.Server/Power/Generator/GeneratorSystem.cs
@@ -81,7 +81,7 @@ public sealed class GeneratorSystem : SharedGeneratorSystem
foreach (var reagentQuantity in solution)
{
- if (reagentQuantity.ReagentId != component.Reagent)
+ if (reagentQuantity.Reagent.Prototype != component.Reagent)
{
args.Clogged = true;
return;
@@ -94,7 +94,7 @@ public sealed class GeneratorSystem : SharedGeneratorSystem
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
return;
- var availableReagent = solution.GetReagentQuantity(component.Reagent).Value;
+ var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Value;
var toRemove = RemoveFractionalFuel(
ref component.FractionalReagent,
args.FuelUsed,
@@ -112,8 +112,8 @@ public sealed class GeneratorSystem : SharedGeneratorSystem
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
return;
- var reagent = component.FractionalReagent * FixedPoint2.Epsilon.Float()
- + solution.GetReagentQuantity(component.Reagent).Float();
+ var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Float();
+ var reagent = component.FractionalReagent * FixedPoint2.Epsilon.Float() + availableReagent;
args.Fuel = reagent * component.Multiplier;
}
diff --git a/Content.Server/Tools/ToolSystem.Welder.cs b/Content.Server/Tools/ToolSystem.Welder.cs
index 1af28f70e1..7097bc4dc9 100644
--- a/Content.Server/Tools/ToolSystem.Welder.cs
+++ b/Content.Server/Tools/ToolSystem.Welder.cs
@@ -58,7 +58,7 @@ namespace Content.Server.Tools
|| !_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var fuelSolution, solutionContainer))
return (FixedPoint2.Zero, FixedPoint2.Zero);
- return (_solutionContainerSystem.GetReagentQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume);
+ return (_solutionContainerSystem.GetTotalPrototypeQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume);
}
public bool TryToggleWelder(EntityUid uid, EntityUid? user,
@@ -95,7 +95,7 @@ namespace Content.Server.Tools
if (!_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var solution, solutionContainer))
return false;
- var fuel = solution.GetReagentQuantity(welder.FuelReagent);
+ var fuel = solution.GetTotalPrototypeQuantity(welder.FuelReagent);
// Not enough fuel to lit welder.
if (fuel == FixedPoint2.Zero || fuel < welder.FuelLitCost)
@@ -307,7 +307,7 @@ namespace Content.Server.Tools
solution.RemoveReagent(welder.FuelReagent, welder.FuelConsumption * _welderTimer);
- if (solution.GetReagentQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
+ if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
TryTurnWelderOff(tool, null, welder);
_entityManager.Dirty(welder);
diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs
index ff53a4bebd..65fdcd62dd 100644
--- a/Content.Shared/Chemistry/Components/Solution.cs
+++ b/Content.Shared/Chemistry/Components/Solution.cs
@@ -3,10 +3,8 @@ using Content.Shared.FixedPoint;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Utility;
using System.Collections;
-using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Content.Shared.Chemistry.Components
@@ -16,12 +14,12 @@ namespace Content.Shared.Chemistry.Components
///
[Serializable, NetSerializable]
[DataDefinition]
- public sealed partial class Solution : IEnumerable, ISerializationHooks
+ public sealed partial class Solution : IEnumerable, ISerializationHooks
{
// This is a list because it is actually faster to add and remove reagents from
// a list than a dictionary, though contains-reagent checks are slightly slower,
[DataField("reagents")]
- public List Contents = new(2);
+ public List Contents;
///
/// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker).
@@ -86,14 +84,12 @@ namespace Content.Shared.Chemistry.Components
///
/// The total heat capacity of all reagents in the solution.
///
- [ViewVariables]
- private float _heatCapacity;
+ [ViewVariables] private float _heatCapacity;
///
/// If true, then needs to be recomputed.
///
- [ViewVariables]
- private bool _heatCapacityDirty = true;
+ [ViewVariables] private bool _heatCapacityDirty = true;
public void UpdateHeatCapacity(IPrototypeManager? protoMan)
{
@@ -101,9 +97,10 @@ namespace Content.Shared.Chemistry.Components
DebugTools.Assert(_heatCapacityDirty);
_heatCapacityDirty = false;
_heatCapacity = 0;
- foreach (var reagent in Contents)
+ foreach (var (reagent, quantity) in Contents)
{
- _heatCapacity += (float) reagent.Quantity * protoMan.Index(reagent.ReagentId).SpecificHeat;
+ _heatCapacity += (float) quantity *
+ protoMan.Index(reagent.Prototype).SpecificHeat;
}
}
@@ -137,11 +134,11 @@ namespace Content.Shared.Chemistry.Components
///
/// Constructs a solution containing 100% of a reagent (ex. A beaker of pure water).
///
- /// The prototype ID of the reagent to add.
+ /// The prototype ID of the reagent to add.
/// The quantity in milli-units.
- public Solution(string reagentId, FixedPoint2 quantity) : this()
+ public Solution(string prototype, FixedPoint2 quantity, ReagentData? data = null) : this()
{
- AddReagent(reagentId, quantity);
+ AddReagent(new ReagentId(prototype, data), quantity);
}
public Solution(IEnumerable reagents, bool setMaxVol = true)
@@ -173,7 +170,6 @@ namespace Content.Shared.Chemistry.Components
return new Solution(this);
}
-
[AssertionMethod]
public void ValidateSolution()
{
@@ -185,8 +181,8 @@ namespace Content.Shared.Chemistry.Components
// All reagents have at least some reagent present.
DebugTools.Assert(!Contents.Any(x => x.Quantity <= FixedPoint2.Zero));
- // No duplicate reagent iDs
- DebugTools.Assert(Contents.Select(x => x.ReagentId).ToHashSet().Count() == Contents.Count);
+ // No duplicate reagents iDs
+ DebugTools.Assert(Contents.Select(x => x.Reagent).ToHashSet().Count == Contents.Count);
// If it isn't flagged as dirty, check heat capacity is correct.
if (!_heatCapacityDirty)
@@ -211,33 +207,101 @@ namespace Content.Shared.Chemistry.Components
MaxVolume = Volume;
}
- public bool ContainsReagent(string reagentId)
+ public bool ContainsPrototype(string prototype)
{
- foreach (var reagent in Contents)
+ foreach (var (reagent, _) in Contents)
{
- if (reagent.ReagentId == reagentId)
+ if (reagent.Prototype == prototype)
return true;
}
return false;
}
- public bool TryGetReagent(string reagentId, out FixedPoint2 quantity)
+ public bool ContainsReagent(ReagentId id)
{
- foreach (var reagent in Contents)
+ foreach (var (reagent, _) in Contents)
{
- if (reagent.ReagentId == reagentId)
- {
- quantity = reagent.Quantity;
+ if (reagent == id)
return true;
- }
}
- quantity = FixedPoint2.New(0);
return false;
}
- public string? GetPrimaryReagentId()
+ public bool ContainsReagent(string reagentId, ReagentData? data)
+ => ContainsReagent(new(reagentId, data));
+
+ public bool TryGetReagent(ReagentId id, out ReagentQuantity quantity)
+ {
+ foreach (var tuple in Contents)
+ {
+ if (tuple.Reagent != id)
+ continue;
+
+ DebugTools.Assert(tuple.Quantity > FixedPoint2.Zero);
+ quantity = tuple;
+ return true;
+ }
+
+ quantity = new ReagentQuantity(id, FixedPoint2.Zero);
+ return false;
+ }
+
+ public bool TryGetReagentQuantity(ReagentId id, out FixedPoint2 volume)
+ {
+ volume = FixedPoint2.Zero;
+ if (!TryGetReagent(id, out var quant))
+ return false;
+
+ volume = quant.Quantity;
+ return true;
+ }
+
+ [Pure]
+ public ReagentQuantity GetReagent(ReagentId id)
+ {
+ TryGetReagent(id, out var quantity);
+ return quantity;
+ }
+
+ public ReagentQuantity this[ReagentId id]
+ {
+ get
+ {
+ if (!TryGetReagent(id, out var quantity))
+ throw new KeyNotFoundException(id.ToString());
+ return quantity;
+ }
+ }
+
+ ///
+ /// Get the volume/quantity of a single reagent in the solution.
+ ///
+ [Pure]
+ public FixedPoint2 GetReagentQuantity(ReagentId id)
+ {
+ return GetReagent(id).Quantity;
+ }
+
+ ///
+ /// Gets the total volume of all reagents in the solution with the given prototype Id.
+ /// If you only want the volume of a single reagent, use
+ ///
+ [Pure]
+ public FixedPoint2 GetTotalPrototypeQuantity(string prototype)
+ {
+ var total = FixedPoint2.Zero;
+ foreach (var (reagent, quantity) in Contents)
+ {
+ if (reagent.Prototype == prototype)
+ total += quantity;
+ }
+
+ return total;
+ }
+
+ public ReagentId? GetPrimaryReagentId()
{
if (Contents.Count == 0)
return null;
@@ -252,15 +316,23 @@ namespace Content.Shared.Chemistry.Components
}
}
- return max.ReagentId!;
+ return max.Reagent;
}
///
/// Adds a given quantity of a reagent directly into the solution.
///
- /// The prototype ID of the reagent to add.
+ /// The prototype ID of the reagent to add.
/// The quantity in milli-units.
- public void AddReagent(string reagentId, FixedPoint2 quantity, bool dirtyHeatCap = true)
+ public void AddReagent(string prototype, FixedPoint2 quantity, bool dirtyHeatCap = true)
+ => AddReagent(new ReagentId(prototype, null), quantity, dirtyHeatCap);
+
+ ///
+ /// Adds a given quantity of a reagent directly into the solution.
+ ///
+ /// The reagent to add.
+ /// The quantity in milli-units.
+ public void AddReagent(ReagentId id, FixedPoint2 quantity, bool dirtyHeatCap = true)
{
if (quantity <= 0)
{
@@ -272,42 +344,45 @@ namespace Content.Shared.Chemistry.Components
_heatCapacityDirty |= dirtyHeatCap;
for (var i = 0; i < Contents.Count; i++)
{
- var reagent = Contents[i];
- if (reagent.ReagentId != reagentId)
+ var (reagent, existingQuantity) = Contents[i];
+ if (reagent != id)
continue;
- Contents[i] = new ReagentQuantity(reagentId, reagent.Quantity + quantity);
+ Contents[i] = new ReagentQuantity(id, existingQuantity + quantity);
ValidateSolution();
return;
}
- Contents.Add(new ReagentQuantity(reagentId, quantity));
+ Contents.Add(new ReagentQuantity(id, quantity));
ValidateSolution();
}
///
/// Adds a given quantity of a reagent directly into the solution.
///
- /// The prototype of the reagent to add.
+ /// The reagent to add.
/// The quantity in milli-units.
- public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity)
+ public void AddReagent(ReagentPrototype proto, ReagentId reagentId, FixedPoint2 quantity)
{
- AddReagent(proto.ID, quantity, false);
+ AddReagent(reagentId, quantity, false);
_heatCapacity += quantity.Float() * proto.SpecificHeat;
}
+ public void AddReagent(ReagentQuantity reagentQuantity)
+ => AddReagent(reagentQuantity.Reagent, reagentQuantity.Quantity);
+
///
/// Adds a given quantity of a reagent directly into the solution.
///
/// The prototype of the reagent to add.
/// The quantity in milli-units.
- public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity, float temperature, IPrototypeManager? protoMan)
+ public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity, float temperature, IPrototypeManager? protoMan, ReagentData? data = null)
{
if (_heatCapacityDirty)
UpdateHeatCapacity(protoMan);
var totalThermalEnergy = Temperature * _heatCapacity + temperature * proto.SpecificHeat;
- AddReagent(proto, quantity);
+ AddReagent(new ReagentId(proto.ID, data), quantity);
Temperature = _heatCapacity == 0 ? 0 : totalThermalEnergy / _heatCapacity;
}
@@ -333,7 +408,7 @@ namespace Content.Shared.Chemistry.Components
for (int i = 0; i < Contents.Count; i++)
{
var old = Contents[i];
- Contents[i] = new ReagentQuantity(old.ReagentId, old.Quantity * scale);
+ Contents[i] = new ReagentQuantity(old.Reagent, old.Quantity * scale);
}
ValidateSolution();
}
@@ -362,7 +437,7 @@ namespace Content.Shared.Chemistry.Components
Contents.RemoveSwap(i);
else
{
- Contents[i] = new ReagentQuantity(old.ReagentId, newQuantity);
+ Contents[i] = new ReagentQuantity(old.Reagent, newQuantity);
Volume += newQuantity;
}
}
@@ -371,43 +446,24 @@ namespace Content.Shared.Chemistry.Components
ValidateSolution();
}
- ///
- /// Returns the amount of a single reagent inside the solution.
- ///
- /// The prototype ID of the reagent to add.
- /// The quantity in milli-units.
- public FixedPoint2 GetReagentQuantity(string reagentId)
- {
- for (var i = 0; i < Contents.Count; i++)
- {
- var reagent = Contents[i];
- if (reagent.ReagentId == reagentId)
- return reagent.Quantity;
- }
-
- return FixedPoint2.Zero;
- }
-
///
/// Attempts to remove an amount of reagent from the solution.
///
- /// The reagent to be removed.
- /// The amount of reagent to remove.
+ /// The reagent to be removed.
/// How much reagent was actually removed. Zero if the reagent is not present on the solution.
- public FixedPoint2 RemoveReagent(string reagentId, FixedPoint2 quantity)
+ public FixedPoint2 RemoveReagent(ReagentQuantity toRemove)
{
- if (quantity <= FixedPoint2.Zero)
+ if (toRemove.Quantity <= FixedPoint2.Zero)
return FixedPoint2.Zero;
for (var i = 0; i < Contents.Count; i++)
{
- var reagent = Contents[i];
+ var (reagent, curQuantity) = Contents[i];
- if(reagent.ReagentId != reagentId)
+ if(reagent != toRemove.Reagent)
continue;
- var curQuantity = reagent.Quantity;
- var newQuantity = curQuantity - quantity;
+ var newQuantity = curQuantity - toRemove.Quantity;
_heatCapacityDirty = true;
if (newQuantity <= 0)
@@ -418,16 +474,38 @@ namespace Content.Shared.Chemistry.Components
return curQuantity;
}
- Contents[i] = new ReagentQuantity(reagentId, newQuantity);
- Volume -= quantity;
+ Contents[i] = new ReagentQuantity(reagent, newQuantity);
+ Volume -= toRemove.Quantity;
ValidateSolution();
- return quantity;
+ return toRemove.Quantity;
}
// Reagent is not on the solution...
return FixedPoint2.Zero;
}
+ ///
+ /// Attempts to remove an amount of reagent from the solution.
+ ///
+ /// The prototype of the reagent to be removed.
+ /// The amount of reagent to remove.
+ /// How much reagent was actually removed. Zero if the reagent is not present on the solution.
+ public FixedPoint2 RemoveReagent(string prototype, FixedPoint2 quantity, ReagentData? data = null)
+ {
+ return RemoveReagent(new ReagentQuantity(prototype, quantity, data));
+ }
+
+ ///
+ /// Attempts to remove an amount of reagent from the solution.
+ ///
+ /// The reagent to be removed.
+ /// The amount of reagent to remove.
+ /// How much reagent was actually removed. Zero if the reagent is not present on the solution.
+ public FixedPoint2 RemoveReagent(ReagentId reagentId, FixedPoint2 quantity)
+ {
+ return RemoveReagent(new ReagentQuantity(reagentId, quantity));
+ }
+
public void RemoveAllSolution()
{
Contents.Clear();
@@ -437,21 +515,33 @@ namespace Content.Shared.Chemistry.Components
}
///
- /// Splits a solution without the specified reagent.
+ /// Splits a solution without the specified reagent prototypes.
///
- public Solution SplitSolutionWithout(FixedPoint2 toTake, params string[] without)
+ public Solution SplitSolutionWithout(FixedPoint2 toTake, params string[] excludedPrototypes)
{
- var existing = new FixedPoint2[without.Length];
- for (var i = 0; i < without.Length; i++)
+ // First remove the blacklisted prototypes
+ List excluded = new();
+ foreach (var id in excludedPrototypes)
{
- TryGetReagent(without[i], out existing[i]);
- RemoveReagent(without[i], existing[i]);
+ foreach (var tuple in Contents)
+ {
+ if (tuple.Reagent.Prototype != id)
+ continue;
+
+ excluded.Add(tuple);
+ RemoveReagent(tuple);
+ break;
+ }
}
+ // Then split the solution
var sol = SplitSolution(toTake);
- for (var i = 0; i < without.Length; i++)
- AddReagent(without[i], existing[i]);
+ // Then re-add the excluded reagents to the original solution.
+ foreach (var reagent in excluded)
+ {
+ AddReagent(reagent);
+ }
return sol;
}
@@ -477,32 +567,32 @@ namespace Content.Shared.Chemistry.Components
for (var i = Contents.Count - 1; i >= 0; i--) // iterate backwards because of remove swap.
{
- var reagent = Contents[i];
+ var (reagent, quantity) = Contents[i];
// This is set up such that integer rounding will tend to take more reagents.
- var split = remaining * reagent.Quantity.Value / effVol;
+ var split = remaining * quantity.Value / effVol;
if (split <= 0)
{
- effVol -= reagent.Quantity.Value;
+ effVol -= quantity.Value;
DebugTools.Assert(split == 0, "Negative solution quantity while splitting? Long/int overflow?");
continue;
}
var splitQuantity = FixedPoint2.FromCents((int) split);
- var newQuantity = reagent.Quantity - splitQuantity;
+ var newQuantity = quantity - splitQuantity;
DebugTools.Assert(newQuantity >= 0);
if (newQuantity > FixedPoint2.Zero)
- Contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity);
+ Contents[i] = new ReagentQuantity(reagent, newQuantity);
else
Contents.RemoveSwap(i);
- newSolution.Contents.Add(new ReagentQuantity(reagent.ReagentId, splitQuantity));
+ newSolution.Contents.Add(new ReagentQuantity(reagent, splitQuantity));
Volume -= splitQuantity;
remaining -= split;
- effVol -= reagent.Quantity.Value;
+ effVol -= quantity.Value;
}
newSolution.Volume = origVol - Volume;
@@ -539,28 +629,28 @@ namespace Content.Shared.Chemistry.Components
var remaining = (long) toTake.Value;
for (var i = Contents.Count - 1; i >= 0; i--)// iterate backwards because of remove swap.
{
- var reagent = Contents[i];
+ var (reagent, quantity) = Contents[i];
// This is set up such that integer rounding will tend to take more reagents.
- var split = remaining * reagent.Quantity.Value / effVol;
+ var split = remaining * quantity.Value / effVol;
if (split <= 0)
{
- effVol -= reagent.Quantity.Value;
+ effVol -= quantity.Value;
DebugTools.Assert(split == 0, "Negative solution quantity while splitting? Long/int overflow?");
continue;
}
var splitQuantity = FixedPoint2.FromCents((int) split);
- var newQuantity = reagent.Quantity - splitQuantity;
+ var newQuantity = quantity - splitQuantity;
if (newQuantity > FixedPoint2.Zero)
- Contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity);
+ Contents[i] = new ReagentQuantity(reagent, newQuantity);
else
Contents.RemoveSwap(i);
remaining -= split;
- effVol -= reagent.Quantity.Value;
+ effVol -= quantity.Value;
}
DebugTools.Assert(remaining >= 0);
@@ -594,23 +684,23 @@ namespace Content.Shared.Chemistry.Components
for (var i = 0; i < otherSolution.Contents.Count; i++)
{
- var otherReagent = otherSolution.Contents[i];
+ var (otherReagent, otherQuantity) = otherSolution.Contents[i];
var found = false;
for (var j = 0; j < Contents.Count; j++)
{
- var reagent = Contents[j];
- if (reagent.ReagentId == otherReagent.ReagentId)
+ var (reagent, quantity) = Contents[j];
+ if (reagent == otherReagent)
{
found = true;
- Contents[j] = new ReagentQuantity(reagent.ReagentId, reagent.Quantity + otherReagent.Quantity);
+ Contents[j] = new ReagentQuantity(reagent, quantity + otherQuantity);
break;
}
}
if (!found)
{
- Contents.Add(new ReagentQuantity(otherReagent.ReagentId, otherReagent.Quantity));
+ Contents.Add(new ReagentQuantity(otherReagent, otherQuantity));
}
}
@@ -636,14 +726,14 @@ namespace Content.Shared.Chemistry.Components
var runningTotalQuantity = FixedPoint2.New(0);
bool first = true;
- foreach (var reagent in Contents)
+ foreach (var (reagent, quantity) in Contents)
{
- if (without.Contains(reagent.ReagentId))
+ if (without.Contains(reagent.Prototype))
continue;
- runningTotalQuantity += reagent.Quantity;
+ runningTotalQuantity += quantity;
- if (!protoMan.TryIndex(reagent.ReagentId, out ReagentPrototype? proto))
+ if (!protoMan.TryIndex(reagent.Prototype, out ReagentPrototype? proto))
{
continue;
}
@@ -655,7 +745,7 @@ namespace Content.Shared.Chemistry.Components
continue;
}
- var interpolateValue = reagent.Quantity.Float() / runningTotalQuantity.Float();
+ var interpolateValue = quantity.Float() / runningTotalQuantity.Float();
mixColor = Color.InterpolateBetween(mixColor, proto.SubstanceColor, interpolateValue);
}
return mixColor;
@@ -666,46 +756,6 @@ namespace Content.Shared.Chemistry.Components
return GetColorWithout(protoMan);
}
- [Obsolete("Use ReactiveSystem.DoEntityReaction")]
- public void DoEntityReaction(EntityUid uid, ReactionMethod method)
- {
- IoCManager.Resolve().GetEntitySystem().DoEntityReaction(uid, this, method);
- }
-
- [Serializable, NetSerializable]
- [DataDefinition]
- public readonly partial struct ReagentQuantity: IComparable
- {
- [DataField("ReagentId", customTypeSerializer:typeof(PrototypeIdSerializer), required:true)]
- public string ReagentId { get; init; }
- [DataField("Quantity", required:true)]
- public FixedPoint2 Quantity { get; init; }
-
- public ReagentQuantity(string reagentId, FixedPoint2 quantity)
- {
- ReagentId = reagentId;
- Quantity = quantity;
- }
-
- public ReagentQuantity() : this(string.Empty, default)
- {
- }
-
- [ExcludeFromCodeCoverage]
- public override string ToString()
- {
- return $"{ReagentId}:{Quantity}";
- }
-
- public int CompareTo(ReagentQuantity other) { return Quantity.Float().CompareTo(other.Quantity.Float()); }
-
- public void Deconstruct(out string reagentId, out FixedPoint2 quantity)
- {
- reagentId = ReagentId;
- quantity = Quantity;
- }
- }
-
#region Enumeration
public IEnumerator GetEnumerator()
@@ -721,6 +771,7 @@ namespace Content.Shared.Chemistry.Components
public void SetContents(IEnumerable reagents, bool setMaxVol = false)
{
+ Volume = 0;
RemoveAllSolution();
_heatCapacityDirty = true;
Contents = new(reagents);
@@ -735,5 +786,15 @@ namespace Content.Shared.Chemistry.Components
ValidateSolution();
}
+ public Dictionary GetReagentPrototypes(IPrototypeManager protoMan)
+ {
+ var dict = new Dictionary(Contents.Count);
+ foreach (var (reagent, quantity) in Contents)
+ {
+ var proto = protoMan.Index(reagent.Prototype);
+ dict[proto] = quantity + dict.GetValueOrDefault(proto);
+ }
+ return dict;
+ }
}
}
diff --git a/Content.Shared/Chemistry/Dispenser/ReagentDispenserInventoryPrototype.cs b/Content.Shared/Chemistry/Dispenser/ReagentDispenserInventoryPrototype.cs
index c308e46da5..8457816838 100644
--- a/Content.Shared/Chemistry/Dispenser/ReagentDispenserInventoryPrototype.cs
+++ b/Content.Shared/Chemistry/Dispenser/ReagentDispenserInventoryPrototype.cs
@@ -14,13 +14,11 @@ namespace Content.Shared.Chemistry.Dispenser
[Serializable, NetSerializable, Prototype("reagentDispenserInventory")]
public sealed class ReagentDispenserInventoryPrototype : IPrototype
{
+ // TODO use ReagentId
[DataField("inventory", customTypeSerializer: typeof(PrototypeIdListSerializer))]
- private List _inventory = new();
+ public List Inventory = new();
- [ViewVariables]
- [IdDataField]
- public string ID { get; private set; } = default!;
-
- public List Inventory => _inventory;
+ [ViewVariables, IdDataField]
+ public string ID { get; } = default!;
}
}
diff --git a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
index da8560fc5b..4ec50bc61a 100644
--- a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
+++ b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
@@ -136,7 +136,9 @@ namespace Content.Shared.Chemistry.Reaction
var reactantName = reactantData.Key;
var reactantCoefficient = reactantData.Value.Amount;
- if (!solution.TryGetReagent(reactantName, out var reactantQuantity))
+ var reactantQuantity = solution.GetTotalPrototypeQuantity(reactantName);
+
+ if (reactantQuantity <= FixedPoint2.Zero)
return false;
if (reactantData.Value.Catalyst)
@@ -292,7 +294,7 @@ namespace Content.Shared.Chemistry.Reaction
SortedSet reactions = new();
foreach (var reactant in solution.Contents)
{
- if (_reactions.TryGetValue(reactant.ReagentId, out var reactantReactions))
+ if (_reactions.TryGetValue(reactant.Reagent.Prototype, out var reactantReactions))
reactions.UnionWith(reactantReactions);
}
diff --git a/Content.Shared/Chemistry/ReactiveSystem.cs b/Content.Shared/Chemistry/ReactiveSystem.cs
index ca372e940b..4881a6bf96 100644
--- a/Content.Shared/Chemistry/ReactiveSystem.cs
+++ b/Content.Shared/Chemistry/ReactiveSystem.cs
@@ -19,32 +19,33 @@ namespace Content.Shared.Chemistry
public void DoEntityReaction(EntityUid uid, Solution solution, ReactionMethod method)
{
- foreach (var (reagentId, quantity) in solution.Contents.ToArray())
+ foreach (var reagent in solution.Contents.ToArray())
{
- ReactionEntity(uid, method, reagentId, quantity, solution);
+ ReactionEntity(uid, method, reagent, solution);
}
}
- public void ReactionEntity(EntityUid uid, ReactionMethod method, string reagentId, FixedPoint2 reactVolume, Solution? source)
+ public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentQuantity reagentQuantity, Solution? source)
{
// We throw if the reagent specified doesn't exist.
- ReactionEntity(uid, method, _prototypeManager.Index(reagentId), reactVolume, source);
+ var proto = _prototypeManager.Index(reagentQuantity.Reagent.Prototype);
+ ReactionEntity(uid, method, proto, reagentQuantity, source);
}
- public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentPrototype reagent,
- FixedPoint2 reactVolume, Solution? source)
+ public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentPrototype proto,
+ ReagentQuantity reagentQuantity, Solution? source)
{
- if (!EntityManager.TryGetComponent(uid, out ReactiveComponent? reactive))
+ if (!TryComp(uid, out ReactiveComponent? reactive))
return;
// If we have a source solution, use the reagent quantity we have left. Otherwise, use the reaction volume specified.
- var args = new ReagentEffectArgs(uid, null, source, reagent,
- source?.GetReagentQuantity(reagent.ID) ?? reactVolume, EntityManager, method, 1f);
+ var args = new ReagentEffectArgs(uid, null, source, proto,
+ source?.GetReagentQuantity(reagentQuantity.Reagent) ?? reagentQuantity.Quantity, EntityManager, method, 1f);
// First, check if the reagent wants to apply any effects.
- if (reagent.ReactiveEffects != null && reactive.ReactiveGroups != null)
+ if (proto.ReactiveEffects != null && reactive.ReactiveGroups != null)
{
- foreach (var (key, val) in reagent.ReactiveEffects)
+ foreach (var (key, val) in proto.ReactiveEffects)
{
if (!val.Methods.Contains(method))
continue;
@@ -64,7 +65,7 @@ namespace Content.Shared.Chemistry
{
var entity = args.SolutionEntity;
_adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
- $"Reactive effect {effect.GetType().Name:effect} of reagent {reagent.ID:reagent} with method {method} applied on entity {ToPrettyString(entity):entity} at {Transform(entity).Coordinates:coordinates}");
+ $"Reactive effect {effect.GetType().Name:effect} of reagent {proto.ID:reagent} with method {method} applied on entity {ToPrettyString(entity):entity} at {Transform(entity).Coordinates:coordinates}");
}
effect.Effect(args);
@@ -80,7 +81,7 @@ namespace Content.Shared.Chemistry
if (!entry.Methods.Contains(method))
continue;
- if (entry.Reagents != null && !entry.Reagents.Contains(reagent.ID))
+ if (entry.Reagents != null && !entry.Reagents.Contains(proto.ID))
continue;
foreach (var effect in entry.Effects)
@@ -92,7 +93,7 @@ namespace Content.Shared.Chemistry
{
var entity = args.SolutionEntity;
_adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
- $"Reactive effect {effect.GetType().Name:effect} of {ToPrettyString(entity):entity} using reagent {reagent.ID:reagent} with method {method} at {Transform(entity).Coordinates:coordinates}");
+ $"Reactive effect {effect.GetType().Name:effect} of {ToPrettyString(entity):entity} using reagent {proto.ID:reagent} with method {method} at {Transform(entity).Coordinates:coordinates}");
}
effect.Effect(args);
diff --git a/Content.Shared/Chemistry/Reagent/ReagentData.cs b/Content.Shared/Chemistry/Reagent/ReagentData.cs
new file mode 100644
index 0000000000..a4a77f552e
--- /dev/null
+++ b/Content.Shared/Chemistry/Reagent/ReagentData.cs
@@ -0,0 +1,44 @@
+using Content.Shared.FixedPoint;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Chemistry.Reagent;
+
+[ImplicitDataDefinitionForInheritors, Serializable, NetSerializable]
+public abstract partial class ReagentData : IEquatable
+{
+ ///
+ /// Convert to a string representation. This if for logging & debugging. This is not localized and should not be
+ /// shown to players.
+ ///
+ public virtual string ToString(string prototype, FixedPoint2 quantity)
+ {
+ return $"{prototype}:{GetType().Name}:{quantity}";
+ }
+
+ ///
+ /// Convert to a string representation. This if for logging & debugging. This is not localized and should not be
+ /// shown to players.
+ ///
+ public virtual string ToString(string prototype)
+ {
+ return $"{prototype}:{GetType().Name}";
+ }
+
+ public abstract bool Equals(ReagentData? other);
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj))
+ return false;
+ if (ReferenceEquals(this, obj))
+ return true;
+ if (obj.GetType() != GetType())
+ return false;
+
+ return Equals((ReagentData) obj);
+ }
+
+ public abstract override int GetHashCode();
+
+ public abstract ReagentData Clone();
+}
diff --git a/Content.Shared/Chemistry/Reagent/ReagentId.cs b/Content.Shared/Chemistry/Reagent/ReagentId.cs
new file mode 100644
index 0000000000..07a4200219
--- /dev/null
+++ b/Content.Shared/Chemistry/Reagent/ReagentId.cs
@@ -0,0 +1,93 @@
+using Content.Shared.FixedPoint;
+using Robust.Shared.Serialization;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Chemistry.Reagent;
+
+///
+/// Struct used to uniquely identify a reagent. This is usually just a ReagentPrototype id string, however some reagents
+/// contain additional data (e.g., blood could store DNA data).
+///
+[Serializable, NetSerializable]
+[DataDefinition]
+public partial struct ReagentId : IEquatable
+{
+ // TODO rename data field.
+ [DataField("ReagentId", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)]
+ public string Prototype { get; private set; }
+
+ ///
+ /// Any additional data that is unique to this reagent type. E.g., for blood this could be DNA data.
+ ///
+ [DataField("data")]
+ public ReagentData? Data { get; private set; }
+
+ public ReagentId(string prototype, ReagentData? data)
+ {
+ Prototype = prototype;
+ Data = data;
+ }
+
+ public ReagentId()
+ {
+ Prototype = default!;
+ }
+
+ public bool Equals(ReagentId other)
+ {
+ if (Prototype != other.Prototype)
+ return false;
+
+ if (Data == null)
+ return other.Data == null;
+
+ if (other.Data == null)
+ return false;
+
+ if (Data.GetType() != other.Data.GetType())
+ return false;
+
+ return Data.Equals(other.Data);
+ }
+
+ public bool Equals(string prototype, ReagentData? otherData = null)
+ {
+ if (Prototype != prototype)
+ return false;
+
+ if (Data == null)
+ return otherData == null;
+
+ return Data.Equals(otherData);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is ReagentId other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Prototype, Data);
+ }
+
+ public string ToString(FixedPoint2 quantity)
+ {
+ return Data?.ToString(Prototype, quantity) ?? $"{Prototype}:{quantity}";
+ }
+
+ public override string ToString()
+ {
+ return Data?.ToString(Prototype) ?? Prototype;
+ }
+
+ public static bool operator ==(ReagentId left, ReagentId right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(ReagentId left, ReagentId right)
+ {
+ return !(left == right);
+ }
+}
diff --git a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs
index 8d1af84edb..0f24a36339 100644
--- a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs
+++ b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs
@@ -141,7 +141,7 @@ namespace Content.Shared.Chemistry.Reagent
return removed;
}
- public void ReactionPlant(EntityUid? plantHolder, Solution.ReagentQuantity amount, Solution solution)
+ public void ReactionPlant(EntityUid? plantHolder, ReagentQuantity amount, Solution solution)
{
if (plantHolder == null)
return;
diff --git a/Content.Shared/Chemistry/Reagent/ReagentQuantity.cs b/Content.Shared/Chemistry/Reagent/ReagentQuantity.cs
new file mode 100644
index 0000000000..9644f919f7
--- /dev/null
+++ b/Content.Shared/Chemistry/Reagent/ReagentQuantity.cs
@@ -0,0 +1,77 @@
+using Content.Shared.FixedPoint;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Chemistry.Reagent;
+
+///
+/// Simple struct for storing a & quantity tuple.
+///
+[Serializable, NetSerializable]
+[DataDefinition]
+public partial struct ReagentQuantity : IEquatable
+{
+ [DataField("Quantity", required:true)]
+ public FixedPoint2 Quantity { get; private set; }
+
+ [IncludeDataField]
+ [ViewVariables]
+ public ReagentId Reagent { get; private set; }
+
+ public ReagentQuantity(string reagentId, FixedPoint2 quantity, ReagentData? data)
+ : this(new ReagentId(reagentId, data), quantity)
+ {
+ }
+
+ public ReagentQuantity(ReagentId reagent, FixedPoint2 quantity)
+ {
+ Reagent = reagent;
+ Quantity = quantity;
+ }
+
+ public ReagentQuantity() : this(default, default)
+ {
+ }
+
+ public override string ToString()
+ {
+ return Reagent.ToString(Quantity);
+ }
+
+ public void Deconstruct(out string prototype, out FixedPoint2 quantity, out ReagentData? data)
+ {
+ prototype = Reagent.Prototype;
+ quantity = Quantity;
+ data = Reagent.Data;
+ }
+
+ public void Deconstruct(out ReagentId id, out FixedPoint2 quantity)
+ {
+ id = Reagent;
+ quantity = Quantity;
+ }
+
+ public bool Equals(ReagentQuantity other)
+ {
+ return Quantity != other.Quantity && Reagent.Equals(other.Reagent);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is ReagentQuantity other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Reagent.GetHashCode(), Quantity);
+ }
+
+ public static bool operator ==(ReagentQuantity left, ReagentQuantity right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(ReagentQuantity left, ReagentQuantity right)
+ {
+ return !(left == right);
+ }
+}
diff --git a/Content.Shared/Chemistry/SharedChemMaster.cs b/Content.Shared/Chemistry/SharedChemMaster.cs
index 0e20e91a51..027002098e 100644
--- a/Content.Shared/Chemistry/SharedChemMaster.cs
+++ b/Content.Shared/Chemistry/SharedChemMaster.cs
@@ -1,4 +1,5 @@
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Serialization;
@@ -43,11 +44,11 @@ namespace Content.Shared.Chemistry
[Serializable, NetSerializable]
public sealed class ChemMasterReagentAmountButtonMessage : BoundUserInterfaceMessage
{
- public readonly string ReagentId;
+ public readonly ReagentId ReagentId;
public readonly ChemMasterReagentAmount Amount;
public readonly bool FromBuffer;
- public ChemMasterReagentAmountButtonMessage(string reagentId, ChemMasterReagentAmount amount, bool fromBuffer)
+ public ChemMasterReagentAmountButtonMessage(ReagentId reagentId, ChemMasterReagentAmount amount, bool fromBuffer)
{
ReagentId = reagentId;
Amount = amount;
@@ -121,34 +122,29 @@ namespace Content.Shared.Chemistry
/// The container name to show to the player
///
public readonly string DisplayName;
- ///
- /// Whether the container holds reagents or entities
- ///
- public readonly bool HoldsReagents;
+
///
/// The currently used volume of the container
///
public readonly FixedPoint2 CurrentVolume;
+
///
/// The maximum volume of the container
///
public readonly FixedPoint2 MaxVolume;
- ///
- /// A list of the reagents/entities and their sizes within the container
- ///
- // todo: this causes NetSerializer exceptions if it's an IReadOnlyList (which would be preferred)
- public readonly List<(string Id, FixedPoint2 Quantity)> Contents;
- public ContainerInfo(
- string displayName, bool holdsReagents,
- FixedPoint2 currentVolume, FixedPoint2 maxVolume,
- List<(string, FixedPoint2)> contents)
+ ///
+ /// A list of the entities and their sizes within the container
+ ///
+ public List<(string Id, FixedPoint2 Quantity)>? Entities { get; init; }
+
+ public List? Reagents { get; init; }
+
+ public ContainerInfo(string displayName, FixedPoint2 currentVolume, FixedPoint2 maxVolume)
{
DisplayName = displayName;
- HoldsReagents = holdsReagents;
CurrentVolume = currentVolume;
MaxVolume = maxVolume;
- Contents = contents;
}
}
@@ -161,7 +157,7 @@ namespace Content.Shared.Chemistry
///
/// A list of the reagents and their amounts within the buffer, if applicable.
///
- public readonly IReadOnlyList BufferReagents;
+ public readonly IReadOnlyList BufferReagents;
public readonly ChemMasterMode Mode;
@@ -174,7 +170,7 @@ namespace Content.Shared.Chemistry
public ChemMasterBoundUserInterfaceState(
ChemMasterMode mode, ContainerInfo? inputContainerInfo, ContainerInfo? outputContainerInfo,
- IReadOnlyList bufferReagents, FixedPoint2 bufferCurrentVolume,
+ IReadOnlyList bufferReagents, FixedPoint2 bufferCurrentVolume,
uint selectedPillType, uint pillDosageLimit, bool updateLabel)
{
InputContainerInfo = inputContainerInfo;
diff --git a/Content.Shared/Chemistry/SharedReagentDispenser.cs b/Content.Shared/Chemistry/SharedReagentDispenser.cs
index 3dd9a18f42..1ecb0993f5 100644
--- a/Content.Shared/Chemistry/SharedReagentDispenser.cs
+++ b/Content.Shared/Chemistry/SharedReagentDispenser.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Serialization;
namespace Content.Shared.Chemistry
@@ -24,9 +25,9 @@ namespace Content.Shared.Chemistry
[Serializable, NetSerializable]
public sealed class ReagentDispenserDispenseReagentMessage : BoundUserInterfaceMessage
{
- public readonly string ReagentId;
+ public readonly ReagentId ReagentId;
- public ReagentDispenserDispenseReagentMessage(string reagentId)
+ public ReagentDispenserDispenseReagentMessage(ReagentId reagentId)
{
ReagentId = reagentId;
}
@@ -58,11 +59,11 @@ namespace Content.Shared.Chemistry
///
/// A list of the reagents which this dispenser can dispense.
///
- public readonly List Inventory;
+ public readonly List Inventory;
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
- public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, List inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
+ public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, List inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
{
OutputContainer = outputContainer;
Inventory = inventory;
diff --git a/Content.Shared/Kitchen/Components/SharedMicrowave.cs b/Content.Shared/Kitchen/Components/SharedMicrowave.cs
index c625987ae7..06ac79af98 100644
--- a/Content.Shared/Kitchen/Components/SharedMicrowave.cs
+++ b/Content.Shared/Kitchen/Components/SharedMicrowave.cs
@@ -1,4 +1,5 @@
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Serialization;
namespace Content.Shared.Kitchen.Components
@@ -27,8 +28,8 @@ namespace Content.Shared.Kitchen.Components
[Serializable, NetSerializable]
public sealed class MicrowaveVaporizeReagentIndexedMessage : BoundUserInterfaceMessage
{
- public Solution.ReagentQuantity ReagentQuantity;
- public MicrowaveVaporizeReagentIndexedMessage(Solution.ReagentQuantity reagentQuantity)
+ public ReagentQuantity ReagentQuantity;
+ public MicrowaveVaporizeReagentIndexedMessage(ReagentQuantity reagentQuantity)
{
ReagentQuantity = reagentQuantity;
}
diff --git a/Content.Shared/Kitchen/MicrowaveMealRecipePrototype.cs b/Content.Shared/Kitchen/MicrowaveMealRecipePrototype.cs
index 898d911141..3ee8e8ee4a 100644
--- a/Content.Shared/Kitchen/MicrowaveMealRecipePrototype.cs
+++ b/Content.Shared/Kitchen/MicrowaveMealRecipePrototype.cs
@@ -33,6 +33,7 @@ namespace Content.Shared.Kitchen
public string Name => Loc.GetString(_name);
+ // TODO Turn this into a ReagentQuantity[]
public IReadOnlyDictionary IngredientsReagents => _ingsReagents;
public IReadOnlyDictionary IngredientsSolids => _ingsSolids;
diff --git a/Content.Shared/Kitchen/SharedReagentGrinder.cs b/Content.Shared/Kitchen/SharedReagentGrinder.cs
index a9a3d88bb8..97c13814b0 100644
--- a/Content.Shared/Kitchen/SharedReagentGrinder.cs
+++ b/Content.Shared/Kitchen/SharedReagentGrinder.cs
@@ -1,4 +1,5 @@
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Serialization;
namespace Content.Shared.Kitchen
@@ -84,8 +85,8 @@ namespace Content.Shared.Kitchen
public bool CanJuice;
public bool CanGrind;
public EntityUid[] ChamberContents;
- public Solution.ReagentQuantity[]? ReagentQuantities;
- public ReagentGrinderInterfaceState(bool isBusy, bool hasBeaker, bool powered, bool canJuice, bool canGrind, EntityUid[] chamberContents, Solution.ReagentQuantity[]? heldBeakerContents)
+ public ReagentQuantity[]? ReagentQuantities;
+ public ReagentGrinderInterfaceState(bool isBusy, bool hasBeaker, bool powered, bool canJuice, bool canGrind, EntityUid[] chamberContents, ReagentQuantity[]? heldBeakerContents)
{
IsBusy = isBusy;
HasBeakerIn = hasBeaker;
diff --git a/Content.Shared/Materials/PhysicalCompositionComponent.cs b/Content.Shared/Materials/PhysicalCompositionComponent.cs
index 97ec3d7b65..4066bb9f7c 100644
--- a/Content.Shared/Materials/PhysicalCompositionComponent.cs
+++ b/Content.Shared/Materials/PhysicalCompositionComponent.cs
@@ -27,4 +27,5 @@ public sealed partial class PhysicalCompositionComponent : Component
///
[DataField("chemicalComposition", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))]
public Dictionary ChemicalComposition = new();
+ // TODO use ReagentQuantity[]
}
diff --git a/Content.Tests/Shared/Chemistry/Solution_Tests.cs b/Content.Tests/Shared/Chemistry/SolutionTests.cs
similarity index 75%
rename from Content.Tests/Shared/Chemistry/Solution_Tests.cs
rename to Content.Tests/Shared/Chemistry/SolutionTests.cs
index 3819876a44..0fa23d2491 100644
--- a/Content.Tests/Shared/Chemistry/Solution_Tests.cs
+++ b/Content.Tests/Shared/Chemistry/SolutionTests.cs
@@ -8,7 +8,7 @@ using Robust.Shared.Utility;
namespace Content.Tests.Shared.Chemistry;
[TestFixture, Parallelizable, TestOf(typeof(Solution))]
-public sealed class Solution_Tests : ContentUnitTest
+public sealed class SolutionTests : ContentUnitTest
{
[OneTimeSetUp]
public void Setup()
@@ -21,7 +21,7 @@ public sealed class Solution_Tests : ContentUnitTest
{
var solution = new Solution();
solution.AddReagent("water", FixedPoint2.New(1000));
- var quantity = solution.GetReagentQuantity("water");
+ var quantity = solution.GetTotalPrototypeQuantity("water");
Assert.That(quantity.Int(), Is.EqualTo(1000));
}
@@ -44,8 +44,8 @@ public sealed class Solution_Tests : ContentUnitTest
tmp.ScaleSolution(2);
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(100)));
- Assert.That(tmp.GetReagentQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
- Assert.That(tmp.GetReagentQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
+ Assert.That(tmp.GetTotalPrototypeQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
+ Assert.That(tmp.GetTotalPrototypeQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
}
// Test float scaling
@@ -59,15 +59,15 @@ public sealed class Solution_Tests : ContentUnitTest
tmp.ScaleSolution(2f);
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(100)));
- Assert.That(tmp.GetReagentQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
- Assert.That(tmp.GetReagentQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
+ Assert.That(tmp.GetTotalPrototypeQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
+ Assert.That(tmp.GetTotalPrototypeQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
tmp = solution.Clone();
tmp.ScaleSolution(0.3f);
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(15)));
- Assert.That(tmp.GetReagentQuantity("water"), Is.EqualTo(FixedPoint2.New(6)));
- Assert.That(tmp.GetReagentQuantity("fire"), Is.EqualTo(FixedPoint2.New(9)));
+ Assert.That(tmp.GetTotalPrototypeQuantity("water"), Is.EqualTo(FixedPoint2.New(6)));
+ Assert.That(tmp.GetTotalPrototypeQuantity("fire"), Is.EqualTo(FixedPoint2.New(9)));
}
}
@@ -75,7 +75,7 @@ public sealed class Solution_Tests : ContentUnitTest
public void ConstructorAddReagent()
{
var solution = new Solution("water", FixedPoint2.New(1000));
- var quantity = solution.GetReagentQuantity("water");
+ var quantity = solution.GetTotalPrototypeQuantity("water");
Assert.That(quantity.Int(), Is.EqualTo(1000));
}
@@ -84,7 +84,7 @@ public sealed class Solution_Tests : ContentUnitTest
public void NonExistingReagentReturnsZero()
{
var solution = new Solution();
- var quantity = solution.GetReagentQuantity("water");
+ var quantity = solution.GetTotalPrototypeQuantity("water");
Assert.That(quantity.Int(), Is.EqualTo(0));
}
@@ -94,7 +94,7 @@ public sealed class Solution_Tests : ContentUnitTest
public void AddLessThanZeroReagentReturnsZero()
{
var solution = new Solution("water", FixedPoint2.New(-1000));
- var quantity = solution.GetReagentQuantity("water");
+ var quantity = solution.GetTotalPrototypeQuantity("water");
Assert.That(quantity.Int(), Is.EqualTo(0));
}
@@ -106,7 +106,7 @@ public sealed class Solution_Tests : ContentUnitTest
var solution = new Solution();
solution.AddReagent("water", FixedPoint2.New(1000));
solution.AddReagent("water", FixedPoint2.New(2000));
- var quantity = solution.GetReagentQuantity("water");
+ var quantity = solution.GetTotalPrototypeQuantity("water");
Assert.That(quantity.Int(), Is.EqualTo(3000));
}
@@ -118,8 +118,8 @@ public sealed class Solution_Tests : ContentUnitTest
solution.AddReagent("water", FixedPoint2.New(1000));
solution.AddReagent("fire", FixedPoint2.New(2000));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
- Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(1000));
+ Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
}
[Test]
@@ -141,8 +141,8 @@ public sealed class Solution_Tests : ContentUnitTest
var newSolution = solution.Clone();
- Assert.That(newSolution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
- Assert.That(newSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
+ Assert.That(newSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(1000));
+ Assert.That(newSolution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
Assert.That(newSolution.Volume.Int(), Is.EqualTo(3000));
}
@@ -155,8 +155,8 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveReagent("water", FixedPoint2.New(500));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
- Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(500));
+ Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
Assert.That(solution.Volume.Int(), Is.EqualTo(2500));
}
@@ -167,7 +167,7 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveReagent("water", FixedPoint2.New(-100));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(100));
Assert.That(solution.Volume.Int(), Is.EqualTo(100));
}
@@ -178,7 +178,7 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveReagent("water", FixedPoint2.New(1000));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
}
@@ -189,7 +189,7 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveReagent("fire", FixedPoint2.New(1000));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(100));
Assert.That(solution.Volume.Int(), Is.EqualTo(100));
}
@@ -201,7 +201,7 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveSolution(FixedPoint2.New(500));
//Check that edited solution is correct
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(200));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(200));
Assert.That(solution.Volume.Int(), Is.EqualTo(200));
}
@@ -213,7 +213,7 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveSolution(FixedPoint2.New(1000));
//Check that edited solution is correct
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
}
@@ -226,8 +226,8 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveSolution(FixedPoint2.New(1500));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
- Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1000));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(500));
+ Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(1000));
Assert.That(solution.Volume.Int(), Is.EqualTo(1500));
}
@@ -238,7 +238,7 @@ public sealed class Solution_Tests : ContentUnitTest
solution.RemoveSolution(FixedPoint2.New(-200));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(800));
Assert.That(solution.Volume.Int(), Is.EqualTo(800));
}
@@ -251,12 +251,12 @@ public sealed class Solution_Tests : ContentUnitTest
var splitSolution = solution.SplitSolution(FixedPoint2.New(750));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(750));
- Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1500));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(750));
+ Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(1500));
Assert.That(solution.Volume.Int(), Is.EqualTo(2250));
- Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(250));
- Assert.That(splitSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(500));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(250));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(500));
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(750));
}
@@ -269,12 +269,12 @@ public sealed class Solution_Tests : ContentUnitTest
var splitSolution = solution.SplitSolution(FixedPoint2.New(1));
- Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.66f));
- Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.34f));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.66f));
+ Assert.That(solution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(1.34f));
Assert.That(solution.Volume.Int(), Is.EqualTo(2));
- Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.34f));
- Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.66f));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.34f));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(0.66f));
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(1));
}
@@ -287,12 +287,12 @@ public sealed class Solution_Tests : ContentUnitTest
var splitSolution = solution.SplitSolution(FixedPoint2.New(2));
- Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f));
- Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.33f));
+ Assert.That(solution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(0.67f));
Assert.That(solution.Volume.Int(), Is.EqualTo(1));
- Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f));
- Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.67f));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(1.33f));
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(2));
}
@@ -306,10 +306,10 @@ public sealed class Solution_Tests : ContentUnitTest
var splitSolution = solution.SplitSolution(FixedPoint2.New(reduce));
- Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(remainder));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(remainder));
Assert.That(solution.Volume.Float(), Is.EqualTo(remainder));
- Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(reduce));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(reduce));
Assert.That(splitSolution.Volume.Float(), Is.EqualTo(reduce));
}
@@ -338,10 +338,10 @@ public sealed class Solution_Tests : ContentUnitTest
var splitSolution = solution.SplitSolution(FixedPoint2.New(1000));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
- Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(800));
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(800));
}
@@ -352,10 +352,10 @@ public sealed class Solution_Tests : ContentUnitTest
var splitSolution = solution.SplitSolution(FixedPoint2.New(-200));
- Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
+ Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(800));
Assert.That(solution.Volume.Int(), Is.EqualTo(800));
- Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
+ Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(0));
}
@@ -393,9 +393,9 @@ public sealed class Solution_Tests : ContentUnitTest
solutionOne.AddSolution(solutionTwo, null);
- Assert.That(solutionOne.GetReagentQuantity("water").Int(), Is.EqualTo(1500));
- Assert.That(solutionOne.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
- Assert.That(solutionOne.GetReagentQuantity("earth").Int(), Is.EqualTo(1000));
+ Assert.That(solutionOne.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(1500));
+ Assert.That(solutionOne.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
+ Assert.That(solutionOne.GetTotalPrototypeQuantity("earth").Int(), Is.EqualTo(1000));
Assert.That(solutionOne.Volume.Int(), Is.EqualTo(4500));
}