private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, AtmosDeviceUpdateEvent args)
        {
            if (!pump.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
            {
                _ambientSoundSystem.SetAmbience(pump.Owner, false);
                return;
            }

            var outputStartingPressure = outlet.Air.Pressure;

            if (outputStartingPressure >= pump.TargetPressure)
            {
                _ambientSoundSystem.SetAmbience(pump.Owner, false);
                return; // No need to pump gas if target has been reached.
            }

            if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
            {
                // We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
                var pressureDelta = pump.TargetPressure - outputStartingPressure;
                var transferMoles = (pressureDelta * outlet.Air.Volume) / (inlet.Air.Temperature * Atmospherics.R);

                var removed = inlet.Air.Remove(transferMoles);
                _atmosphereSystem.Merge(outlet.Air, removed);
                _ambientSoundSystem.SetAmbience(pump.Owner, removed.TotalMoles > 0f);
            }
        }
        private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, AtmosDeviceUpdateEvent args)
        {
            var appearance = pump.Owner.GetComponentOrNull <AppearanceComponent>();

            if (!pump.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
            {
                appearance?.SetData(PressurePumpVisuals.Enabled, false);
                return;
            }

            var outputStartingPressure = outlet.Air.Pressure;

            if (MathHelper.CloseToPercent(pump.TargetPressure, outputStartingPressure))
            {
                appearance?.SetData(PressurePumpVisuals.Enabled, false);
                return; // No need to pump gas if target has been reached.
            }

            if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
            {
                appearance?.SetData(PressurePumpVisuals.Enabled, true);

                // We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
                var pressureDelta = pump.TargetPressure - outputStartingPressure;
                var transferMoles = pressureDelta * outlet.Air.Volume / inlet.Air.Temperature * Atmospherics.R;

                var removed = inlet.Air.Remove(transferMoles);
                outlet.AssumeAir(removed);
            }
        }
Пример #3
0
        private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceUpdateEvent args)
        {
            if (!pump.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
            {
                return;
            }

            var inputStartingPressure  = inlet.Air.Pressure;
            var outputStartingPressure = outlet.Air.Pressure;

            // Pump mechanism won't do anything if the pressure is too high/too low unless you overclock it.
            if ((inputStartingPressure < pump.LowerThreshold) || (outputStartingPressure > pump.HigherThreshold) && !pump.Overclocked)
            {
                return;
            }

            // Overclocked pumps can only force gas a certain amount.
            if ((outputStartingPressure - inputStartingPressure > pump.OverclockThreshold) && pump.Overclocked)
            {
                return;
            }

            // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
            var transferRatio = (float)(pump.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inlet.Air.Volume;

            var removed = inlet.Air.RemoveRatio(transferRatio);

            // Some of the gas from the mixture leaks when overclocked.
            if (pump.Overclocked)
            {
                var atmosphereSystem = Get <AtmosphereSystem>();
                var tile             = atmosphereSystem.GetTileMixture(pump.Owner.Transform.Coordinates, true);

                if (tile != null)
                {
                    var leaked = removed.RemoveRatio(pump.LeakRatio);
                    atmosphereSystem.Merge(tile, leaked);
                }
            }

            outlet.AssumeAir(removed);
        }
Пример #4
0
        private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, AtmosDeviceUpdateEvent args)
        {
            var appearance = EntityManager.GetComponentOrNull <AppearanceComponent>(filter.Owner);

            if (!filter.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !EntityManager.TryGetComponent(uid, out AtmosDeviceComponent? device) ||
                !nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode) ||
                !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode) ||
                !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode) ||
                outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure) // No need to transfer if target is full.
            {
                appearance?.SetData(FilterVisuals.Enabled, false);
                _ambientSoundSystem.SetAmbience(filter.Owner, false);
                return;
            }

            // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
            var transferRatio = (float)(filter.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;

            if (transferRatio <= 0)
            {
                appearance?.SetData(FilterVisuals.Enabled, false);
                _ambientSoundSystem.SetAmbience(filter.Owner, false);
                return;
            }

            var removed = inletNode.Air.RemoveRatio(transferRatio);

            if (filter.FilteredGas.HasValue)
            {
                appearance?.SetData(FilterVisuals.Enabled, true);

                var filteredOut = new GasMixture()
                {
                    Temperature = removed.Temperature
                };

                filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value));
                removed.SetMoles(filter.FilteredGas.Value, 0f);

                var target = filterNode.Air.Pressure < Atmospherics.MaxOutputPressure ? filterNode : inletNode;
                _atmosphereSystem.Merge(target.Air, filteredOut);
                if (filteredOut.Pressure != 0f)
                {
                    _ambientSoundSystem.SetAmbience(filter.Owner, true);
                }
                else
                {
                    _ambientSoundSystem.SetAmbience(filter.Owner, false);
                }
            }

            _atmosphereSystem.Merge(outletNode.Air, removed);
        }
        private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, AtmosDeviceUpdateEvent args)
        {
            if (!filter.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode) ||
                !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode) ||
                !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode))
            {
                return;
            }

            if (outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure)
            {
                return; // No need to transfer if target is full.
            }
            // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
            var transferRatio = (float)(filter.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;

            if (transferRatio <= 0)
            {
                return;
            }

            var removed = inletNode.Air.RemoveRatio(transferRatio);

            if (filter.FilteredGas.HasValue)
            {
                var filteredOut = new GasMixture()
                {
                    Temperature = removed.Temperature
                };

                filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value));
                removed.SetMoles(filter.FilteredGas.Value, 0f);

                var target = filterNode.Air.Pressure < Atmospherics.MaxOutputPressure ? filterNode : inletNode;
                target.AssumeAir(filteredOut);
            }

            outletNode.AssumeAir(removed);
        }
        private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceUpdateEvent args)
        {
            if (!pump.Enabled ||
                !TryComp(uid, out NodeContainerComponent? nodeContainer) ||
                !TryComp(uid, out AtmosDeviceComponent? device) ||
                !nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
            {
                _ambientSoundSystem.SetAmbience(uid, false);
                return;
            }

            var inputStartingPressure  = inlet.Air.Pressure;
            var outputStartingPressure = outlet.Air.Pressure;

            // Pump mechanism won't do anything if the pressure is too high/too low unless you overclock it.
            if ((inputStartingPressure < pump.LowerThreshold) || (outputStartingPressure > pump.HigherThreshold) && !pump.Overclocked)
            {
                return;
            }

            // Overclocked pumps can only force gas a certain amount.
            if ((outputStartingPressure - inputStartingPressure > pump.OverclockThreshold) && pump.Overclocked)
            {
                return;
            }

            // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
            var transferRatio = (float)(pump.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inlet.Air.Volume;

            var removed = inlet.Air.RemoveRatio(transferRatio);

            // Some of the gas from the mixture leaks when overclocked.
            if (pump.Overclocked)
            {
                var transform = Transform(uid);
                var indices   = _transformSystem.GetGridOrMapTilePosition(uid, transform);
                var tile      = _atmosphereSystem.GetTileMixture(transform.GridUid, null, indices, true);

                if (tile != null)
                {
                    var leaked = removed.RemoveRatio(pump.LeakRatio);
                    _atmosphereSystem.Merge(tile, leaked);
                }
            }

            _atmosphereSystem.Merge(outlet.Air, removed);
            _ambientSoundSystem.SetAmbience(uid, removed.TotalMoles > 0f);
        }
        private void OnMinerUpdated(EntityUid uid, GasMinerComponent miner, AtmosDeviceUpdateEvent args)
        {
            if (!CheckMinerOperation(args.Atmosphere, miner, out var tile) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f)
            {
                return;
            }

            // Time to mine some gas.

            var merger = new GasMixture(1)
            {
                Temperature = miner.SpawnTemperature
            };

            merger.SetMoles(miner.SpawnGas.Value, miner.SpawnAmount);

            tile.AssumeAir(merger);
        }
Пример #8
0
        private void OnMinerUpdated(EntityUid uid, GasMinerComponent miner, AtmosDeviceUpdateEvent args)
        {
            var atmosphereSystem = Get <AtmosphereSystem>();

            if (!CheckMinerOperation(atmosphereSystem, miner, out var environment) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f)
            {
                return;
            }

            // Time to mine some gas.

            var merger = new GasMixture(1)
            {
                Temperature = miner.SpawnTemperature
            };

            merger.SetMoles(miner.SpawnGas.Value, miner.SpawnAmount);

            atmosphereSystem.Merge(environment, merger);
        }
        private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args)
        {
            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
            {
                return;
            }

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

            DirtyUI(uid);

            // Nothing to do here.
            if (MathHelper.CloseTo(portNode.Air.Pressure, canister.LastPressure))
            {
                return;
            }

            canister.LastPressure = portNode.Air.Pressure;

            if (portNode.Air.Pressure < 10)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 0);
            }
            else if (portNode.Air.Pressure < Atmospherics.OneAtmosphere)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 1);
            }
            else if (portNode.Air.Pressure < (15 * Atmospherics.OneAtmosphere))
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 2);
            }
            else
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 3);
            }
        }
