namespace Content.Server.Chemistry.Containers.EntitySystems;
+[Obsolete("This is being depreciated. Use SharedSolutionContainerSystem instead!")]
public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem
{
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<SolutionContainerManagerComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentShutdown>(OnComponentShutdown);
- SubscribeLocalEvent<ContainedSolutionComponent, ComponentShutdown>(OnComponentShutdown);
- }
-
-
+ [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")]
public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name)
=> EnsureSolution(entity, name, out _);
+ [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")]
public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name, out bool existed)
=> EnsureSolution(entity, name, FixedPoint2.Zero, out existed);
+ [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")]
public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name, FixedPoint2 maxVol, out bool existed)
=> EnsureSolution(entity, name, maxVol, null, out existed);
+ [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")]
public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed)
{
- var (uid, meta) = entity;
- if (!Resolve(uid, ref meta))
- throw new InvalidOperationException("Attempted to ensure solution on invalid entity.");
-
- var manager = EnsureComp<SolutionContainerManagerComponent>(uid);
- if (meta.EntityLifeStage >= EntityLifeStage.MapInitialized)
- return EnsureSolutionEntity((uid, manager), name, maxVol, prototype, out existed).Comp.Solution;
- else
- return EnsureSolutionPrototype((uid, manager), name, maxVol, prototype, out existed);
- }
-
- public void EnsureAllSolutions(Entity<SolutionContainerManagerComponent> entity)
- {
- if (entity.Comp.Solutions is not { } prototypes)
- return;
-
- foreach (var (name, prototype) in prototypes)
- {
- EnsureSolutionEntity((entity.Owner, entity.Comp), name, prototype.MaxVolume, prototype, out _);
- }
-
- entity.Comp.Solutions = null;
- Dirty(entity);
- }
-
- public Entity<SolutionComponent> EnsureSolutionEntity(Entity<SolutionContainerManagerComponent?> entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed)
- {
- existed = true;
-
- var (uid, container) = entity;
-
- var solutionSlot = ContainerSystem.EnsureContainer<ContainerSlot>(uid, $"solution@{name}", out existed);
- if (!Resolve(uid, ref container, logMissing: false))
- {
- existed = false;
- container = AddComp<SolutionContainerManagerComponent>(uid);
- container.Containers.Add(name);
- }
- else if (!existed)
- {
- container.Containers.Add(name);
- Dirty(uid, container);
- }
-
- var needsInit = false;
- SolutionComponent solutionComp;
- if (solutionSlot.ContainedEntity is not { } solutionId)
- {
- prototype ??= new() { MaxVolume = maxVol };
- prototype.Name = name;
- (solutionId, solutionComp, _) = SpawnSolutionUninitialized(solutionSlot, name, maxVol, prototype);
- existed = false;
- needsInit = true;
- Dirty(uid, container);
- }
- else
- {
- solutionComp = Comp<SolutionComponent>(solutionId);
- DebugTools.Assert(TryComp(solutionId, out ContainedSolutionComponent? relation) && relation.Container == uid && relation.ContainerName == name);
- DebugTools.Assert(solutionComp.Solution.Name == name);
-
- var solution = solutionComp.Solution;
- solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol);
-
- // Depending on MapInitEvent order some systems can ensure solution empty solutions and conflict with the prototype solutions.
- // We want the reagents from the prototype to exist even if something else already created the solution.
- if (prototype is { Volume.Value: > 0 })
- solution.AddSolution(prototype, PrototypeManager);
-
- Dirty(solutionId, solutionComp);
- }
-
- if (needsInit)
- EntityManager.InitializeAndStartEntity(solutionId, Transform(solutionId).MapID);
-
- return (solutionId, solutionComp);
- }
-
- private Solution EnsureSolutionPrototype(Entity<SolutionContainerManagerComponent?> entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed)
- {
- existed = true;
-
- var (uid, container) = entity;
- if (!Resolve(uid, ref container, logMissing: false))
- {
- container = AddComp<SolutionContainerManagerComponent>(uid);
- existed = false;
- }
-
- if (container.Solutions is null)
- container.Solutions = new(SolutionContainerManagerComponent.DefaultCapacity);
-
- if (!container.Solutions.TryGetValue(name, out var solution))
- {
- solution = prototype ?? new() { Name = name, MaxVolume = maxVol };
- container.Solutions.Add(name, solution);
- existed = false;
- }
- else
- solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol);
-
- Dirty(uid, container);
- return solution;
+ EnsureSolution(entity, name, maxVol, prototype, out existed, out var solution);
+ return solution!;//solution is only ever null on the client, so we can suppress this
}
-
- private Entity<SolutionComponent, ContainedSolutionComponent> SpawnSolutionUninitialized(ContainerSlot container, string name, FixedPoint2 maxVol, Solution prototype)
+ [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")]
+ public Entity<SolutionComponent> EnsureSolutionEntity(
+ Entity<SolutionContainerManagerComponent?> entity,
+ string name,
+ FixedPoint2 maxVol,
+ Solution? prototype,
+ out bool existed)
{
- var coords = new EntityCoordinates(container.Owner, Vector2.Zero);
- var uid = EntityManager.CreateEntityUninitialized(null, coords, null);
-
- var solution = new SolutionComponent() { Solution = prototype };
- AddComp(uid, solution);
-
- var relation = new ContainedSolutionComponent() { Container = container.Owner, ContainerName = name };
- AddComp(uid, relation);
-
- MetaData.SetEntityName(uid, $"solution - {name}");
- ContainerSystem.Insert(uid, container, force: true);
-
- return (uid, solution, relation);
+ EnsureSolutionEntity(entity, name, out existed, out var solEnt, maxVol, prototype);
+ return solEnt!.Value;//solEnt is only ever null on the client, so we can suppress this
}
-
- #region Event Handlers
-
- private void OnMapInit(Entity<SolutionContainerManagerComponent> entity, ref MapInitEvent args)
- {
- EnsureAllSolutions(entity);
- }
-
- private void OnComponentShutdown(Entity<SolutionContainerManagerComponent> entity, ref ComponentShutdown args)
- {
- foreach (var name in entity.Comp.Containers)
- {
- if (ContainerSystem.TryGetContainer(entity, $"solution@{name}", out var solutionContainer))
- ContainerSystem.ShutdownContainer(solutionContainer);
- }
- entity.Comp.Containers.Clear();
- }
-
- private void OnComponentShutdown(Entity<ContainedSolutionComponent> entity, ref ComponentShutdown args)
- {
- if (TryComp(entity.Comp.Container, out SolutionContainerManagerComponent? container))
- {
- container.Containers.Remove(entity.Comp.ContainerName);
- Dirty(entity.Comp.Container, container);
- }
-
- if (ContainerSystem.TryGetContainer(entity, $"solution@{entity.Comp.ContainerName}", out var solutionContainer))
- ContainerSystem.ShutdownContainer(solutionContainer);
- }
-
- #endregion Event Handlers
}
using Robust.Shared.Utility;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
+using Robust.Shared.Map;
+using Robust.Shared.Network;
using Dependency = Robust.Shared.IoC.DependencyAttribute;
namespace Content.Shared.Chemistry.EntitySystems;
[Dependency] protected readonly SharedHandsSystem Hands = default!;
[Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
[Dependency] protected readonly MetaDataSystem MetaData = default!;
+ [Dependency] protected readonly INetManager NetManager = default!;
public override void Initialize()
{
InitializeRelays();
SubscribeLocalEvent<SolutionComponent, ComponentInit>(OnComponentInit);
- SubscribeLocalEvent<SolutionComponent, ComponentStartup>(OnComponentStartup);
- SubscribeLocalEvent<SolutionComponent, ComponentShutdown>(OnComponentShutdown);
-
- SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentInit>(OnComponentInit);
-
+ SubscribeLocalEvent<SolutionComponent, ComponentStartup>(OnSolutionStartup);
+ SubscribeLocalEvent<SolutionComponent, ComponentShutdown>(OnSolutionShutdown);
+ SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentInit>(OnContainerManagerInit);
SubscribeLocalEvent<ExaminableSolutionComponent, ExaminedEvent>(OnExamineSolution);
SubscribeLocalEvent<ExaminableSolutionComponent, GetVerbsEvent<ExamineVerb>>(OnSolutionExaminableVerb);
+ SubscribeLocalEvent<SolutionContainerManagerComponent, MapInitEvent>(OnMapInit);
+
+ if (NetManager.IsServer)
+ {
+ SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentShutdown>(OnContainerManagerShutdown);
+ SubscribeLocalEvent<ContainedSolutionComponent, ComponentShutdown>(OnContainedSolutionShutdown);
+ }
}
/// <param name="name">The name of the solution entity to fetch.</param>
/// <param name="entity">Returns the solution entity that was fetched.</param>
/// <param name="solution">Returns the solution state of the solution entity that was fetched.</param>
+ /// /// <param name="errorOnMissing">Should we print an error if the solution specified by name is missing</param>
/// <returns></returns>
- public bool TryGetSolution(Entity<SolutionContainerManagerComponent?> container, string? name, [NotNullWhen(true)] out Entity<SolutionComponent>? entity, [NotNullWhen(true)] out Solution? solution)
+ public bool TryGetSolution(
+ Entity<SolutionContainerManagerComponent?> container,
+ string? name,
+ [NotNullWhen(true)] out Entity<SolutionComponent>? entity,
+ [NotNullWhen(true)] out Solution? solution,
+ bool errorOnMissing = false)
{
if (!TryGetSolution(container, name, out entity))
{
}
/// <inheritdoc cref="TryGetSolution"/>
- public bool TryGetSolution(Entity<SolutionContainerManagerComponent?> container, string? name, [NotNullWhen(true)] out Entity<SolutionComponent>? entity)
+ public bool TryGetSolution(
+ Entity<SolutionContainerManagerComponent?> container,
+ string? name,
+ [NotNullWhen(true)] out Entity<SolutionComponent>? entity,
+ bool errorOnMissing = false)
{
if (TryComp(container, out BlockSolutionAccessComponent? blocker))
{
else
{
entity = null;
+ if (!errorOnMissing)
+ return false;
+ Log.Error($"{ToPrettyString(container)} does not have a solution with ID: {name}");
return false;
}
if (!TryComp(uid, out SolutionComponent? comp))
{
entity = null;
+ if (!errorOnMissing)
+ return false;
+ Log.Error($"{ToPrettyString(container)} does not have a solution with ID: {name}");
return false;
}
/// <summary>
/// Version of TryGetSolution that doesn't take or return an entity.
/// Used for prototypes and with old code parity.
- public bool TryGetSolution(SolutionContainerManagerComponent container, string name, [NotNullWhen(true)] out Solution? solution)
+ public bool TryGetSolution(SolutionContainerManagerComponent container,
+ string name,
+ [NotNullWhen(true)] out Solution? solution,
+ bool errorOnMissing = false)
{
solution = null;
- if (container.Solutions == null)
+ if (container.Solutions != null)
+ return container.Solutions.TryGetValue(name, out solution);
+ if (!errorOnMissing)
return false;
-
- return container.Solutions.TryGetValue(name, out solution);
+ Log.Error($"{container} does not have a solution with ID: {name}");
+ return false;
}
public IEnumerable<(string? Name, Entity<SolutionComponent> Solution)> EnumerateSolutions(Entity<SolutionContainerManagerComponent?> container, bool includeSelf = true)
entity.Comp.Solution.ValidateSolution();
}
- private void OnComponentStartup(Entity<SolutionComponent> entity, ref ComponentStartup args)
+ private void OnSolutionStartup(Entity<SolutionComponent> entity, ref ComponentStartup args)
{
UpdateChemicals(entity);
}
- private void OnComponentShutdown(Entity<SolutionComponent> entity, ref ComponentShutdown args)
+ private void OnSolutionShutdown(Entity<SolutionComponent> entity, ref ComponentShutdown args)
{
RemoveAllSolution(entity);
}
- private void OnComponentInit(Entity<SolutionContainerManagerComponent> entity, ref ComponentInit args)
+ private void OnContainerManagerInit(Entity<SolutionContainerManagerComponent> entity, ref ComponentInit args)
{
if (entity.Comp.Containers is not { Count: > 0 } containers)
return;
return true;
}
+ private void OnMapInit(Entity<SolutionContainerManagerComponent> entity, ref MapInitEvent args)
+ {
+ EnsureAllSolutions(entity);
+ }
+
+ private void OnContainerManagerShutdown(Entity<SolutionContainerManagerComponent> entity, ref ComponentShutdown args)
+ {
+ foreach (var name in entity.Comp.Containers)
+ {
+ if (ContainerSystem.TryGetContainer(entity, $"solution@{name}", out var solutionContainer))
+ ContainerSystem.ShutdownContainer(solutionContainer);
+ }
+ entity.Comp.Containers.Clear();
+ }
+
+ private void OnContainedSolutionShutdown(Entity<ContainedSolutionComponent> entity, ref ComponentShutdown args)
+ {
+ if (TryComp(entity.Comp.Container, out SolutionContainerManagerComponent? container))
+ {
+ container.Containers.Remove(entity.Comp.ContainerName);
+ Dirty(entity.Comp.Container, container);
+ }
+
+ if (ContainerSystem.TryGetContainer(entity, $"solution@{entity.Comp.ContainerName}", out var solutionContainer))
+ ContainerSystem.ShutdownContainer(solutionContainer);
+ }
+
#endregion Event Handlers
+
+ public bool EnsureSolution(
+ Entity<MetaDataComponent?> entity,
+ string name,
+ [NotNullWhen(true)]out Solution? solution,
+ FixedPoint2 maxVol = default)
+ {
+ return EnsureSolution(entity, name, maxVol, null, out _, out solution);
+ }
+
+ public bool EnsureSolution(
+ Entity<MetaDataComponent?> entity,
+ string name,
+ out bool existed,
+ [NotNullWhen(true)]out Solution? solution,
+ FixedPoint2 maxVol = default)
+ {
+ return EnsureSolution(entity, name, maxVol, null, out existed, out solution);
+ }
+
+ public bool EnsureSolution(
+ Entity<MetaDataComponent?> entity,
+ string name,
+ FixedPoint2 maxVol,
+ Solution? prototype,
+ out bool existed,
+ [NotNullWhen(true)] out Solution? solution)
+ {
+ solution = null;
+ existed = false;
+
+ var (uid, meta) = entity;
+ if (!Resolve(uid, ref meta))
+ throw new InvalidOperationException("Attempted to ensure solution on invalid entity.");
+ var manager = EnsureComp<SolutionContainerManagerComponent>(uid);
+ if (meta.EntityLifeStage >= EntityLifeStage.MapInitialized)
+ {
+ EnsureSolutionEntity((uid, manager), name, out existed,
+ out var solEnt, maxVol, prototype);
+ solution = solEnt!.Value.Comp.Solution;
+ return true;
+ }
+ solution = EnsureSolutionPrototype((uid, manager), name, maxVol, prototype, out existed);
+ return true;
+ }
+
+ public void EnsureAllSolutions(Entity<SolutionContainerManagerComponent> entity)
+ {
+ if (NetManager.IsClient)
+ return;
+
+ if (entity.Comp.Solutions is not { } prototypes)
+ return;
+
+ foreach (var (name, prototype) in prototypes)
+ {
+ EnsureSolutionEntity((entity.Owner, entity.Comp), name, out _, out _, prototype.MaxVolume, prototype);
+ }
+
+ entity.Comp.Solutions = null;
+ Dirty(entity);
+ }
+
+ public bool EnsureSolutionEntity(
+ Entity<SolutionContainerManagerComponent?> entity,
+ string name,
+ [NotNullWhen(true)] out Entity<SolutionComponent>? solutionEntity,
+ FixedPoint2 maxVol = default) =>
+ EnsureSolutionEntity(entity, name, out _, out solutionEntity, maxVol);
+
+ public bool EnsureSolutionEntity(
+ Entity<SolutionContainerManagerComponent?> entity,
+ string name,
+ out bool existed,
+ [NotNullWhen(true)] out Entity<SolutionComponent>? solutionEntity,
+ FixedPoint2 maxVol = default,
+ Solution? prototype = null
+ )
+ {
+ existed = true;
+ solutionEntity = null;
+
+ var (uid, container) = entity;
+
+ var solutionSlot = ContainerSystem.EnsureContainer<ContainerSlot>(uid, $"solution@{name}", out existed);
+ if (!Resolve(uid, ref container, logMissing: false))
+ {
+ existed = false;
+ container = AddComp<SolutionContainerManagerComponent>(uid);
+ container.Containers.Add(name);
+ if (NetManager.IsClient)
+ return false;
+ }
+ else if (!existed)
+ {
+ container.Containers.Add(name);
+ Dirty(uid, container);
+ }
+
+ var needsInit = false;
+ SolutionComponent solutionComp;
+ if (solutionSlot.ContainedEntity is not { } solutionId)
+ {
+ if (NetManager.IsClient)
+ return false;
+ prototype ??= new() { MaxVolume = maxVol };
+ prototype.Name = name;
+ (solutionId, solutionComp, _) = SpawnSolutionUninitialized(solutionSlot, name, maxVol, prototype);
+ existed = false;
+ needsInit = true;
+ Dirty(uid, container);
+ }
+ else
+ {
+ solutionComp = Comp<SolutionComponent>(solutionId);
+ DebugTools.Assert(TryComp(solutionId, out ContainedSolutionComponent? relation) && relation.Container == uid && relation.ContainerName == name);
+ DebugTools.Assert(solutionComp.Solution.Name == name);
+
+ var solution = solutionComp.Solution;
+ solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol);
+
+ // Depending on MapInitEvent order some systems can ensure solution empty solutions and conflict with the prototype solutions.
+ // We want the reagents from the prototype to exist even if something else already created the solution.
+ if (prototype is { Volume.Value: > 0 })
+ solution.AddSolution(prototype, PrototypeManager);
+
+ Dirty(solutionId, solutionComp);
+ }
+
+ if (needsInit)
+ EntityManager.InitializeAndStartEntity(solutionId, Transform(solutionId).MapID);
+ solutionEntity = (solutionId, solutionComp);
+ return true;
+ }
+
+ private Solution EnsureSolutionPrototype(Entity<SolutionContainerManagerComponent?> entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed)
+ {
+ existed = true;
+
+ var (uid, container) = entity;
+ if (!Resolve(uid, ref container, logMissing: false))
+ {
+ container = AddComp<SolutionContainerManagerComponent>(uid);
+ existed = false;
+ }
+
+ if (container.Solutions is null)
+ container.Solutions = new(SolutionContainerManagerComponent.DefaultCapacity);
+
+ if (!container.Solutions.TryGetValue(name, out var solution))
+ {
+ solution = prototype ?? new() { Name = name, MaxVolume = maxVol };
+ container.Solutions.Add(name, solution);
+ existed = false;
+ }
+ else
+ solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol);
+
+ Dirty(uid, container);
+ return solution;
+ }
+
+ private Entity<SolutionComponent, ContainedSolutionComponent> SpawnSolutionUninitialized(ContainerSlot container, string name, FixedPoint2 maxVol, Solution prototype)
+ {
+ var coords = new EntityCoordinates(container.Owner, Vector2.Zero);
+ var uid = EntityManager.CreateEntityUninitialized(null, coords, null);
+
+ var solution = new SolutionComponent() { Solution = prototype };
+ AddComp(uid, solution);
+
+ var relation = new ContainedSolutionComponent() { Container = container.Owner, ContainerName = name };
+ AddComp(uid, relation);
+
+ MetaData.SetEntityName(uid, $"solution - {name}");
+ ContainerSystem.Insert(uid, container, force: true);
+
+ return (uid, solution, relation);
+ }
+
+ public void AdjustDissolvedReagent(
+ Entity<SolutionComponent> dissolvedSolution,
+ FixedPoint2 volume,
+ ReagentId reagent,
+ float concentrationChange)
+ {
+ if (concentrationChange == 0)
+ return;
+ var dissolvedSol = dissolvedSolution.Comp.Solution;
+ var amtChange =
+ GetReagentQuantityFromConcentration(dissolvedSolution, volume, MathF.Abs(concentrationChange));
+ if (concentrationChange > 0)
+ {
+ dissolvedSol.AddReagent(reagent, amtChange);
+ }
+ else
+ {
+ dissolvedSol.RemoveReagent(reagent,amtChange);
+ }
+ UpdateChemicals(dissolvedSolution);
+ }
+
+ public FixedPoint2 GetReagentQuantityFromConcentration(Entity<SolutionComponent> dissolvedSolution,
+ FixedPoint2 volume,float concentration)
+ {
+ var dissolvedSol = dissolvedSolution.Comp.Solution;
+ if (volume == 0
+ || dissolvedSol.Volume == 0)
+ return 0;
+ return concentration * volume;
+ }
+
+ public float GetReagentConcentration(Entity<SolutionComponent> dissolvedSolution,
+ FixedPoint2 volume, ReagentId dissolvedReagent)
+ {
+ var dissolvedSol = dissolvedSolution.Comp.Solution;
+ if (volume == 0
+ || dissolvedSol.Volume == 0
+ || !dissolvedSol.TryGetReagentQuantity(dissolvedReagent, out var dissolvedVol))
+ return 0;
+ return (float)dissolvedVol / volume.Float();
+ }
+
+ public FixedPoint2 ClampReagentAmountByConcentration(
+ Entity<SolutionComponent> dissolvedSolution,
+ FixedPoint2 volume,
+ ReagentId dissolvedReagent,
+ FixedPoint2 dissolvedReagentAmount,
+ float maxConcentration = 1f)
+ {
+ var dissolvedSol = dissolvedSolution.Comp.Solution;
+ if (volume == 0
+ || dissolvedSol.Volume == 0
+ || !dissolvedSol.TryGetReagentQuantity(dissolvedReagent, out var dissolvedVol))
+ return 0;
+ volume *= maxConcentration;
+ dissolvedVol += dissolvedReagentAmount;
+ var overflow = volume - dissolvedVol;
+ if (overflow < 0)
+ dissolvedReagentAmount += overflow;
+ return dissolvedReagentAmount;
+ }
}