private void Scrub(float timeDelta, GasVentScrubberComponent scrubber, GasMixture?tile, PipeNode outlet) { // Cannot scrub if tile is null or air-blocked. if (tile == null || outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere) // Cannot scrub if pressure too high. { return; } // Take a gas sample. var ratio = MathF.Min(1f, timeDelta * scrubber.TransferRate / tile.Volume); var removed = tile.RemoveRatio(ratio); // Nothing left to remove from the tile. if (MathHelper.CloseToPercent(removed.TotalMoles, 0f)) { return; } if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing) { _atmosphereSystem.ScrubInto(removed, outlet.Air, scrubber.FilterGases); // Remix the gases. _atmosphereSystem.Merge(tile, removed); } else if (scrubber.PumpDirection == ScrubberPumpDirection.Siphoning) { _atmosphereSystem.Merge(outlet.Air, removed); } }
public void PumpToxins(EntityUid uid, GasMixture to, BloodstreamComponent?blood = null, RespiratorComponent?respiration = null) { if (!Resolve(uid, ref blood)) { return; } if (!Resolve(uid, ref respiration, false)) { _atmosSystem.Merge(to, blood.Air); blood.Air.Clear(); return; } var toxins = _respiratorSystem.Clean(uid, respiration, blood); var toOld = new float[to.Moles.Length]; Array.Copy(to.Moles, toOld, toOld.Length); _atmosSystem.Merge(to, toxins); for (var i = 0; i < toOld.Length; i++) { var newAmount = to.GetMoles(i); var oldAmount = toOld[i]; var delta = newAmount - oldAmount; toxins.AdjustMoles(i, -delta); } _atmosSystem.Merge(blood.Air, toxins); }
/// <summary> /// True if we were able to scrub, false if we were not. /// </summary> public bool Scrub(float timeDelta, float transferRate, ScrubberPumpDirection mode, HashSet <Gas> filterGases, GasMixture?tile, GasMixture destination) { // Cannot scrub if tile is null or air-blocked. if (tile == null || destination.Pressure >= 50 * Atmospherics.OneAtmosphere) // Cannot scrub if pressure too high. { return(false); } // Take a gas sample. var ratio = MathF.Min(1f, timeDelta * transferRate / tile.Volume); var removed = tile.RemoveRatio(ratio); // Nothing left to remove from the tile. if (MathHelper.CloseToPercent(removed.TotalMoles, 0f)) { return(false); } if (mode == ScrubberPumpDirection.Scrubbing) { _atmosphereSystem.ScrubInto(removed, destination, filterGases); // Remix the gases. _atmosphereSystem.Merge(tile, removed); } else if (mode == ScrubberPumpDirection.Siphoning) { _atmosphereSystem.Merge(destination, removed); } return(true); }
/// <summary> /// Inhales directly from a given mixture. /// </summary> public void TakeGasFrom(EntityUid uid, float frameTime, GasMixture from, LungComponent?lung = null, MechanismComponent?mech = null) { if (!Resolve(uid, ref lung, ref mech)) { return; } var ratio = (Atmospherics.BreathVolume / from.Volume) * frameTime; _atmosSys.Merge(lung.Air, from.RemoveRatio(ratio)); // Push to bloodstream if (mech.Body == null) { return; } if (!EntityManager.TryGetComponent((mech.Body).Owner, out BloodstreamComponent? bloodstream)) { return; } var to = bloodstream.Air; _atmosSys.Merge(to, lung.Air); lung.Air.Clear(); }
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 OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceUpdateEvent args) { TryComp(uid, out AppearanceComponent? appearance); 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)) { appearance?.SetData(PumpVisuals.Enabled, false); _ambientSoundSystem.SetAmbience(pump.Owner, false); _ambientSoundSystem.SetAmbience(pump.Owner, 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; } appearance?.SetData(PumpVisuals.Enabled, true); _ambientSoundSystem.SetAmbience(pump.Owner, true); // 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 tile = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(pump.Owner).Coordinates, true); if (tile != null) { var leaked = removed.RemoveRatio(pump.LeakRatio); _atmosphereSystem.Merge(tile, leaked); } } _atmosphereSystem.Merge(outlet.Air, removed); }
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 = EntityManager.GetComponentOrNull <AppearanceComponent>(pump.Owner); 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(PumpVisuals.Enabled, false); return; } var outputStartingPressure = outlet.Air.Pressure; if (MathHelper.CloseToPercent(pump.TargetPressure, outputStartingPressure)) { appearance?.SetData(PumpVisuals.Enabled, false); return; // No need to pump gas if target has been reached. } if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0) { appearance?.SetData(PumpVisuals.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); _atmosphereSystem.Merge(outlet.Air, removed); } }
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 (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet)) { return; } 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 OnActivate(EntityUid uid, GasArtifactComponent component, ArtifactActivatedEvent args) { if (component.SpawnGas == null || component.SpawnTemperature == null) { return; } var transform = Transform(uid); var environment = _atmosphereSystem.GetContainingMixture(uid, false, true); if (environment == null) { return; } if (environment.Pressure >= component.MaxExternalPressure) { return; } var merger = new GasMixture(1) { Temperature = component.SpawnTemperature.Value }; merger.SetMoles(component.SpawnGas.Value, component.SpawnAmount); _atmosphereSystem.Merge(environment, merger); }
/// <summary> /// Completely dumps the content of the canister into the world. /// </summary> public void PurgeContents(EntityUid uid, GasCanisterComponent?canister = null, TransformComponent?transform = null) { if (!Resolve(uid, ref canister, ref transform)) { return; } var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates, true); if (environment is not null) { _atmosphereSystem.Merge(environment, canister.Air); } _adminLogSystem.Add(LogType.CanisterPurged, LogImpact.Medium, $"Canister {uid} purged its contents of {canister.Air} into the environment."); canister.Air.Clear(); }
/// <summary> /// Completely dumps the content of the canister into the world. /// </summary> public void PurgeContents(EntityUid uid, GasCanisterComponent?canister = null, TransformComponent?transform = null) { if (!Resolve(uid, ref canister, ref transform)) { return; } var environment = _atmosphereSystem.GetContainingMixture(uid, false, true); if (environment is not null) { _atmosphereSystem.Merge(environment, canister.Air); } _adminLogger.Add(LogType.CanisterPurged, LogImpact.Medium, $"Canister {ToPrettyString(uid):canister} purged its contents of {canister.Air:gas} into the environment."); canister.Air.Clear(); }
private void OnBeforeUnanchored(EntityUid uid, AtmosUnsafeUnanchorComponent component, BeforeUnanchoredEvent args) { if (!component.Enabled || !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodes)) { return; } if (_atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(component.Owner).Coordinates, true) is not { } environment) { environment = GasMixture.SpaceGas; } var lost = 0f; var timesLost = 0; foreach (var node in nodes.Nodes.Values) { if (node is not PipeNode pipe) { continue; } var difference = pipe.Air.Pressure - environment.Pressure; lost += difference * environment.Volume / (environment.Temperature * Atmospherics.R); timesLost++; } var sharedLoss = lost / timesLost; var buffer = new GasMixture(); foreach (var node in nodes.Nodes.Values) { if (node is not PipeNode pipe) { continue; } _atmosphereSystem.Merge(buffer, pipe.Air.Remove(sharedLoss)); } _atmosphereSystem.Merge(environment, buffer); }
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); } } }
/// <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(); }
public void Inhale(EntityUid uid, SharedBodyComponent?body = null) { if (!Resolve(uid, ref body, false)) { return; } var organs = _bodySystem.GetComponentsOnMechanisms <LungComponent>(uid, body); // Inhale gas var ev = new InhaleLocationEvent(); RaiseLocalEvent(uid, ev, false); if (ev.Gas == null) { ev.Gas = _atmosSys.GetContainingMixture(uid, false, true); if (ev.Gas == null) { return; } } var ratio = (Atmospherics.BreathVolume / ev.Gas.Volume); var actualGas = ev.Gas.RemoveRatio(ratio); var lungRatio = 1.0f / organs.Count; var gas = organs.Count == 1 ? actualGas : actualGas.RemoveRatio(lungRatio); foreach (var(lung, _) in organs) { // Merge doesn't remove gas from the giver. _atmosSys.Merge(lung.Air, gas); _lungSystem.GasToReagent(lung.Owner, lung); } }
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.GetTileMixture(EntityManager.GetComponent <TransformComponent>(injector.Owner).Coordinates, 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); }
private void OnMinerUpdated(EntityUid uid, GasMinerComponent miner, AtmosDeviceUpdateEvent args) { if (!CheckMinerOperation(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 Scrub(AtmosphereSystem atmosphereSystem, GasVentScrubberComponent scrubber, AppearanceComponent?appearance, GasMixture?tile, PipeNode outlet) { // Cannot scrub if tile is null or air-blocked. if (tile == null) { return; } // Cannot scrub if pressure too high. if (outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere) { return; } if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing) { appearance?.SetData(ScrubberVisuals.State, scrubber.WideNet ? ScrubberState.WideScrub : ScrubberState.Scrub); var transferMoles = MathF.Min(1f, (scrubber.VolumeRate / tile.Volume) * tile.TotalMoles); // Take a gas sample. var removed = tile.Remove(transferMoles); // Nothing left to remove from the tile. if (MathHelper.CloseTo(removed.TotalMoles, 0f)) { return; } atmosphereSystem.ScrubInto(removed, outlet.Air, scrubber.FilterGases); // Remix the gases. atmosphereSystem.Merge(tile, removed); } else if (scrubber.PumpDirection == ScrubberPumpDirection.Siphoning) { appearance?.SetData(ScrubberVisuals.State, ScrubberState.Siphon); var transferMoles = tile.TotalMoles * (scrubber.VolumeRate / tile.Volume); var removed = tile.Remove(transferMoles); outlet.AssumeAir(removed); } }
private void OnPassiveGateUpdated(EntityUid uid, GasPassiveGateComponent gate, AtmosDeviceUpdateEvent args) { if (!gate.Enabled) { return; } if (!EntityManager.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. _atmosphereSystem.Merge(outlet.Air, inlet.Air.Remove(transferMoles)); } }
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 OnMixerUpdated(EntityUid uid, GasMixerComponent mixer, AtmosDeviceUpdateEvent args) { // TODO ATMOS: Cache total moles since it's expensive. if (!mixer.Enabled) { return; } if (!EntityManager.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); _atmosphereSystem.Merge(outlet.Air, removed); } if (transferMolesTwo > 0f) { var removed = inletTwo.Air.Remove(transferMolesTwo); _atmosphereSystem.Merge(outlet.Air, removed); } }
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 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; } _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 environment = _atmosphereSystem.GetTileMixture(canister.Owner.Transform.Coordinates, true); _atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure); } } 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); } }
public void ExitDisposals(EntityUid uid, DisposalHolderComponent?holder = null, TransformComponent?holderTransform = null) { if (!Resolve(uid, ref holder, ref holderTransform)) { return; } if (holder.IsExitingDisposals) { Logger.ErrorS("c.s.disposal.holder", "Tried exiting disposals twice. This should never happen."); return; } holder.IsExitingDisposals = true; // Check for a disposal unit to throw them into and then eject them from it. // *This ejection also makes the target not collide with the unit.* // *This is on purpose.* DisposalUnitComponent?duc = null; if (_mapManager.TryGetGrid(holderTransform.GridUid, out var grid)) { foreach (var contentUid in grid.GetLocal(holderTransform.Coordinates)) { if (EntityManager.TryGetComponent(contentUid, out duc)) { break; } } } foreach (var entity in holder.Container.ContainedEntities.ToArray()) { RemComp <BeingDisposedComponent>(entity); if (EntityManager.TryGetComponent(entity, out IPhysBody? physics)) { physics.CanCollide = true; } var meta = MetaData(entity); holder.Container.ForceRemove(entity, EntityManager, meta); var xform = Transform(entity); if (xform.ParentUid != uid) { continue; } if (duc != null) { duc.Container.Insert(entity, EntityManager, xform, meta: meta); } else { xform.AttachParentToContainerOrGrid(EntityManager); } } if (duc != null) { _disposalUnitSystem.TryEjectContents(duc); } if (_atmosphereSystem.GetTileMixture(holderTransform.Coordinates, true) is {} environment) { _atmosphereSystem.Merge(environment, holder.Air); holder.Air.Clear(); } EntityManager.DeleteEntity(uid); }