Пример #10
0
        private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args)
        {
            var environment = _atmosphereSystem.GetContainingMixture(uid, true, true);

            if (environment == null)
            {
                return;
            }

            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet))
            {
                return;
            }

            var environmentPressure = environment.Pressure;
            var pressureDelta       = MathF.Abs(environmentPressure - inlet.Air.Pressure);

            if ((environment.Temperature > 0 || inlet.Air.Temperature > 0) && pressureDelta > 0.5f)
            {
                if (environmentPressure < inlet.Air.Pressure)
                {
                    var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature;
                    var transferMoles  = pressureDelta * environment.Volume / (airTemperature * Atmospherics.R);
                    var removed        = inlet.Air.Remove(transferMoles);
                    _atmosphereSystem.Merge(environment, removed);
                }
                else
                {
                    var airTemperature = inlet.Air.Temperature > 0 ? inlet.Air.Temperature : environment.Temperature;
                    var outputVolume   = inlet.Air.Volume;
                    var transferMoles  = (pressureDelta * outputVolume) / (airTemperature * Atmospherics.R);
                    transferMoles = MathF.Min(transferMoles, environment.TotalMoles * inlet.Air.Volume / environment.Volume);
                    var removed = environment.Remove(transferMoles);
                    _atmosphereSystem.Merge(inlet.Air, removed);
                }
            }
        }
        private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args)
        {
            var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates) !;

            if (environment.Air == null)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet))
            {
                return;
            }

            var environmentPressure = environment.Air.Pressure;
            var pressureDelta       = MathF.Abs(environmentPressure - inlet.Air.Pressure);

            if ((environment.Air.Temperature > 0 || inlet.Air.Temperature > 0) && pressureDelta > 0.5f)
            {
                if (environmentPressure < inlet.Air.Pressure)
                {
                    var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature;
                    var transferMoles  = pressureDelta * environment.Air.Volume / (airTemperature * Atmospherics.R);
                    var removed        = inlet.Air.Remove(transferMoles);
                    environment.AssumeAir(removed);
                }
                else
                {
                    var airTemperature = inlet.Air.Temperature > 0 ? inlet.Air.Temperature : environment.Temperature;
                    var outputVolume   = inlet.Air.Volume;
                    var transferMoles  = (pressureDelta * outputVolume) / (airTemperature * Atmospherics.R);
                    transferMoles = MathF.Min(transferMoles, environment.Air.TotalMoles * inlet.Air.Volume / environment.Air.Volume);
                    var removed = environment.Air.Remove(transferMoles);
                    inlet.AssumeAir(removed);
                    environment.Invalidate();
                }
            }
        }
        private void OnGasDualPortVentPumpUpdated(EntityUid uid, GasDualPortVentPumpComponent vent, AtmosDeviceUpdateEvent args)
        {
            var appearance = vent.Owner.GetComponentOrNull <AppearanceComponent>();

            if (vent.Welded)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Welded);
                return;
            }

            if (!vent.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(vent.OutletName, out PipeNode? outlet))
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);

            // We're in an air-blocked tile... Do nothing.
            if (environment == null)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
                return;
            }

            if (vent.PumpDirection == VentPumpDirection.Releasing)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Out);
                var pressureDelta = 10000f;

                if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, (vent.ExternalPressureBound - environment.Pressure));
                }

                if ((vent.PressureChecks & DualPortVentPressureBound.InputMinimum) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, (inlet.Air.Pressure - vent.InputPressureMin));
                }

                if (pressureDelta > 0 && inlet.Air.Temperature > 0)
                {
                    var transferMoles = pressureDelta * environment.Volume / inlet.Air.Temperature * Atmospherics.R;
                    var removed       = inlet.Air.Remove(transferMoles);
                    _atmosphereSystem.Merge(environment, removed);
                }
            }
            else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0f)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.In);
                var ourMultiplier = outlet.Air.Volume / environment.Temperature * Atmospherics.R;
                var molesDelta    = 10000 * ourMultiplier;

                if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0)
                {
                    molesDelta =
                        MathF.Min(molesDelta,
                                  (environment.Pressure - vent.OutputPressureMax) * environment.Volume / (environment.Temperature * Atmospherics.R));
                }

                if ((vent.PressureChecks & DualPortVentPressureBound.InputMinimum) != 0)
                {
                    molesDelta = MathF.Min(molesDelta, (vent.InputPressureMin - outlet.Air.Pressure) * ourMultiplier);
                }

                if (molesDelta > 0)
                {
                    var removed = environment.Remove(molesDelta);

                    _atmosphereSystem.Merge(outlet.Air, removed);
                }
            }
        }
        private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
        {
            if (scrubber.Welded)
            {
                return;
            }

            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

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

            if (!scrubber.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
            {
                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);

            Scrub(timeDelta, scrubber, environment, outlet);

            if (!scrubber.WideNet)
            {
                return;
            }

            // Scrub adjacent tiles too.
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true))
            {
                Scrub(timeDelta, scrubber, adjacent, outlet);
            }
        }
