private void OnDeviceUpdated(EntityUid uid, PortableScrubberComponent component, AtmosDeviceUpdateEvent args)
        {
            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            var timeDelta = (float)(_gameTiming.CurTime - device.LastProcess).TotalSeconds;

            if (!component.Enabled)
            {
                return;
            }

            /// If we are on top of a connector port, empty into it.
            if (TryComp <NodeContainerComponent>(uid, out var nodeContainer) &&
                nodeContainer.TryGetNode(component.PortName, out PortablePipeNode? portableNode) &&
                portableNode.ConnectionsEnabled)
            {
                _atmosphereSystem.React(component.Air, portableNode);
                if (portableNode.NodeGroup is PipeNet {
                    NodeCount : > 1
                } net)
                {
                    _canisterSystem.MixContainerWithPipeNet(component.Air, net.Air);
                }
            }

            if (component.Full)
            {
                UpdateAppearance(uid, true, false);
                return;
            }

            var xform = Transform(uid);

            if (xform.GridUid == null)
            {
                return;
            }

            var position = _transformSystem.GetGridOrMapTilePosition(uid, xform);

            var environment = _atmosphereSystem.GetTileMixture(xform.GridUid, xform.MapUid, position, true);

            var running = Scrub(timeDelta, component, environment);

            UpdateAppearance(uid, false, running);
            /// We scrub once to see if we can and set the animation
            if (!running)
            {
                return;
            }
            /// widenet
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true))
            {
                Scrub(timeDelta, component, environment);
            }
        }
 /// <summary>
 /// Examining tells you how full it is as a %.
 /// </summary>
 private void OnExamined(EntityUid uid, PortableScrubberComponent component, ExaminedEvent args)
 {
     if (args.IsInDetailsRange)
     {
         var percentage = Math.Round(((component.Air.Pressure) / component.MaxPressure) * 100);
         args.PushMarkup(Loc.GetString("portable-scrubber-fill-level", ("percent", percentage)));
     }
 }
        /// <summary>
        /// When this is destroyed, we dump out all the gas inside.
        /// </summary>
        private void OnDestroyed(EntityUid uid, PortableScrubberComponent component, DestructionEventArgs args)
        {
            var environment = _atmosphereSystem.GetContainingMixture(uid, false, true);

            if (environment != null)
            {
                _atmosphereSystem.Merge(environment, component.Air);
            }

            _adminLogger.Add(LogType.CanisterPurged, LogImpact.Medium, $"Portable scrubber {ToPrettyString(uid):canister} purged its contents of {component.Air:gas} into the environment.");
            component.Air.Clear();
        }
        /// <summary>
        /// If there is a port under us, let us connect with adjacent atmos pipes.
        /// </summary>
        private void OnAnchorChanged(EntityUid uid, PortableScrubberComponent component, ref AnchorStateChangedEvent args)
        {
            if (!TryComp(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(component.PortName, out PipeNode? portableNode))
            {
                return;
            }

            portableNode.ConnectionsEnabled = (args.Anchored && _gasPortableSystem.FindGasPortIn(Transform(uid).GridUid, Transform(uid).Coordinates, out _));

            UpdateDrainingAppearance(uid, portableNode.ConnectionsEnabled);
        }
 private bool Scrub(float timeDelta, PortableScrubberComponent scrubber, GasMixture?tile)
 {
     return(_scrubberSystem.Scrub(timeDelta, scrubber.TransferRate, ScrubberPumpDirection.Scrubbing, scrubber.FilterGases, tile, scrubber.Air));
 }
 private void OnPowerChanged(EntityUid uid, PortableScrubberComponent component, PowerChangedEvent args)
 {
     UpdateAppearance(uid, component.Full, args.Powered);
     component.Enabled = args.Powered;
 }