using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.Reaction; using Content.Shared.FixedPoint; namespace Content.Shared.Chemistry.EntitySystems; #region Events /// /// This event alerts system that the solution was changed /// [ByRefEvent] public record struct SolutionContainerChangedEvent { public readonly Solution Solution; public readonly string SolutionId; public SolutionContainerChangedEvent(Solution solution, string solutionId) { SolutionId = solutionId; Solution = solution; } } /// /// An event raised when more reagents are added to a (managed) solution than it can hold. /// [ByRefEvent] public record struct SolutionContainerOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow) { /// The entity which contains the solution that has overflowed. public readonly EntityUid SolutionEnt = SolutionEnt; /// The solution that has overflowed. public readonly Solution SolutionHolder = SolutionHolder; /// The reagents that have overflowed the solution. public readonly Solution Overflow = Overflow; /// The volume by which the solution has overflowed. public readonly FixedPoint2 OverflowVol = Overflow.Volume; /// Whether some subscriber has taken care of the effects of the overflow. public bool Handled = false; } /// /// Ref event used to relay events raised on solution entities to their containers. /// /// /// The event that is being relayed. /// The container entity that the event is being relayed to. /// The name of the solution entity that the event is being relayed from. [ByRefEvent] public record struct SolutionRelayEvent(TEvent Event, EntityUid ContainerEnt, string Name) { public readonly EntityUid ContainerEnt = ContainerEnt; public readonly string Name = Name; public TEvent Event = Event; } /// /// Ref event used to relay events raised on solution containers to their contained solutions. /// /// /// The event that is being relayed. /// The solution entity that the event is being relayed to. /// The name of the solution entity that the event is being relayed to. [ByRefEvent] public record struct SolutionContainerRelayEvent(TEvent Event, Entity SolutionEnt, string Name) { public readonly Entity SolutionEnt = SolutionEnt; public readonly string Name = Name; public TEvent Event = Event; } #endregion Events public abstract partial class SharedSolutionContainerSystem { protected void InitializeRelays() { SubscribeLocalEvent(OnSolutionChanged); SubscribeLocalEvent(OnSolutionOverflow); SubscribeLocalEvent(RelaySolutionRefEvent); } #region Event Handlers protected virtual void OnSolutionChanged(Entity entity, ref SolutionChangedEvent args) { var (solutionId, solutionComp) = args.Solution; var solution = solutionComp.Solution; UpdateAppearance(entity.Comp.Container, (solutionId, solutionComp, entity.Comp)); var relayEvent = new SolutionContainerChangedEvent(solution, entity.Comp.ContainerName); RaiseLocalEvent(entity.Comp.Container, ref relayEvent); } protected virtual void OnSolutionOverflow(Entity entity, ref SolutionOverflowEvent args) { var solution = args.Solution.Comp.Solution; var overflow = solution.SplitSolution(args.Overflow); var relayEv = new SolutionContainerOverflowEvent(entity.Owner, solution, overflow) { Handled = args.Handled, }; RaiseLocalEvent(entity.Comp.Container, ref relayEv); args.Handled = relayEv.Handled; } #region Relay Event Handlers private void RelaySolutionValEvent(EntityUid uid, ContainedSolutionComponent comp, TEvent @event) { var relayEvent = new SolutionRelayEvent(@event, uid, comp.ContainerName); RaiseLocalEvent(comp.Container, ref relayEvent); } private void RelaySolutionRefEvent(Entity entity, ref TEvent @event) { var relayEvent = new SolutionRelayEvent(@event, entity.Owner, entity.Comp.ContainerName); RaiseLocalEvent(entity.Comp.Container, ref relayEvent); @event = relayEvent.Event; } private void RelaySolutionContainerEvent(EntityUid uid, SolutionContainerManagerComponent comp, TEvent @event) { foreach (var (name, soln) in EnumerateSolutions((uid, comp))) { var relayEvent = new SolutionContainerRelayEvent(@event, soln, name!); RaiseLocalEvent(soln, ref relayEvent); } } private void RelaySolutionContainerEvent(Entity entity, ref TEvent @event) { foreach (var (name, soln) in EnumerateSolutions((entity.Owner, entity.Comp))) { var relayEvent = new SolutionContainerRelayEvent(@event, soln, name!); RaiseLocalEvent(soln, ref relayEvent); @event = relayEvent.Event; } } #endregion Relay Event Handlers #endregion Event Handlers }