Пример #14
0
        private void OnMixerUpdated(EntityUid uid, GasMixerComponent mixer, AtmosDeviceUpdateEvent args)
        {
            // TODO ATMOS: Cache total moles since it's expensive.

            if (!mixer.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(mixer.InletOneName, out PipeNode? inletOne) ||
                !nodeContainer.TryGetNode(mixer.InletTwoName, out PipeNode? inletTwo) ||
                !nodeContainer.TryGetNode(mixer.OutletName, out PipeNode? outlet))
            {
                return;
            }

            var outputStartingPressure = outlet.Air.Pressure;

            if (outputStartingPressure >= mixer.TargetPressure)
            {
                return; // Target reached, no need to mix.
            }
            var generalTransfer = (mixer.TargetPressure - outputStartingPressure) * outlet.Air.Volume / Atmospherics.R;

            var transferMolesOne = inletOne.Air.Temperature > 0 ? mixer.InletOneConcentration * generalTransfer / inletOne.Air.Temperature : 0f;
            var transferMolesTwo = inletTwo.Air.Temperature > 0 ? mixer.InletTwoConcentration * generalTransfer / inletTwo.Air.Temperature : 0f;

            if (mixer.InletTwoConcentration <= 0f)
            {
                if (inletOne.Air.Temperature <= 0f)
                {
                    return;
                }

                transferMolesOne = MathF.Min(transferMolesOne, inletOne.Air.TotalMoles);
                transferMolesTwo = 0f;
            }

            else if (mixer.InletOneConcentration <= 0)
            {
                if (inletTwo.Air.Temperature <= 0f)
                {
                    return;
                }

                transferMolesOne = 0f;
                transferMolesTwo = MathF.Min(transferMolesTwo, inletTwo.Air.TotalMoles);
            }
            else
            {
                if (inletOne.Air.Temperature <= 0f || inletTwo.Air.Temperature <= 0f)
                {
                    return;
                }

                if (transferMolesOne <= 0 || transferMolesTwo <= 0)
                {
                    return;
                }

                if (inletOne.Air.TotalMoles < transferMolesOne || inletTwo.Air.TotalMoles < transferMolesTwo)
                {
                    var ratio = MathF.Min(inletOne.Air.TotalMoles / transferMolesOne, inletTwo.Air.TotalMoles / transferMolesTwo);
                    transferMolesOne *= ratio;
                    transferMolesTwo *= ratio;
                }
            }

            // Actually transfer the gas now.

            if (transferMolesOne > 0f)
            {
                var removed = inletOne.Air.Remove(transferMolesOne);
                outlet.AssumeAir(removed);
            }

            if (transferMolesTwo > 0f)
            {
                var removed = inletTwo.Air.Remove(transferMolesTwo);
                outlet.AssumeAir(removed);
            }
        }
Пример #15
0
        private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
        {
            var appearance = EntityManager.GetComponentOrNull <AppearanceComponent>(scrubber.Owner);

            if (scrubber.Welded)
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Welded);
                _ambientSoundSystem.SetAmbience(scrubber.Owner, false);
                return;
            }

            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

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

            if (!scrubber.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
                _ambientSoundSystem.SetAmbience(scrubber.Owner, false);
                return;
            }
            _ambientSoundSystem.SetAmbience(scrubber.Owner, true);

            var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(scrubber.Owner).Coordinates, true);

            Scrub(timeDelta, scrubber, appearance, environment, outlet);

            if (!scrubber.WideNet)
            {
                return;
            }

            // Scrub adjacent tiles too.
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(EntityManager.GetComponent <TransformComponent>(scrubber.Owner).Coordinates, false, true))
            {
                Scrub(timeDelta, scrubber, null, adjacent, outlet);
            }
        }
Пример #16
0
        private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args)
        {
            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(canister.PortName, out PortablePipeNode? portNode))
            {
                return;
            }

            var atmosphereSystem = Get <AtmosphereSystem>();

            atmosphereSystem.React(canister.Air, portNode);

            if (portNode.NodeGroup is PipeNet {
                NodeCount: > 1
            } net)
            {
                var buffer = new GasMixture(net.Air.Volume + canister.Air.Volume);

                atmosphereSystem.Merge(buffer, net.Air);
                atmosphereSystem.Merge(buffer, canister.Air);

                net.Air.Clear();
                atmosphereSystem.Merge(net.Air, buffer);
                net.Air.Multiply(net.Air.Volume / buffer.Volume);

                canister.Air.Clear();
                atmosphereSystem.Merge(canister.Air, buffer);
                canister.Air.Multiply(canister.Air.Volume / buffer.Volume);
            }

            // Release valve is open, release gas.
            if (canister.ReleaseValve)
            {
                if (!ComponentManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) ||
                    !containerManager.TryGetContainer(canister.ContainerName, out var container))
                {
                    return;
                }

                if (container.ContainedEntities.Count > 0)
                {
                    var gasTank = container.ContainedEntities[0].GetComponent <GasTankComponent>();
                    atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure);
                }
                else
                {
                    var tileAtmosphere = canister.Owner.Transform.Coordinates.GetTileAtmosphere();
                    atmosphereSystem.ReleaseGasTo(canister.Air, tileAtmosphere?.Air, canister.ReleasePressure);
                    tileAtmosphere?.Invalidate();
                }
            }

            DirtyUI(uid);

            // If last pressure is very close to the current pressure, do nothing.
            if (MathHelper.CloseTo(canister.Air.Pressure, canister.LastPressure))
            {
                return;
            }

            canister.LastPressure = canister.Air.Pressure;

            if (canister.Air.Pressure < 10)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 0);
            }
            else if (canister.Air.Pressure < Atmospherics.OneAtmosphere)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 1);
            }
            else if (canister.Air.Pressure < (15 * Atmospherics.OneAtmosphere))
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 2);
            }
            else
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 3);
            }
        }
Пример #17
0
        private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, AtmosDeviceUpdateEvent args)
        {
            var appearance = thermoMachine.Owner.GetComponentOrNull <AppearanceComponent>();

            appearance?.SetData(ThermoMachineVisuals.Enabled, false);

            if (!thermoMachine.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet))
            {
                return;
            }

            var airHeatCapacity      = _atmosphereSystem.GetHeatCapacity(inlet.Air);
            var combinedHeatCapacity = airHeatCapacity + thermoMachine.HeatCapacity;
            var oldTemperature       = inlet.Air.Temperature;

            if (combinedHeatCapacity > 0)
            {
                appearance?.SetData(ThermoMachineVisuals.Enabled, true);
                var combinedEnergy = thermoMachine.HeatCapacity * thermoMachine.TargetTemperature + airHeatCapacity * inlet.Air.Temperature;
                inlet.Air.Temperature = combinedEnergy / combinedHeatCapacity;
            }

            // TODO ATMOS: Active power usage.
        }
Пример #18
0
        private void OnPassiveGateUpdated(EntityUid uid, GasPassiveGateComponent gate, AtmosDeviceUpdateEvent args)
        {
            if (!gate.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(gate.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(gate.OutletName, out PipeNode? outlet))
            {
                return;
            }

            var outputStartingPressure = outlet.Air.Pressure;
            var inputStartingPressure  = inlet.Air.Pressure;

            if (outputStartingPressure >= MathF.Min(gate.TargetPressure, inputStartingPressure - gate.FrictionPressureDifference))
            {
                return; // No need to pump gas, target reached or input pressure too low.
            }
            if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
            {
                // We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
                var pressureDelta = MathF.Min(gate.TargetPressure - outputStartingPressure, (inputStartingPressure - outputStartingPressure) / 2);
                // We can't have a pressure delta that would cause outlet pressure > inlet pressure.

                var transferMoles = pressureDelta * outlet.Air.Volume / (inlet.Air.Temperature * Atmospherics.R);

                // Actually transfer the gas.
                outlet.AssumeAir(inlet.Air.Remove(transferMoles));
            }
        }
Пример #19
0
        private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
        {
            var appearance = scrubber.Owner.GetComponentOrNull <AppearanceComponent>();

            if (scrubber.Welded)
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Welded);
                return;
            }

            if (!scrubber.Enabled ||
                !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true);

            Scrub(_atmosphereSystem, scrubber, appearance, environment, outlet);

            if (!scrubber.WideNet)
            {
                return;
            }

            // Scrub adjacent tiles too.
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(scrubber.Owner.Transform.Coordinates, false, true))
            {
                Scrub(_atmosphereSystem, scrubber, null, adjacent, outlet);
            }
        }
        private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
        {
            var appearance = scrubber.Owner.GetComponentOrNull <AppearanceComponent>();

            if (scrubber.Welded)
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Welded);
                return;
            }

            appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);

            if (!scrubber.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
            {
                return;
            }

            var environment = args.Atmosphere.GetTile(scrubber.Owner.Transform.Coordinates) !;

            Scrub(scrubber, appearance, environment, outlet);

            if (!scrubber.WideNet)
            {
                return;
            }

            // Scrub adjacent tiles too.
            foreach (var adjacent in environment.AdjacentTiles)
            {
                // Pass null appearance, we don't need to set it there.
                Scrub(scrubber, null, adjacent, outlet);
            }
        }
Пример #21
0
        private void OnGasVentPumpUpdated(EntityUid uid, GasVentPumpComponent vent, AtmosDeviceUpdateEvent args)
        {
            //Bingo waz here
            if (vent.Welded)
            {
                return;
            }

            var nodeName = vent.PumpDirection switch
            {
                VentPumpDirection.Releasing => vent.Inlet,
                VentPumpDirection.Siphoning => vent.Outlet,
                _ => throw new ArgumentOutOfRangeException()
            };

            if (!vent.Enabled ||
                !TryComp(uid, out AtmosDeviceComponent? device) ||
                !TryComp(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(nodeName, out PipeNode? pipe))
            {
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(vent.Owner).Coordinates, true);

            // We're in an air-blocked tile... Do nothing.
            if (environment == null)
            {
                return;
            }

            var timeDelta     = (_gameTiming.CurTime - device.LastProcess).TotalSeconds;
            var pressureDelta = (float)timeDelta * vent.TargetPressureChange;

            if (vent.PumpDirection == VentPumpDirection.Releasing && pipe.Air.Pressure > 0)
            {
                if (environment.Pressure > vent.MaxPressure)
                {
                    return;
                }

                if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Pressure);
                }

                if (pressureDelta <= 0)
                {
                    return;
                }

                // how many moles to transfer to change external pressure by pressureDelta
                // (ignoring temperature differences because I am lazy)
                var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R);

                // limit transferMoles so the source doesn't go below its bound.
                if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
                {
                    var internalDelta = pipe.Air.Pressure - vent.InternalPressureBound;

                    if (internalDelta <= 0)
                    {
                        return;
                    }

                    var maxTransfer = internalDelta * pipe.Air.Volume / (pipe.Air.Temperature * Atmospherics.R);
                    transferMoles = MathF.Min(transferMoles, maxTransfer);
                }

                _atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles));
            }
            else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0)
            {
                if (pipe.Air.Pressure > vent.MaxPressure)
                {
                    return;
                }

                if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, vent.InternalPressureBound - pipe.Air.Pressure);
                }

                if (pressureDelta <= 0)
                {
                    return;
                }

                // how many moles to transfer to change internal pressure by pressureDelta
                // (ignoring temperature differences because I am lazy)
                var transferMoles = pressureDelta * pipe.Air.Volume / (environment.Temperature * Atmospherics.R);

                // limit transferMoles so the source doesn't go below its bound.
                if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
                {
                    var externalDelta = environment.Pressure - vent.ExternalPressureBound;

                    if (externalDelta <= 0)
                    {
                        return;
                    }

                    var maxTransfer = externalDelta * environment.Volume / (environment.Temperature * Atmospherics.R);

                    transferMoles = MathF.Min(transferMoles, maxTransfer);
                }

                _atmosphereSystem.Merge(pipe.Air, environment.Remove(transferMoles));
            }
        }
        private void OnOutletInjectorUpdated(EntityUid uid, GasOutletInjectorComponent injector, AtmosDeviceUpdateEvent args)
        {
            injector.Injecting = false;

            if (!injector.Enabled)
            {
                return;
            }

            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
            {
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(injector.Owner).Coordinates, true);

            if (environment == null)
            {
                return;
            }

            if (inlet.Air.Temperature < 0)
            {
                return;
            }

            var timeDelta = (float)(_gameTiming.CurTime - device.LastProcess).TotalSeconds;
            var ratio     = MathF.Min(1f, timeDelta * injector.TransferRate / inlet.Air.Volume);
            var removed   = inlet.Air.RemoveRatio(ratio);

            _atmosphereSystem.Merge(environment, removed);
        }
        private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args)
        {
            _atmosphereSystem.React(canister.Air, canister);

            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(canister.PortName, out PortablePipeNode? portNode))
            {
                return;
            }

            if (portNode.NodeGroup is PipeNet {
                NodeCount: > 1
            } net)
            {
                MixContainerWithPipeNet(canister.Air, net.Air);
            }

            ContainerManagerComponent?containerManager = null;

            // Release valve is open, release gas.
            if (canister.ReleaseValve)
            {
                if (!EntityManager.TryGetComponent(uid, out containerManager) ||
                    !containerManager.TryGetContainer(canister.ContainerName, out var container))
                {
                    return;
                }

                if (container.ContainedEntities.Count > 0)
                {
                    var gasTank = EntityManager.GetComponent <GasTankComponent>(container.ContainedEntities[0]);
                    _atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure);
                }
                else
                {
                    var environment = _atmosphereSystem.GetContainingMixture(uid, false, true);
                    _atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure);
                }
            }

            // If last pressure is very close to the current pressure, do nothing.
            if (MathHelper.CloseToPercent(canister.Air.Pressure, canister.LastPressure))
            {
                return;
            }

            DirtyUI(uid, canister, nodeContainer, containerManager);

            canister.LastPressure = canister.Air.Pressure;

            if (canister.Air.Pressure < 10)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 0);
            }
            else if (canister.Air.Pressure < Atmospherics.OneAtmosphere)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 1);
            }
            else if (canister.Air.Pressure < (15 * Atmospherics.OneAtmosphere))
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 2);
            }
            else
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 3);
            }
        }
Пример #24
0
        private void OnOutletInjectorUpdated(EntityUid uid, GasOutletInjectorComponent injector, AtmosDeviceUpdateEvent args)
        {
            if (!injector.Enabled)
            {
                return;
            }

            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
            {
                return;
            }

            var environment = _atmosphereSystem.GetContainingMixture(uid, true, true);

            if (environment == null)
            {
                return;
            }

            if (inlet.Air.Temperature < 0)
            {
                return;
            }

            if (environment.Pressure > injector.MaxPressure)
            {
                return;
            }

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

            // TODO adjust ratio so that environment does not go above MaxPressure?
            var ratio   = MathF.Min(1f, timeDelta * injector.TransferRate / inlet.Air.Volume);
            var removed = inlet.Air.RemoveRatio(ratio);

            _atmosphereSystem.Merge(environment, removed);
        }
Пример #25
0
        private void OnOutletInjectorUpdated(EntityUid uid, GasOutletInjectorComponent injector, AtmosDeviceUpdateEvent args)
        {
            injector.Injecting = false;

            if (!injector.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
            {
                return;
            }

            var atmosphereSystem = Get <AtmosphereSystem>();
            var environment      = atmosphereSystem.GetTileMixture(injector.Owner.Transform.Coordinates, true);

            if (environment == null)
            {
                return;
            }

            if (inlet.Air.Temperature > 0)
            {
                var transferMoles = inlet.Air.Pressure * injector.VolumeRate / (inlet.Air.Temperature * Atmospherics.R);

                var removed = inlet.Air.Remove(transferMoles);

                atmosphereSystem.Merge(environment, removed);
            }
        }
        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);
            }
        }
Пример #27
0
        private void OnGasVentPumpUpdated(EntityUid uid, GasVentPumpComponent vent, AtmosDeviceUpdateEvent args)
        {
            var appearance = vent.Owner.GetComponentOrNull <AppearanceComponent>();

            if (vent.Welded)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Welded);
                return;
            }

            appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);

            if (!vent.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe))
            {
                return;
            }

            var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates) !;

            // We're in an air-blocked tile... Do nothing.
            if (environment.Air == null)
            {
                return;
            }

            if (vent.PumpDirection == VentPumpDirection.Releasing)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Out);
                var pressureDelta = 10000f;

                if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Air.Pressure);
                }

                if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, pipe.Air.Pressure - vent.InternalPressureBound);
                }

                if (pressureDelta > 0 && pipe.Air.Temperature > 0)
                {
                    var transferMoles = pressureDelta * environment.Air.Volume / (pipe.Air.Temperature * Atmospherics.R);

                    environment.AssumeAir(pipe.Air.Remove(transferMoles));
                }
            }
            else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Air.Pressure > 0)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.In);
                var ourMultiplier = pipe.Air.Volume / (environment.Air.Temperature * Atmospherics.R);
                var molesDelta    = 10000f * ourMultiplier;

                if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
                {
                    molesDelta = MathF.Min(molesDelta,
                                           (environment.Air.Pressure - vent.ExternalPressureBound) * environment.Air.Volume /
                                           (environment.Air.Temperature * Atmospherics.R));
                }

                if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
                {
                    molesDelta = MathF.Min(molesDelta, (vent.InternalPressureBound - pipe.Air.Pressure) * ourMultiplier);
                }

                if (molesDelta > 0)
                {
                    var removed = environment.Air.Remove(molesDelta);
                    pipe.AssumeAir(removed);
                    environment.Invalidate();
                }
            }
        }
Пример #28
0
        private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args)
        {
            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
            {
                return;
            }

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

            // Release valve is open, release gas.
            if (canister.ReleaseValve)
            {
                if (!ComponentManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) ||
                    !containerManager.TryGetContainer(canister.ContainerName, out var container))
                {
                    return;
                }

                var atmosphereSystem = Get <AtmosphereSystem>();

                if (container.ContainedEntities.Count > 0)
                {
                    var gasTank = container.ContainedEntities[0].GetComponent <GasTankComponent>();
                    atmosphereSystem.ReleaseGasTo(portNode.Air, gasTank.Air, canister.ReleasePressure);
                }
                else
                {
                    var tileAtmosphere = canister.Owner.Transform.Coordinates.GetTileAtmosphere();
                    atmosphereSystem.ReleaseGasTo(portNode.Air, tileAtmosphere?.Air, canister.ReleasePressure);
                    tileAtmosphere?.Invalidate();
                }
            }

            DirtyUI(uid);

            // Nothing to do here.
            if (MathHelper.CloseTo(portNode.Air.Pressure, canister.LastPressure))
            {
                return;
            }

            canister.LastPressure = portNode.Air.Pressure;

            if (portNode.Air.Pressure < 10)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 0);
            }
            else if (portNode.Air.Pressure < Atmospherics.OneAtmosphere)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 1);
            }
            else if (portNode.Air.Pressure < (15 * Atmospherics.OneAtmosphere))
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 2);
            }
            else
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 3);
            }
        }