]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Atmos device performance improvements (#26493)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Sat, 30 Mar 2024 04:17:53 +0000 (17:17 +1300)
committerGitHub <noreply@github.com>
Sat, 30 Mar 2024 04:17:53 +0000 (15:17 +1100)
* Atmos device performance improvements

* AtmosDirection perf improvements

* Fix errors

* Add GasTileOverlayComponent arguments

* Make excite no longer invalidate a tile

51 files changed:
Content.Server/Atmos/EntitySystems/AirFilterSystem.cs
Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
Content.Server/Atmos/EntitySystems/GasTankSystem.cs
Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs
Content.Server/Atmos/EntitySystems/HeatExchangerSystem.cs
Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs
Content.Server/Atmos/Piping/Binary/EntitySystems/GasPassiveGateSystem.cs
Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
Content.Server/Atmos/Piping/Binary/EntitySystems/GasRecyclerSystem.cs
Content.Server/Atmos/Piping/Binary/EntitySystems/GasValveSystem.cs
Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs
Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs
Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs
Content.Server/Atmos/Piping/Trinary/EntitySystems/PressureControlledValveSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
Content.Server/Atmos/Portable/PortableScrubberSystem.cs
Content.Server/Atmos/Portable/SpaceHeaterSystem.cs
Content.Server/Electrocution/ElectrocutionNode.cs
Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs
Content.Server/Explosion/EntitySystems/ExplosionSpaceTileFlood.cs
Content.Server/Mech/Systems/MechSystem.cs
Content.Server/Medical/CryoPodSystem.cs
Content.Server/NodeContainer/EntitySystems/NodeContainerSystem.cs
Content.Server/PneumaticCannon/PneumaticCannonSystem.cs
Content.Server/Power/Components/CableVisComponent.cs
Content.Server/Power/EntitySystems/CableVisSystem.cs
Content.Server/Power/Generator/GasPowerReceiverSystem.cs
Content.Server/Spreader/SpreaderSystem.cs
Content.Shared/Atmos/AtmosDirection.cs
Content.Shared/Tools/Systems/WeldableSystem.cs
Resources/Prototypes/Entities/Virtual/electrocution.yml

index d947e60b6dad38fd565a1eaeacc5e42b8623fb79..2ab15cfb174322dad8f0fc71f19d2d075e0dd5c2 100644 (file)
@@ -13,6 +13,7 @@ public sealed class AirFilterSystem : EntitySystem
 {
     [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
     [Dependency] private readonly IMapManager _map = default!;
+    [Dependency] private readonly SharedTransformSystem _transform = default!;
 
     public override void Initialize()
     {
@@ -31,7 +32,7 @@ public sealed class AirFilterSystem : EntitySystem
         if (air.Pressure >= intake.Pressure)
             return;
 
-        var environment = _atmosphere.GetContainingMixture(uid, true, true);
+        var environment = _atmosphere.GetContainingMixture(uid, args.Grid, args.Map, true, true);
         // nothing to intake from
         if (environment == null)
             return;
@@ -63,12 +64,11 @@ public sealed class AirFilterSystem : EntitySystem
         var oxygen = air.GetMoles(filter.Oxygen) / air.TotalMoles;
         var gases = oxygen >= filter.TargetOxygen ? filter.Gases : filter.OverflowGases;
 
-        var coordinates = Transform(uid).MapPosition;
         GasMixture? destination = null;
-        if (_map.TryFindGridAt(coordinates, out _, out var grid))
+        if (args.Grid is {} grid)
         {
-            var tile = grid.GetTileRef(coordinates);
-            destination = _atmosphere.GetTileMixture(tile.GridUid, null, tile.GridIndices, true);
+            var position = _transform.GetGridTilePositionOrDefault(uid);
+            destination = _atmosphere.GetTileMixture(grid, args.Map, position, true);
         }
 
         if (destination != null)
index 4be4d8271f37b9dd15afd8fa03a7ddf6bbc3efde..9590b9aa5486ed095ccfe64cf79c46e1da685088 100644 (file)
@@ -24,6 +24,8 @@ namespace Content.Server.Atmos.EntitySystems
 
     /// <summary>
     ///     Event that tries to query the mixture a certain entity is exposed to.
+    ///     This is mainly intended for use with entities inside of containers.
+    ///     This event is not raised for entities that are directly parented to the grid.
     /// </summary>
     [ByRefEvent]
     public struct AtmosExposedGetAirEvent
@@ -31,7 +33,7 @@ namespace Content.Server.Atmos.EntitySystems
         /// <summary>
         ///     The entity we want to query this for.
         /// </summary>
-        public readonly EntityUid Entity;
+        public readonly Entity<TransformComponent> Entity;
 
         /// <summary>
         ///     The mixture that the entity is exposed to. Output parameter.
@@ -39,9 +41,9 @@ namespace Content.Server.Atmos.EntitySystems
         public GasMixture? Gas = null;
 
         /// <summary>
-        ///     Whether to invalidate the mixture, if possible.
+        ///     Whether to excite the mixture, if possible.
         /// </summary>
-        public bool Invalidate = false;
+        public readonly bool Excite = false;
 
         /// <summary>
         ///     Whether this event has been handled or not.
@@ -49,10 +51,10 @@ namespace Content.Server.Atmos.EntitySystems
         /// </summary>
         public bool Handled = false;
 
-        public AtmosExposedGetAirEvent(EntityUid entity, bool invalidate = false)
+        public AtmosExposedGetAirEvent(Entity<TransformComponent> entity, bool excite = false)
         {
             Entity = entity;
-            Invalidate = invalidate;
+            Excite = excite;
         }
     }
 }
index fb94fe414b0864b8ec08285a6e55f034e26723a5..614d550c2f71b2595fcc48632897f63b8bbd3f91 100644 (file)
@@ -4,6 +4,7 @@ using Content.Server.Atmos.Piping.Components;
 using Content.Server.Atmos.Reactions;
 using Content.Server.NodeContainer.NodeGroups;
 using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
 using Robust.Shared.Map.Components;
 using Robust.Shared.Utility;
 
@@ -11,41 +12,39 @@ namespace Content.Server.Atmos.EntitySystems;
 
 public partial class AtmosphereSystem
 {
-    public GasMixture? GetContainingMixture(EntityUid uid, bool ignoreExposed = false, bool excite = false, TransformComponent? transform = null)
+    public GasMixture? GetContainingMixture(Entity<TransformComponent?> ent, bool ignoreExposed = false, bool excite = false)
     {
-        if (!ignoreExposed)
-        {
-            // Used for things like disposals/cryo to change which air people are exposed to.
-            var ev = new AtmosExposedGetAirEvent(uid, excite);
-
-            // Give the entity itself a chance to handle this.
-            RaiseLocalEvent(uid, ref ev, false);
-
-            if (ev.Handled)
-                return ev.Gas;
+        if (!Resolve(ent, ref ent.Comp))
+            return null;
 
-            // We need to get the parent now, so we need the transform... If the parent is invalid, we can't do much else.
-            if(!Resolve(uid, ref transform) || !transform.ParentUid.IsValid() || transform.MapUid == null)
-                return GetTileMixture(null, null, Vector2i.Zero, excite);
+        return GetContainingMixture(ent, ent.Comp.GridUid, ent.Comp.MapUid, ignoreExposed, excite);
+    }
 
-            // Give the parent entity a chance to handle the event...
-            RaiseLocalEvent(transform.ParentUid, ref ev, false);
+    public GasMixture? GetContainingMixture(
+        Entity<TransformComponent?> ent,
+        Entity<GridAtmosphereComponent?, GasTileOverlayComponent?>? grid,
+        Entity<MapAtmosphereComponent?>? map,
+        bool ignoreExposed = false,
+        bool excite = false)
+    {
+        if (!Resolve(ent, ref ent.Comp))
+            return null;
 
+        if (!ignoreExposed && !ent.Comp.Anchored)
+        {
+            // Used for things like disposals/cryo to change which air people are exposed to.
+            var ev = new AtmosExposedGetAirEvent((ent, ent.Comp), excite);
+            RaiseLocalEvent(ent, ref ev);
             if (ev.Handled)
                 return ev.Gas;
-        }
-        // Oops, we did a little bit of code duplication...
-        else if(!Resolve(uid, ref transform))
-        {
-            return GetTileMixture(null, null, Vector2i.Zero, excite);
-        }
 
+            // TODO ATMOS: recursively iterate up through parents
+            // This really needs recursive InContainer metadata flag for performance
+            // And ideally some fast way to get the innermost airtight container.
+        }
 
-        var gridUid = transform.GridUid;
-        var mapUid = transform.MapUid;
-        var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
-
-        return GetTileMixture(gridUid, mapUid, position, excite);
+        var position = _transformSystem.GetGridTilePositionOrDefault((ent, ent.Comp));
+        return GetTileMixture(grid, map, position, excite);
     }
 
     public bool HasAtmosphere(EntityUid gridUid) => _atmosQuery.HasComponent(gridUid);
@@ -84,21 +83,28 @@ public partial class AtmosphereSystem
             entity.Comp.InvalidatedCoords.Add(tile);
     }
 
-    public GasMixture?[]? GetTileMixtures(Entity<GridAtmosphereComponent?>? grid, Entity<MapAtmosphereComponent?>? map, List<Vector2i> tiles, bool excite = false)
+    public GasMixture?[]? GetTileMixtures(
+        Entity<GridAtmosphereComponent?, GasTileOverlayComponent?>? grid,
+        Entity<MapAtmosphereComponent?>? map,
+        List<Vector2i> tiles,
+        bool excite = false)
     {
         GasMixture?[]? mixtures = null;
         var handled = false;
 
         // If we've been passed a grid, try to let it handle it.
-        if (grid is {} gridEnt && Resolve(gridEnt, ref gridEnt.Comp))
+        if (grid is {} gridEnt && Resolve(gridEnt, ref gridEnt.Comp1))
         {
+            if (excite)
+                Resolve(gridEnt, ref gridEnt.Comp2);
+
             handled = true;
             mixtures = new GasMixture?[tiles.Count];
 
             for (var i = 0; i < tiles.Count; i++)
             {
                 var tile = tiles[i];
-                if (!gridEnt.Comp.Tiles.TryGetValue(tile, out var atmosTile))
+                if (!gridEnt.Comp1.Tiles.TryGetValue(tile, out var atmosTile))
                 {
                     // need to get map atmosphere
                     handled = false;
@@ -108,7 +114,10 @@ public partial class AtmosphereSystem
                 mixtures[i] = atmosTile.Air;
 
                 if (excite)
-                    gridEnt.Comp.InvalidatedCoords.Add(tile);
+                {
+                    AddActiveTile(gridEnt.Comp1, atmosTile);
+                    InvalidateVisuals((gridEnt.Owner, gridEnt.Comp2), tile);
+                }
             }
         }
 
@@ -146,15 +155,22 @@ public partial class AtmosphereSystem
         return GetTileMixture(entity.Comp.GridUid, entity.Comp.MapUid, indices, excite);
     }
 
-    public GasMixture? GetTileMixture(Entity<GridAtmosphereComponent?>? grid, Entity<MapAtmosphereComponent?>? map, Vector2i gridTile, bool excite = false)
+    public GasMixture? GetTileMixture(
+        Entity<GridAtmosphereComponent?, GasTileOverlayComponent?>? grid,
+        Entity<MapAtmosphereComponent?>? map,
+        Vector2i gridTile,
+        bool excite = false)
     {
         // If we've been passed a grid, try to let it handle it.
         if (grid is {} gridEnt
-            && Resolve(gridEnt, ref gridEnt.Comp, false)
-            && gridEnt.Comp.Tiles.TryGetValue(gridTile, out var tile))
+            && Resolve(gridEnt, ref gridEnt.Comp1, false)
+            && gridEnt.Comp1.Tiles.TryGetValue(gridTile, out var tile))
         {
             if (excite)
-                gridEnt.Comp.InvalidatedCoords.Add(gridTile);
+            {
+                AddActiveTile(gridEnt.Comp1, tile);
+                InvalidateVisuals((grid.Value.Owner, grid.Value.Comp2), gridTile);
+            }
 
             return tile.Air;
         }
index de4c9199cf72ccd5ef273b9f89664ed404c9c47e..c1b58f7a7728eb390f6fd6614ffd6ebeb72fc488 100644 (file)
@@ -1,5 +1,7 @@
 using Content.Server.Atmos.Components;
 using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
+using Robust.Shared.Map.Components;
 using Robust.Shared.Utility;
 
 namespace Content.Server.Atmos.EntitySystems
@@ -64,10 +66,12 @@ namespace Content.Server.Atmos.EntitySystems
             excitedGroup.DismantleCooldown = 0;
         }
 
-        private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup)
+        private void ExcitedGroupSelfBreakdown(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+            ExcitedGroup excitedGroup)
         {
             DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
-            DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!");
+            DebugTools.Assert(ent.Comp1.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!");
             var combined = new GasMixture(Atmospherics.CellVolume);
 
             var tileSize = excitedGroup.Tiles.Count;
@@ -77,7 +81,7 @@ namespace Content.Server.Atmos.EntitySystems
 
             if (tileSize == 0)
             {
-                ExcitedGroupDispose(gridAtmosphere, excitedGroup);
+                ExcitedGroupDispose(ent.Comp1, excitedGroup);
                 return;
             }
 
@@ -103,7 +107,7 @@ namespace Content.Server.Atmos.EntitySystems
                     continue;
 
                 tile.Air.CopyFromMutable(combined);
-                InvalidateVisuals(tile.GridIndex, tile.GridIndices);
+                InvalidateVisuals(ent, tile);
             }
 
             excitedGroup.BreakdownCooldown = 0;
index bd45030896ffb2aa167ced8293c0f4ea228a002b..4b9ef49a406fe5e0ac404ce4de699053f38ed9cb 100644 (file)
@@ -1,4 +1,3 @@
-using System.Linq;
 using Content.Server.Atmos.Components;
 using Content.Server.Atmos.Reactions;
 using Content.Shared.Atmos;
@@ -160,7 +159,7 @@ public sealed partial class AtmosphereSystem
     }
 
     /// <summary>
-    /// Update array of adjacent tiles and the adjacency flags. Optionally activates all tiles with modified adjacencies.
+    /// Update array of adjacent tiles and the adjacency flags.
     /// </summary>
     private void UpdateAdjacentTiles(
         Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
@@ -195,14 +194,16 @@ public sealed partial class AtmosphereSystem
             if (activate)
                 AddActiveTile(atmos, adjacent);
 
-            var oppositeDirection = direction.GetOpposite();
+            var oppositeIndex = i.ToOppositeIndex();
+            var oppositeDirection = (AtmosDirection) (1 << oppositeIndex);
+
             if (adjBlockDirs.IsFlagSet(oppositeDirection) || blockedDirs.IsFlagSet(direction))
             {
                 // Adjacency is blocked by some airtight entity.
                 tile.AdjacentBits &= ~direction;
                 adjacent.AdjacentBits &= ~oppositeDirection;
                 tile.AdjacentTiles[i] = null;
-                adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = null;
+                adjacent.AdjacentTiles[oppositeIndex] = null;
             }
             else
             {
@@ -210,7 +211,7 @@ public sealed partial class AtmosphereSystem
                 tile.AdjacentBits |= direction;
                 adjacent.AdjacentBits |= oppositeDirection;
                 tile.AdjacentTiles[i] = adjacent;
-                adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = tile;
+                adjacent.AdjacentTiles[oppositeIndex] = tile;
             }
 
             DebugTools.Assert(!(tile.AdjacentBits.IsFlagSet(direction) ^
index 713d1c4682c538a0504abf292c102575fde3f96c..7163b4cd44c33c9463bc9822767ca3c5c404e4d7 100644 (file)
@@ -1,10 +1,12 @@
 using Content.Server.Atmos.Components;
 using Content.Server.Atmos.Reactions;
 using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
 using Content.Shared.Audio;
 using Content.Shared.Database;
 using Robust.Shared.Audio;
 using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
 using Robust.Shared.Player;
 
 namespace Content.Server.Atmos.EntitySystems
@@ -18,18 +20,18 @@ namespace Content.Server.Atmos.EntitySystems
         [ViewVariables(VVAccess.ReadWrite)]
         public string? HotspotSound { get; private set; } = "/Audio/Effects/fire.ogg";
 
-        private void ProcessHotspot(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
+        private void ProcessHotspot(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+            TileAtmosphere tile)
         {
+            var gridAtmosphere = ent.Comp1;
             if (!tile.Hotspot.Valid)
             {
                 gridAtmosphere.HotspotTiles.Remove(tile);
                 return;
             }
 
-            if (!tile.Excited)
-            {
-                AddActiveTile(gridAtmosphere, tile);
-            }
+            AddActiveTile(gridAtmosphere, tile);
 
             if (!tile.Hotspot.SkippedFirstProcess)
             {
@@ -44,7 +46,7 @@ namespace Content.Server.Atmos.EntitySystems
                 || tile.Air == null || tile.Air.GetMoles(Gas.Oxygen) < 0.5f || (tile.Air.GetMoles(Gas.Plasma) < 0.5f && tile.Air.GetMoles(Gas.Tritium) < 0.5f))
             {
                 tile.Hotspot = new Hotspot();
-                InvalidateVisuals(tile.GridIndex, tile.GridIndices);
+                InvalidateVisuals(ent, tile);
                 return;
             }
 
index c27e18b55b0013c0c32ad0c99bf5016f4e590bf5..fb2375899d9dbb0dda25b03b4c1cf7ad154f4dd5 100644 (file)
@@ -1,14 +1,18 @@
 using Content.Server.Atmos.Components;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Components;
+using Robust.Shared.Map.Components;
 using Robust.Shared.Utility;
 
 namespace Content.Server.Atmos.EntitySystems
 {
     public sealed partial class AtmosphereSystem
     {
-        private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, GasTileOverlayComponent visuals)
+        private void ProcessCell(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+            TileAtmosphere tile, int fireCount)
         {
+            var gridAtmosphere = ent.Comp1;
             // Can't process a tile without air
             if (tile.Air == null)
             {
@@ -52,11 +56,7 @@ namespace Content.Server.Atmos.EntitySystems
                     shouldShareAir = true;
                 } else if (CompareExchange(tile.Air, enemyTile.Air) != GasCompareResult.NoExchange)
                 {
-                    if (!enemyTile.Excited)
-                    {
-                        AddActiveTile(gridAtmosphere, enemyTile);
-                    }
-
+                    AddActiveTile(gridAtmosphere, enemyTile);
                     if (ExcitedGroups)
                     {
                         var excitedGroup = tile.ExcitedGroup;
@@ -91,7 +91,7 @@ namespace Content.Server.Atmos.EntitySystems
                         }
                         else
                         {
-                            ConsiderPressureDifference(gridAtmosphere, enemyTile, direction.GetOpposite(), -difference);
+                            ConsiderPressureDifference(gridAtmosphere, enemyTile, i.ToOppositeDir(), -difference);
                         }
                     }
 
@@ -102,7 +102,7 @@ namespace Content.Server.Atmos.EntitySystems
             if(tile.Air != null)
                 React(tile.Air, tile);
 
-            InvalidateVisuals(tile.GridIndex, tile.GridIndices, visuals);
+            InvalidateVisuals(ent, tile);
 
             var remove = true;
 
@@ -146,7 +146,7 @@ namespace Content.Server.Atmos.EntitySystems
         /// <param name="tile">Tile Atmosphere to be activated.</param>
         private void AddActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
         {
-            if (tile.Air == null)
+            if (tile.Air == null || tile.Excited)
                 return;
 
             tile.Excited = true;
index dcbc1e86ee20f403427c59575fa0a7a62622f040..08193027d67bf2ec41ee2756ada35e5f99913cc3 100644 (file)
@@ -230,7 +230,7 @@ namespace Content.Server.Atmos.EntitySystems
                             if (otherTile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
                             _equalizeQueue[queueLength++] = otherTile2;
                             otherTile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
-                            otherTile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
+                            otherTile2.MonstermosInfo.CurrentTransferDirection = k.ToOppositeDir();
                             otherTile2.MonstermosInfo.CurrentTransferAmount = 0;
                             if (otherTile2.MonstermosInfo.MoleDelta < 0)
                             {
@@ -296,7 +296,7 @@ namespace Content.Server.Atmos.EntitySystems
                             if (otherTile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
                             _equalizeQueue[queueLength++] = otherTile2;
                             otherTile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
-                            otherTile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
+                            otherTile2.MonstermosInfo.CurrentTransferDirection = k.ToOppositeDir();
                             otherTile2.MonstermosInfo.CurrentTransferAmount = 0;
 
                             if (otherTile2.MonstermosInfo.MoleDelta > 0)
@@ -338,7 +338,7 @@ namespace Content.Server.Atmos.EntitySystems
             for (var i = 0; i < tileCount; i++)
             {
                 var otherTile = _equalizeTiles[i]!;
-                FinalizeEq(gridAtmosphere, otherTile, ent);
+                FinalizeEq(ent, otherTile);
             }
 
             for (var i = 0; i < tileCount; i++)
@@ -473,7 +473,7 @@ namespace Content.Server.Atmos.EntitySystems
                     if(tile2.Space)
                         continue;
 
-                    tile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
+                    tile2.MonstermosInfo.CurrentTransferDirection = j.ToOppositeDir();
                     tile2.MonstermosInfo.CurrentTransferAmount = 0.0f;
                     tile2.PressureSpecificTarget = otherTile.PressureSpecificTarget;
                     tile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
@@ -549,7 +549,7 @@ namespace Content.Server.Atmos.EntitySystems
                     otherTile.Air.Temperature = Atmospherics.TCMB;
                 }
 
-                InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices, visuals);
+                InvalidateVisuals(ent, otherTile);
                 HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.MonstermosInfo.CurrentTransferAmount);
             }
 
@@ -598,11 +598,13 @@ namespace Content.Server.Atmos.EntitySystems
 
             UpdateAdjacentTiles(ent, tile);
             UpdateAdjacentTiles(ent, other);
-            InvalidateVisuals(tile.GridIndex, tile.GridIndices, ent);
-            InvalidateVisuals(other.GridIndex, other.GridIndices, ent);
+            InvalidateVisuals(ent, tile);
+            InvalidateVisuals(ent, other);
         }
 
-        private void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, GasTileOverlayComponent? visuals)
+        private void FinalizeEq(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+            TileAtmosphere tile)
         {
             Span<float> transferDirections = stackalloc float[Atmospherics.Directions];
             var hasTransferDirs = false;
@@ -629,17 +631,19 @@ namespace Content.Server.Atmos.EntitySystems
 
                 // Everything that calls this method already ensures that Air will not be null.
                 if (tile.Air!.TotalMoles < amount)
-                    FinalizeEqNeighbors(gridAtmosphere, tile, transferDirections, visuals);
+                    FinalizeEqNeighbors(ent, tile, transferDirections);
 
-                otherTile.MonstermosInfo[direction.GetOpposite()] = 0;
+                otherTile.MonstermosInfo[i.ToOppositeDir()] = 0;
                 Merge(otherTile.Air, tile.Air.Remove(amount));
-                InvalidateVisuals(tile.GridIndex, tile.GridIndices, visuals);
-                InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices, visuals);
-                ConsiderPressureDifference(gridAtmosphere, tile, direction, amount);
+                InvalidateVisuals(ent, tile);
+                InvalidateVisuals(ent, otherTile);
+                ConsiderPressureDifference(ent, tile, direction, amount);
             }
         }
 
-        private void FinalizeEqNeighbors(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, ReadOnlySpan<float> transferDirs, GasTileOverlayComponent? visuals)
+        private void FinalizeEqNeighbors(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+            TileAtmosphere tile, ReadOnlySpan<float> transferDirs)
         {
             for (var i = 0; i < Atmospherics.Directions; i++)
             {
@@ -647,7 +651,7 @@ namespace Content.Server.Atmos.EntitySystems
                 var amount = transferDirs[i];
                 // Since AdjacentBits is set, AdjacentTiles[i] wouldn't be null, and neither would its air.
                 if(amount < 0 && tile.AdjacentBits.IsFlagSet(direction))
-                    FinalizeEq(gridAtmosphere, tile.AdjacentTiles[i]!, visuals);  // A bit of recursion if needed.
+                    FinalizeEq(ent, tile.AdjacentTiles[i]!);  // A bit of recursion if needed.
             }
         }
 
@@ -664,7 +668,9 @@ namespace Content.Server.Atmos.EntitySystems
                 Log.Error($"Encountered null-tile in {nameof(AdjustEqMovement)}. Trace: {Environment.StackTrace}");
                 return;
             }
-            var adj = tile.AdjacentTiles[direction.ToIndex()];
+
+            var idx = direction.ToIndex();
+            var adj = tile.AdjacentTiles[idx];
             if (adj == null)
             {
                 var nonNull = tile.AdjacentTiles.Where(x => x != null).Count();
@@ -673,7 +679,7 @@ namespace Content.Server.Atmos.EntitySystems
             }
 
             tile.MonstermosInfo[direction] += amount;
-            adj.MonstermosInfo[direction.GetOpposite()] -= amount;
+            adj.MonstermosInfo[idx.ToOppositeDir()] -= amount;
         }
 
         private void HandleDecompressionFloorRip(MapGridComponent mapGrid, TileAtmosphere tile, float sum)
index eba398c182104a62744b7012efb9aa8ff0a12702..bd023e8574a4de7bfc5625b589d72e82f3118886 100644 (file)
@@ -86,7 +86,7 @@ namespace Content.Server.Atmos.EntitySystems
                 DebugTools.Assert(atmosphere.Tiles.GetValueOrDefault(tile.GridIndices) == tile);
                 UpdateAdjacentTiles(ent, tile, activate: true);
                 UpdateTileAir(ent, tile, volume);
-                InvalidateVisuals(uid, tile.GridIndices, visuals);
+                InvalidateVisuals(ent, tile);
 
                 if (number++ < InvalidCoordinatesLagCheckIterations)
                     continue;
@@ -313,15 +313,17 @@ namespace Content.Server.Atmos.EntitySystems
             return true;
         }
 
-        private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere, GasTileOverlayComponent visuals)
+        private bool ProcessActiveTiles(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent)
         {
+            var atmosphere = ent.Comp1;
             if(!atmosphere.ProcessingPaused)
                 QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles);
 
             var number = 0;
             while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
             {
-                ProcessCell(atmosphere, tile, atmosphere.UpdateCounter, visuals);
+                ProcessCell(ent, tile, atmosphere.UpdateCounter);
 
                 if (number++ < LagCheckIterations)
                     continue;
@@ -337,8 +339,10 @@ namespace Content.Server.Atmos.EntitySystems
             return true;
         }
 
-        private bool ProcessExcitedGroups(GridAtmosphereComponent gridAtmosphere)
+        private bool ProcessExcitedGroups(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent)
         {
+            var gridAtmosphere = ent.Comp1;
             if (!gridAtmosphere.ProcessingPaused)
             {
                 gridAtmosphere.CurrentRunExcitedGroups.Clear();
@@ -356,7 +360,7 @@ namespace Content.Server.Atmos.EntitySystems
                 excitedGroup.DismantleCooldown++;
 
                 if (excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles)
-                    ExcitedGroupSelfBreakdown(gridAtmosphere, excitedGroup);
+                    ExcitedGroupSelfBreakdown(ent, excitedGroup);
                 else if (excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles)
                     DeactivateGroupTiles(gridAtmosphere, excitedGroup);
                 // TODO ATMOS. What is the point of this? why is this only de-exciting the group? Shouldn't it also dismantle it?
@@ -411,15 +415,17 @@ namespace Content.Server.Atmos.EntitySystems
             return true;
         }
 
-        private bool ProcessHotspots(GridAtmosphereComponent atmosphere)
+        private bool ProcessHotspots(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent)
         {
+            var atmosphere = ent.Comp1;
             if(!atmosphere.ProcessingPaused)
                 QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.HotspotTiles);
 
             var number = 0;
             while (atmosphere.CurrentRunTiles.TryDequeue(out var hotspot))
             {
-                ProcessHotspot(atmosphere, hotspot);
+                ProcessHotspot(ent, hotspot);
 
                 if (number++ < LagCheckIterations)
                     continue;
@@ -507,8 +513,11 @@ namespace Content.Server.Atmos.EntitySystems
             return num * AtmosTime;
         }
 
-        private bool ProcessAtmosDevices(GridAtmosphereComponent atmosphere)
+        private bool ProcessAtmosDevices(
+            Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+            Entity<MapAtmosphereComponent?> map)
         {
+            var atmosphere = ent.Comp1;
             if (!atmosphere.ProcessingPaused)
             {
                 atmosphere.CurrentRunAtmosDevices.Clear();
@@ -521,7 +530,7 @@ namespace Content.Server.Atmos.EntitySystems
 
             var time = _gameTiming.CurTime;
             var number = 0;
-            var ev = new AtmosDeviceUpdateEvent(RealAtmosTime());
+            var ev = new AtmosDeviceUpdateEvent(RealAtmosTime(), (ent, ent.Comp1, ent.Comp2), map);
             while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device))
             {
                 RaiseLocalEvent(device, ref ev);
@@ -565,12 +574,11 @@ namespace Content.Server.Atmos.EntitySystems
                 var ent = _currentRunAtmosphere[_currentRunAtmosphereIndex];
                 var (owner, atmosphere, visuals, grid, xform) = ent;
 
-                if (!TryComp(owner, out TransformComponent? x)
-                    || x.MapUid == null
-                    || TerminatingOrDeleted(x.MapUid.Value)
-                    || x.MapID == MapId.Nullspace)
+                if (xform.MapUid == null
+                    || TerminatingOrDeleted(xform.MapUid.Value)
+                    || xform.MapID == MapId.Nullspace)
                 {
-                    Log.Error($"Attempted to process atmos without a map? Entity: {ToPrettyString(owner)}. Map: {ToPrettyString(x?.MapUid)}. MapId: {x?.MapID}");
+                    Log.Error($"Attempted to process atmos without a map? Entity: {ToPrettyString(owner)}. Map: {ToPrettyString(xform?.MapUid)}. MapId: {xform?.MapID}");
                     continue;
                 }
 
@@ -585,6 +593,8 @@ namespace Content.Server.Atmos.EntitySystems
                 // We subtract it so it takes lost time into account.
                 atmosphere.Timer -= AtmosTime;
 
+                var map = new Entity<MapAtmosphereComponent?>(xform.MapUid.Value, _mapAtmosQuery.CompOrNull(xform.MapUid.Value));
+
                 switch (atmosphere.State)
                 {
                     case AtmosphereProcessingState.Revalidate:
@@ -614,7 +624,7 @@ namespace Content.Server.Atmos.EntitySystems
                         atmosphere.State = AtmosphereProcessingState.ActiveTiles;
                         continue;
                     case AtmosphereProcessingState.ActiveTiles:
-                        if (!ProcessActiveTiles(ent, ent))
+                        if (!ProcessActiveTiles(ent))
                         {
                             atmosphere.ProcessingPaused = true;
                             return;
@@ -625,7 +635,7 @@ namespace Content.Server.Atmos.EntitySystems
                         atmosphere.State = ExcitedGroups ? AtmosphereProcessingState.ExcitedGroups : AtmosphereProcessingState.HighPressureDelta;
                         continue;
                     case AtmosphereProcessingState.ExcitedGroups:
-                        if (!ProcessExcitedGroups(atmosphere))
+                        if (!ProcessExcitedGroups(ent))
                         {
                             atmosphere.ProcessingPaused = true;
                             return;
@@ -645,7 +655,7 @@ namespace Content.Server.Atmos.EntitySystems
                         atmosphere.State = AtmosphereProcessingState.Hotspots;
                         continue;
                     case AtmosphereProcessingState.Hotspots:
-                        if (!ProcessHotspots(atmosphere))
+                        if (!ProcessHotspots(ent))
                         {
                             atmosphere.ProcessingPaused = true;
                             return;
@@ -680,7 +690,7 @@ namespace Content.Server.Atmos.EntitySystems
                         atmosphere.State = AtmosphereProcessingState.AtmosDevices;
                         continue;
                     case AtmosphereProcessingState.AtmosDevices:
-                        if (!ProcessAtmosDevices(atmosphere))
+                        if (!ProcessAtmosDevices(ent, map))
                         {
                             atmosphere.ProcessingPaused = true;
                             return;
index 5c73cf112466d86bfb4b25a7b2a443676cc774d4..8ed92a9d0eb26b19b721371e98a4db07bad790ec 100644 (file)
@@ -16,7 +16,7 @@ namespace Content.Server.Atmos.EntitySystems
                 if (!directions.IsFlagSet(direction))
                     continue;
 
-                var adjacent = tile.AdjacentTiles[direction.ToIndex()];
+                var adjacent = tile.AdjacentTiles[i];
 
                 // TODO ATMOS handle adjacent being null.
                 if (adjacent == null || adjacent.ThermalConductivity == 0f)
index 67c6d5998dd544962a83e1457c9a85ec27e646b9..cf4c73aa2f4c9e9c02a22450ed004a2b38cde11c 100644 (file)
@@ -36,9 +36,17 @@ public partial class AtmosphereSystem
     }
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public void InvalidateVisuals(EntityUid gridUid, Vector2i tile, GasTileOverlayComponent? comp = null)
+    public void InvalidateVisuals(Entity<GasTileOverlayComponent?> grid, Vector2i tile)
     {
-        _gasTileOverlaySystem.Invalidate(gridUid, tile, comp);
+        _gasTileOverlaySystem.Invalidate(grid, tile);
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    private void InvalidateVisuals(
+        Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+        TileAtmosphere tile)
+    {
+        _gasTileOverlaySystem.Invalidate((ent.Owner, ent.Comp2), tile.GridIndices);
     }
 
     /// <summary>
index a553766582716bbab2aac5b67eb2618fe9fea14c..44bfa4cc10c7518d1aab7286c0606e60b24a0378 100644 (file)
@@ -96,7 +96,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
         var query = EntityQueryEnumerator<AtmosExposedComponent, TransformComponent>();
         while (query.MoveNext(out var uid, out _, out var transform))
         {
-            var air = GetContainingMixture(uid, transform:transform);
+            var air = GetContainingMixture((uid, transform));
 
             if (air == null)
                 continue;
index aed00432e1f5d1e1ec6692d12f4a1a73e651d2d5..80842416e8bd7943d5ff1c6e3aee4f93e0437e32 100644 (file)
@@ -168,7 +168,7 @@ namespace Content.Server.Atmos.EntitySystems
         private void ReleaseGas(Entity<GasTankComponent> gasTank)
         {
             var removed = RemoveAirVolume(gasTank, gasTank.Comp.ValveOutputRate * TimerDelay);
-            var environment = _atmosphereSystem.GetContainingMixture(gasTank, false, true);
+            var environment = _atmosphereSystem.GetContainingMixture(gasTank.Owner, false, true);
             if (environment != null)
             {
                 _atmosphereSystem.Merge(environment, removed);
index 003eed59e0360de6f150c60cbe5089f01447dfb5..c42cfd08da3dd05fbbdcc39c53bf80c7de627225 100644 (file)
@@ -60,6 +60,7 @@ namespace Content.Server.Atmos.EntitySystems
         private float _updateInterval;
 
         private int _thresholds;
+        private EntityQuery<GasTileOverlayComponent> _query;
 
         public override void Initialize()
         {
@@ -84,6 +85,7 @@ namespace Content.Server.Atmos.EntitySystems
 
             SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
             SubscribeLocalEvent<GasTileOverlayComponent, ComponentStartup>(OnStartup);
+            _query = GetEntityQuery<GasTileOverlayComponent>();
         }
 
         private void OnStartup(EntityUid uid, GasTileOverlayComponent component, ComponentStartup args)
@@ -132,10 +134,10 @@ namespace Content.Server.Atmos.EntitySystems
         private void UpdateThresholds(int value) => _thresholds = value;
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public void Invalidate(EntityUid grid, Vector2i index, GasTileOverlayComponent? comp = null)
+        public void Invalidate(Entity<GasTileOverlayComponent?> grid, Vector2i index)
         {
-            if (Resolve(grid, ref comp))
-                comp.InvalidTiles.Add(index);
+            if (_query.Resolve(grid.Owner, ref grid.Comp))
+                grid.Comp.InvalidTiles.Add(index);
         }
 
         private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
index 286b154e96fa43625bf51bd9134fe314d18622a5..b3644e88b73a0d5364b9bf0591c81fffa49f6db1 100644 (file)
@@ -40,24 +40,16 @@ public sealed class HeatExchangerSystem : EntitySystem
 
     private void OnAtmosUpdate(EntityUid uid, HeatExchangerComponent comp, ref AtmosDeviceUpdateEvent args)
     {
-        if (!TryComp(uid, out NodeContainerComponent? nodeContainer)
-                || !TryComp(uid, out AtmosDeviceComponent? device)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.InletName, out PipeNode? inlet)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.OutletName, out PipeNode? outlet))
+        // make sure that the tile the device is on isn't blocked by a wall or something similar.
+        if (args.Grid is {} grid
+            && _transform.TryGetGridTilePosition(uid, out var tile)
+            && _atmosphereSystem.IsTileAirBlocked(grid, tile))
         {
             return;
         }
 
-        // make sure that the tile the device is on isn't blocked by a wall or something similar.
-        var xform = Transform(uid);
-        if (_transform.TryGetGridTilePosition(uid, out var tile))
-        {
-            // TryGetGridTilePosition() already returns false if GridUid is null, but the null checker isn't smart enough yet
-            if (xform.GridUid != null && _atmosphereSystem.IsTileAirBlocked(xform.GridUid.Value, tile))
-            {
-                return;
-            }
-        }
+        if (!_nodeContainer.TryGetNodes(uid, comp.InletName, comp.OutletName, out PipeNode? inlet, out PipeNode? outlet))
+            return;
 
         var dt = args.dt;
 
index 28a0a01c99af13e84586bbe3824896af703f5d06..c1a5256fdd5bb51f0e649db1c3e3e318f19ab167 100644 (file)
@@ -204,11 +204,7 @@ public sealed class AtmosMonitorSystem : EntitySystem
         if (!this.IsPowered(uid, EntityManager))
             return;
 
-        // can't hurt
-        // (in case something is making AtmosDeviceUpdateEvents
-        // outside the typical device loop)
-        if (!TryComp<AtmosDeviceComponent>(uid, out var atmosDeviceComponent)
-            || atmosDeviceComponent.JoinedGrid == null)
+        if (args.Grid  == null)
             return;
 
         // if we're not monitoring atmos, don't bother
index 77bab4775ce3c9db29a778c895440de081dcc7c0..fced4d79884a4f6fe324b9a4c43bf79a33b18fc7 100644 (file)
@@ -26,11 +26,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
 
         private void OnPassiveGateUpdated(EntityUid uid, GasPassiveGateComponent gate, ref AtmosDeviceUpdateEvent args)
         {
-            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
-                return;
-
-            if (!_nodeContainer.TryGetNode(nodeContainer, gate.InletName, out PipeNode? inlet)
-                || !_nodeContainer.TryGetNode(nodeContainer, gate.OutletName, out PipeNode? outlet))
+            if (!_nodeContainer.TryGetNodes(uid, gate.InletName, gate.OutletName, out PipeNode? inlet, out PipeNode? outlet))
                 return;
 
             var n1 = inlet.Air.TotalMoles;
index 49b69fc6739ab4306e413bf8e3ac2de74520969b..af25d04df922c06c62b3687a18a2a55fa62aacda 100644 (file)
@@ -66,9 +66,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
         private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceUpdateEvent args)
         {
             if (!pump.Enabled
-                || !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
-                || !_nodeContainer.TryGetNode(nodeContainer, pump.InletName, out PipeNode? inlet)
-                || !_nodeContainer.TryGetNode(nodeContainer, pump.OutletName, out PipeNode? outlet))
+                || !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet))
             {
                 _ambientSoundSystem.SetAmbience(uid, false);
                 return;
index e14069b8a766bc4762a92200207eb278a09d63e2..3ebc50949263f420ec1a3bce2ebdfcd3a53f3ea8 100644 (file)
@@ -41,12 +41,8 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
             if (!EntityManager.GetComponent<TransformComponent>(ent).Anchored || !args.IsInDetailsRange) // Not anchored? Out of range? No status.
                 return;
 
-            if (!EntityManager.TryGetComponent(ent, out NodeContainerComponent? nodeContainer)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.InletName, out PipeNode? inlet)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.OutletName, out PipeNode? _))
-            {
+            if (!_nodeContainer.TryGetNode(ent.Owner, comp.InletName, out PipeNode? inlet))
                 return;
-            }
 
             using (args.PushGroup(nameof(GasRecyclerComponent)))
             {
@@ -72,9 +68,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
         private void OnUpdate(Entity<GasRecyclerComponent> ent, ref AtmosDeviceUpdateEvent args)
         {
             var comp = ent.Comp;
-            if (!EntityManager.TryGetComponent(ent, out NodeContainerComponent? nodeContainer)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.InletName, out PipeNode? inlet)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.OutletName, out PipeNode? outlet))
+            if (!_nodeContainer.TryGetNodes(ent.Owner, comp.InletName, comp.OutletName, out PipeNode? inlet, out PipeNode? outlet))
             {
                 _ambientSoundSystem.SetAmbience(ent, false);
                 return;
index 934ce8a7a47d418187a460038e55905dee39e98d..ed7567428e14f9505aaa82362c0186d1d7975a91 100644 (file)
@@ -59,9 +59,8 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
         public void Set(EntityUid uid, GasValveComponent component, bool value)
         {
             component.Open = value;
-            if (TryComp(uid, out NodeContainerComponent? nodeContainer)
-                && _nodeContainer.TryGetNode(nodeContainer, component.InletName, out PipeNode? inlet)
-                && _nodeContainer.TryGetNode(nodeContainer, component.OutletName, out PipeNode? outlet))
+
+            if (_nodeContainer.TryGetNodes(uid, component.InletName, component.OutletName, out PipeNode? inlet, out PipeNode? outlet))
             {
                 if (TryComp<AppearanceComponent>(uid, out var appearance))
                 {
index 8e478bd2b5456444216b905b30da04aa98b510ee..e4767c4061a7c366531bd4d8808558c05e746d12 100644 (file)
@@ -71,11 +71,8 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
 
         private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, ref AtmosDeviceUpdateEvent args)
         {
-            if (!pump.Enabled
-                || !TryComp(uid, out NodeContainerComponent? nodeContainer)
-                || !TryComp(uid, out AtmosDeviceComponent? device)
-                || !_nodeContainer.TryGetNode(nodeContainer, pump.InletName, out PipeNode? inlet)
-                || !_nodeContainer.TryGetNode(nodeContainer, pump.OutletName, out PipeNode? outlet))
+            if (!pump.Enabled ||
+                !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet))
             {
                 _ambientSoundSystem.SetAmbience(uid, false);
                 return;
index 80461f1bebfc3e2875d3562e6b21a449f65fec0a..b70262e857b01a2ab067ec9d430e27c181d665fd 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Server.Atmos.Components;
+using Content.Shared.Atmos.Components;
 
 namespace Content.Server.Atmos.Piping.Components;
 
@@ -46,18 +47,25 @@ public sealed partial class AtmosDeviceComponent : Component
 /// Use this for atmos devices instead of <see cref="EntitySystem.Update"/>.
 /// </summary>
 [ByRefEvent]
-public readonly struct AtmosDeviceUpdateEvent
+public readonly struct AtmosDeviceUpdateEvent(float dt, Entity<GridAtmosphereComponent, GasTileOverlayComponent>? grid, Entity<MapAtmosphereComponent?>? map)
 {
     /// <summary>
     /// Time elapsed since last update, in seconds. Multiply values used in the update handler
     /// by this number to make them tickrate-invariant. Use this number instead of AtmosphereSystem.AtmosTime.
     /// </summary>
-    public readonly float dt;
+    public readonly float dt = dt;
 
-    public AtmosDeviceUpdateEvent(float dt)
-    {
-        this.dt = dt;
-    }
+    /// <summary>
+    /// The grid that this device is currently on.
+    /// </summary>
+    public readonly Entity<GridAtmosphereComponent?, GasTileOverlayComponent?>? Grid = grid == null
+        ? null
+        : (grid.Value, grid.Value, grid.Value);
+
+    /// <summary>
+    /// The map that the device & grid is on.
+    /// </summary>
+    public readonly Entity<MapAtmosphereComponent?>? Map = map;
 }
 
 /// <summary>
index c15d31f7d64d6bbcd967f9f52392f30a12b7bdd8..3c73a8f64ee916e96829ef807a16f1fcae941667 100644 (file)
@@ -129,9 +129,10 @@ namespace Content.Server.Atmos.Piping.EntitySystems
             _timer -= _atmosphereSystem.AtmosTime;
 
             var time = _gameTiming.CurTime;
-            var ev = new AtmosDeviceUpdateEvent(_atmosphereSystem.AtmosTime);
+            var ev = new AtmosDeviceUpdateEvent(_atmosphereSystem.AtmosTime, null, null);
             foreach (var device in _joinedDevices)
             {
+                DebugTools.Assert(!HasComp<GridAtmosphereComponent>(Transform(device).GridUid));
                 RaiseLocalEvent(device, ref ev);
                 device.Comp.LastProcess = time;
             }
index 9853a17f829a9a185de04c4dd55aede5411dd236..aa206dbc6867c009e0e43232d1b8666b09dd6398 100644 (file)
@@ -38,9 +38,9 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems
         private bool CheckMinerOperation(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
         {
             var (uid, miner) = ent;
-            environment = _atmosphereSystem.GetContainingMixture(uid, true, true);
-
             var transform = Transform(uid);
+            environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
+
             var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
 
             // Space.
index faf06a60793b23cba14d1405c4b2493c341672d9..f856946a9252efd90fc57c15dd399f985e8234fe 100644 (file)
@@ -53,11 +53,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
         private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, ref AtmosDeviceUpdateEvent args)
         {
             if (!filter.Enabled
-                || !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
-                || !EntityManager.TryGetComponent(uid, out AtmosDeviceComponent? device)
-                || !_nodeContainer.TryGetNode(nodeContainer, filter.InletName, out PipeNode? inletNode)
-                || !_nodeContainer.TryGetNode(nodeContainer, filter.FilterName, out PipeNode? filterNode)
-                || !_nodeContainer.TryGetNode(nodeContainer, filter.OutletName, out PipeNode? outletNode)
+                || !_nodeContainer.TryGetNodes(uid, filter.InletName, filter.OutletName, filter.FilterName, out PipeNode? inletNode, out PipeNode? filterNode, out PipeNode? outletNode)
                 || outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure) // No need to transfer if target is full.
             {
                 _ambientSoundSystem.SetAmbience(uid, false);
@@ -187,16 +183,15 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
             if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
                 return;
 
-            var gasMixDict = new Dictionary<string, GasMixture?>();
+            args.GasMixtures ??= new Dictionary<string, GasMixture?>();
 
             if(_nodeContainer.TryGetNode(nodeContainer, component.InletName, out PipeNode? inlet))
-                gasMixDict.Add(Loc.GetString("gas-analyzer-window-text-inlet"), inlet.Air);
+                args.GasMixtures.Add(Loc.GetString("gas-analyzer-window-text-inlet"), inlet.Air);
             if(_nodeContainer.TryGetNode(nodeContainer, component.FilterName, out PipeNode? filterNode))
-                gasMixDict.Add(Loc.GetString("gas-analyzer-window-text-filter"), filterNode.Air);
+                args.GasMixtures.Add(Loc.GetString("gas-analyzer-window-text-filter"), filterNode.Air);
             if(_nodeContainer.TryGetNode(nodeContainer, component.OutletName, out PipeNode? outlet))
-                gasMixDict.Add(Loc.GetString("gas-analyzer-window-text-outlet"), outlet.Air);
+                args.GasMixtures.Add(Loc.GetString("gas-analyzer-window-text-outlet"), outlet.Air);
 
-            args.GasMixtures = gasMixDict;
             args.DeviceFlipped = inlet != null && filterNode != null && inlet.CurrentPipeDirection.ToDirection() == filterNode.CurrentPipeDirection.ToDirection().GetClockwise90Degrees();
         }
     }
index fb65c17f6102670276ff4a509dc2b6a2741dedbe..ba8ebf3c9ae2d95b5c30868361fbdc0d323383f7 100644 (file)
@@ -54,18 +54,8 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
         {
             // TODO ATMOS: Cache total moles since it's expensive.
 
-            if (!mixer.Enabled)
-            {
-                _ambientSoundSystem.SetAmbience(uid, false);
-                return;
-            }
-
-            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
-                return;
-
-            if (!_nodeContainer.TryGetNode(nodeContainer, mixer.InletOneName, out PipeNode? inletOne)
-                || !_nodeContainer.TryGetNode(nodeContainer, mixer.InletTwoName, out PipeNode? inletTwo)
-                || !_nodeContainer.TryGetNode(nodeContainer, mixer.OutletName, out PipeNode? outlet))
+            if (!mixer.Enabled
+                || !_nodeContainer.TryGetNodes(uid, mixer.InletOneName, mixer.InletTwoName, mixer.OutletName, out PipeNode? inletOne, out PipeNode? inletTwo, out PipeNode? outlet))
             {
                 _ambientSoundSystem.SetAmbience(uid, false);
                 return;
index 2c2f1584a53534c90e2d769b23bbe430e5bd3ac1..1bab2abd8e9e84d9a45c73e6e0a44d7522f5d4af 100644 (file)
@@ -33,11 +33,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
 
         private void OnUpdate(EntityUid uid, PressureControlledValveComponent comp, ref AtmosDeviceUpdateEvent args)
         {
-            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
-                || !EntityManager.TryGetComponent(uid, out AtmosDeviceComponent? device)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.InletName, out PipeNode? inletNode)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.ControlName, out PipeNode? controlNode)
-                || !_nodeContainer.TryGetNode(nodeContainer, comp.OutletName, out PipeNode? outletNode))
+            if (!_nodeContainer.TryGetNodes(uid, comp.InletName, comp.ControlName, comp.OutletName, out PipeNode? inletNode, out PipeNode? controlNode, out PipeNode? outletNode))
             {
                 _ambientSoundSystem.SetAmbience(uid, false);
                 comp.Enabled = false;
index 170586339db6e52bd9dd8d9d4e5d57d558f5beb8..3e4340bf1db557a9b3453cc4816280706860e7e1 100644 (file)
@@ -60,7 +60,7 @@ public sealed class GasCanisterSystem : EntitySystem
         if (!Resolve(uid, ref canister, ref transform))
             return;
 
-        var environment = _atmos.GetContainingMixture(uid, false, true);
+        var environment = _atmos.GetContainingMixture((uid, transform), false, true);
 
         if (environment is not null)
             _atmos.Merge(environment, canister.Air);
@@ -168,7 +168,7 @@ public sealed class GasCanisterSystem : EntitySystem
             }
             else
             {
-                var environment = _atmos.GetContainingMixture(uid, false, true);
+                var environment = _atmos.GetContainingMixture(uid, args.Grid, args.Map, false, true);
                 _atmos.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure);
             }
         }
index 852542ec6cd29e59a6a23b67e01a6b61aa0a68b2..e903ceedafa2ad0a601932db96b0b7eb3f8cc145 100644 (file)
@@ -30,9 +30,8 @@ public sealed class GasCondenserSystem : EntitySystem
 
     private void OnCondenserUpdated(Entity<GasCondenserComponent> entity, ref AtmosDeviceUpdateEvent args)
     {
-        if (!(_power.IsPowered(entity) && TryComp<ApcPowerReceiverComponent>(entity, out var receiver))
-            || !TryComp<NodeContainerComponent>(entity, out var nodeContainer)
-            || !_nodeContainer.TryGetNode(nodeContainer, entity.Comp.Inlet, out PipeNode? inlet)
+        if (!(TryComp<ApcPowerReceiverComponent>(entity, out var receiver) && _power.IsPowered(entity, receiver))
+            || !_nodeContainer.TryGetNode(entity.Owner, entity.Comp.Inlet, out PipeNode? inlet)
             || !_solution.ResolveSolution(entity.Owner, entity.Comp.SolutionId, ref entity.Comp.Solution, out var solution))
         {
             return;
index 8029a0955651f1e7426e9560577e615ebefd891a..834a1dfb0b7526203d2e480b9820d24eaf60653a 100644 (file)
@@ -50,16 +50,10 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
             if (!injector.Enabled)
                 return;
 
-            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+            if (!_nodeContainer.TryGetNode(uid, injector.InletName, out PipeNode? inlet))
                 return;
 
-            if (!TryComp(uid, out AtmosDeviceComponent? device))
-                return;
-
-            if (!_nodeContainer.TryGetNode(nodeContainer, injector.InletName, out PipeNode? inlet))
-                return;
-
-            var environment = _atmosphereSystem.GetContainingMixture(uid, true, true);
+            var environment = _atmosphereSystem.GetContainingMixture(uid, args.Grid, args.Map, true, true);
 
             if (environment == null)
                 return;
index c8fd23d466a1a2b6eaa42cfd758df09d052feb2d..72812cb5237a93fe74266bdbec2da51261534f65 100644 (file)
@@ -24,15 +24,12 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
 
         private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, ref AtmosDeviceUpdateEvent args)
         {
-            var environment = _atmosphereSystem.GetContainingMixture(uid, true, true);
+            var environment = _atmosphereSystem.GetContainingMixture(uid, args.Grid, args.Map, true, true);
 
             if (environment == null)
                 return;
 
-            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
-                return;
-
-            if (!_nodeContainer.TryGetNode(nodeContainer, vent.InletName, out PipeNode? inlet))
+            if (!_nodeContainer.TryGetNode(uid, vent.InletName, out PipeNode? inlet))
                 return;
 
             var inletAir = inlet.Air.RemoveRatio(1f);
index 4ddd19dd45e0a7af276f27fad5ae69d4a9cdf948..7cb8102a38849d9ca5292fce11eeec858385d0ff 100644 (file)
@@ -39,10 +39,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
 
         private void OnAnchorChanged(EntityUid uid, GasPortableComponent portable, ref AnchorStateChangedEvent args)
         {
-            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
-                return;
-
-            if (!_nodeContainer.TryGetNode(nodeContainer, portable.PortName, out PipeNode? portableNode))
+            if (!_nodeContainer.TryGetNode(uid, portable.PortName, out PipeNode? portableNode))
                 return;
 
             portableNode.ConnectionsEnabled = args.Anchored;
index d4ddd65a8ec9de7267730484cbbb938dff9438d0..9b61044f03eb82f8a9c0fc6b7081debb62de8999 100644 (file)
@@ -110,7 +110,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
                 _atmosphereSystem.AddHeat(heatExchangeGasMixture, dQPipe);
                 thermoMachine.LastEnergyDelta = dQPipe;
 
-                if (dQLeak != 0f && _atmosphereSystem.GetContainingMixture(uid, excite: true) is { } containingMixture)
+                if (dQLeak != 0f && _atmosphereSystem.GetContainingMixture(uid, args.Grid, args.Map, excite: true) is { } containingMixture)
                     _atmosphereSystem.AddHeat(containingMixture, dQLeak);
             }
 
@@ -130,8 +130,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
             }
             else
             {
-                if (!TryComp<NodeContainerComponent>(uid, out var nodeContainer)
-                    || !_nodeContainer.TryGetNode(nodeContainer, thermoMachine.InletName, out PipeNode? inlet))
+                if (!_nodeContainer.TryGetNode(uid, thermoMachine.InletName, out PipeNode? inlet))
                     return;
                 heatExchangeGasMixture = inlet.Air;
             }
index 3a3ccf7523409d049954ff08435ce4641b845cbd..a986385f5e9b1ae4b92e2beb849f4ba2d386c252 100644 (file)
@@ -67,15 +67,12 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
                 _ => throw new ArgumentOutOfRangeException()
             };
 
-            if (!vent.Enabled
-                || !TryComp(uid, out AtmosDeviceComponent? device)
-                || !TryComp(uid, out NodeContainerComponent? nodeContainer)
-                || !_nodeContainer.TryGetNode(nodeContainer, nodeName, out PipeNode? pipe))
+            if (!vent.Enabled || !_nodeContainer.TryGetNode(uid, nodeName, out PipeNode? pipe))
             {
                 return;
             }
 
-            var environment = _atmosphereSystem.GetContainingMixture(uid, true, true);
+            var environment = _atmosphereSystem.GetContainingMixture(uid, args.Grid, args.Map, true, true);
 
             // We're in an air-blocked tile... Do nothing.
             if (environment == null)
@@ -295,9 +292,6 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
         /// </summary>
         private void OnAnalyzed(EntityUid uid, GasVentPumpComponent component, GasAnalyzerScanEvent args)
         {
-            if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
-                return;
-
             var gasMixDict = new Dictionary<string, GasMixture?>();
 
             // these are both called pipe, above it switches using this so I duplicated that...?
@@ -307,7 +301,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
                 VentPumpDirection.Siphoning => component.Outlet,
                 _ => throw new ArgumentOutOfRangeException()
             };
-            if (_nodeContainer.TryGetNode(nodeContainer, nodeName, out PipeNode? pipe))
+            if (_nodeContainer.TryGetNode(uid, nodeName, out PipeNode? pipe))
                 gasMixDict.Add(nodeName, pipe.Air);
 
             args.GasMixtures = gasMixDict;
index 5afa007e5e1286d76d5d1548f82b2bbe9c1559f0..b27689ed586ed5af358ce7eeaf2103510dceb159 100644 (file)
@@ -49,27 +49,18 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
         private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, ref AtmosDeviceUpdateEvent args)
         {
             if (_weldable.IsWelded(uid))
-            {
-                return;
-            }
-
-            if (!TryComp(uid, out AtmosDeviceComponent? device))
                 return;
 
             var timeDelta = args.dt;
 
-            if (!scrubber.Enabled
-            || !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
-            || !_nodeContainer.TryGetNode(nodeContainer, scrubber.OutletName, out PipeNode? outlet))
+            if (!scrubber.Enabled || !_nodeContainer.TryGetNode(uid, scrubber.OutletName, out PipeNode? outlet))
                 return;
 
-            var xform = Transform(uid);
-
-            if (xform.GridUid == null)
+            if (args.Grid is not {} grid)
                 return;
 
-            var position = _transformSystem.GetGridTilePositionOrDefault((uid,xform));
-            var environment = _atmosphereSystem.GetTileMixture(xform.GridUid, xform.MapUid, position, true);
+            var position = _transformSystem.GetGridTilePositionOrDefault(uid);
+            var environment = _atmosphereSystem.GetTileMixture(grid, args.Map, position, true);
 
             Scrub(timeDelta, scrubber, environment, outlet);
 
@@ -77,7 +68,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
                 return;
 
             // Scrub adjacent tiles too.
-            var enumerator = _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true);
+            var enumerator = _atmosphereSystem.GetAdjacentTileMixtures(grid, position, false, true);
             while (enumerator.MoveNext(out var adjacent))
             {
                 Scrub(timeDelta, scrubber, adjacent, outlet);
index e986f8f991d380b1261eec0298c3d2e8a5b3ec8d..f9043c091a8be2a3455b3528aabb8cba8537f0db 100644 (file)
@@ -47,17 +47,13 @@ namespace Content.Server.Atmos.Portable
 
         private void OnDeviceUpdated(EntityUid uid, PortableScrubberComponent component, ref AtmosDeviceUpdateEvent args)
         {
-            if (!TryComp(uid, out AtmosDeviceComponent? device))
-                return;
-
             var timeDelta = args.dt;
 
             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(nodeContainer, component.PortName, out PortablePipeNode? portableNode)
+            if (_nodeContainer.TryGetNode(uid, component.PortName, out PortablePipeNode? portableNode)
                 && portableNode.ConnectionsEnabled)
             {
                 _atmosphereSystem.React(component.Air, portableNode);
@@ -71,13 +67,11 @@ namespace Content.Server.Atmos.Portable
                 return;
             }
 
-            var xform = Transform(uid);
-
-            if (xform.GridUid == null)
+            if (args.Grid is not {} grid)
                 return;
 
-            var position = _transformSystem.GetGridTilePositionOrDefault((uid,xform));
-            var environment = _atmosphereSystem.GetTileMixture(xform.GridUid, xform.MapUid, position, true);
+            var position = _transformSystem.GetGridTilePositionOrDefault(uid);
+            var environment = _atmosphereSystem.GetTileMixture(grid, args.Map, position, true);
 
             var running = Scrub(timeDelta, component, environment);
 
@@ -85,8 +79,9 @@ namespace Content.Server.Atmos.Portable
             // We scrub once to see if we can and set the animation
             if (!running)
                 return;
+
             // widenet
-            var enumerator = _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true);
+            var enumerator = _atmosphereSystem.GetAdjacentTileMixtures(grid, position, false, true);
             while (enumerator.MoveNext(out var adjacent))
             {
                 Scrub(timeDelta, component, adjacent);
@@ -98,10 +93,7 @@ namespace Content.Server.Atmos.Portable
         /// </summary>
         private void OnAnchorChanged(EntityUid uid, PortableScrubberComponent component, ref AnchorStateChangedEvent args)
         {
-            if (!TryComp(uid, out NodeContainerComponent? nodeContainer))
-                return;
-
-            if (!_nodeContainer.TryGetNode(nodeContainer, component.PortName, out PipeNode? portableNode))
+            if (!_nodeContainer.TryGetNode(uid, component.PortName, out PipeNode? portableNode))
                 return;
 
             portableNode.ConnectionsEnabled = (args.Anchored && _gasPortableSystem.FindGasPortIn(Transform(uid).GridUid, Transform(uid).Coordinates, out _));
@@ -159,14 +151,10 @@ namespace Content.Server.Atmos.Portable
         /// </summary>
         private void OnScrubberAnalyzed(EntityUid uid, PortableScrubberComponent component, GasAnalyzerScanEvent args)
         {
-            var gasMixDict = new Dictionary<string, GasMixture?> { { Name(uid), component.Air } };
+            args.GasMixtures ??= new Dictionary<string, GasMixture?> { { Name(uid), component.Air } };
             // If it's connected to a port, include the port side
-            if (TryComp(uid, out NodeContainerComponent? nodeContainer))
-            {
-                if (_nodeContainer.TryGetNode(nodeContainer, component.PortName, out PipeNode? port))
-                    gasMixDict.Add(component.PortName, port.Air);
-            }
-            args.GasMixtures = gasMixDict;
+            if (_nodeContainer.TryGetNode(uid, component.PortName, out PipeNode? port))
+                args.GasMixtures.Add(component.PortName, port.Air);
         }
     }
 }
index 16311328218623d5097580f68ec0f48cf052db2c..fff15f696c46d17b1abc630040e8709533da028d 100644 (file)
@@ -71,7 +71,7 @@ public sealed class SpaceHeaterSystem : EntitySystem
         // If in automatic temperature mode, check if we need to adjust the heat exchange direction
         if (spaceHeater.Mode == SpaceHeaterMode.Auto)
         {
-            var environment = _atmosphereSystem.GetContainingMixture(uid);
+            var environment = _atmosphereSystem.GetContainingMixture(uid, args.Grid, args.Map);
             if (environment == null)
                 return;
 
index 7abcba76666d6fc0b15e8762723ff32ad15dab3c..c8e437d3532539f881c76dab193370546982099c 100644 (file)
@@ -9,7 +9,7 @@ namespace Content.Server.Electrocution
     public sealed partial class ElectrocutionNode : Node
     {
         [DataField("cable")]
-        public EntityUid CableEntity;
+        public EntityUid? CableEntity;
         [DataField("node")]
         public string? NodeName;
 
@@ -19,12 +19,11 @@ namespace Content.Server.Electrocution
             MapGridComponent? grid,
             IEntityManager entMan)
         {
-            var _nodeContainer = entMan.System<NodeContainerSystem>();
-
-            if (!nodeQuery.TryGetComponent(CableEntity, out var nodeContainer))
+            if (CableEntity == null || NodeName == null)
                 yield break;
 
-            if (_nodeContainer.TryGetNode(nodeContainer, NodeName, out Node? node))
+            var _nodeContainer = entMan.System<NodeContainerSystem>();
+            if (_nodeContainer.TryGetNode(CableEntity.Value, NodeName, out Node? node))
                 yield return node;
         }
     }
index 8d2a699de270b634d936ddb4046b1b60506f5df8..7db1f513f7c41aa44d278f1185c5d8d2b65f75a5 100644 (file)
@@ -271,7 +271,7 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood
                 var direction = (AtmosDirection) (1 << i);
                 if (ignoreTileBlockers || !blockedDirections.IsFlagSet(direction))
                 {
-                    ProcessNewTile(iteration, tile.Offset(direction), direction.GetOpposite());
+                    ProcessNewTile(iteration, tile.Offset(direction), i.ToOppositeDir());
                 }
             }
 
@@ -300,7 +300,7 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood
                 var direction = (AtmosDirection) (1 << i);
                 if (blockedDirections.IsFlagSet(direction))
                 {
-                    list.Add((tile.Offset(direction), direction.GetOpposite()));
+                    list.Add((tile.Offset(direction), i.ToOppositeDir()));
                 }
             }
         }
index f8c917c1cd6cd941e7125ea784d7128228776f22..313b03e03a6b578c90dbf64844b11a7cf24ca837 100644 (file)
@@ -97,7 +97,7 @@ public sealed class ExplosionSpaceTileFlood : ExplosionTileFlood
                 if (!unblockedDirections.IsFlagSet(direction))
                     continue; // explosion cannot propagate in this direction. Ever.
 
-                ProcessNewTile(iteration, tile.Offset(direction), direction.GetOpposite());
+                ProcessNewTile(iteration, tile.Offset(direction), i.ToOppositeDir());
             }
         }
     }
index 78034e0fc3df5d5b6db8c316d2f891f68ae4f23a..9e546dc33fe78367a8bef810989e074478b1f2f5 100644 (file)
@@ -404,14 +404,17 @@ public sealed partial class MechSystem : SharedMechSystem
         if (args.Handled)
             return;
 
-        if (!TryComp<MechComponent>(component.Mech, out var mech) ||
-            !TryComp<MechAirComponent>(component.Mech, out var mechAir))
+        if (!TryComp(component.Mech, out MechComponent? mech))
+            return;
+
+        if (mech.Airtight && TryComp(component.Mech, out MechAirComponent? air))
         {
+            args.Handled = true;
+            args.Gas = air.Air;
             return;
         }
 
-        args.Gas = mech.Airtight ? mechAir.Air : _atmosphere.GetContainingMixture(component.Mech);
-
+        args.Gas =  _atmosphere.GetContainingMixture(component.Mech, excite: args.Excite);
         args.Handled = true;
     }
 
index a7d12d9f0fdf740fad7bc96ce6debe7547926359..a949d980bef4f733e6e021b68598111ca1da2560 100644 (file)
@@ -257,10 +257,7 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem
 
     private void OnCryoPodUpdateAtmosphere(Entity<CryoPodComponent> entity, ref AtmosDeviceUpdateEvent args)
     {
-        if (!TryComp(entity, out NodeContainerComponent? nodeContainer))
-            return;
-
-        if (!_nodeContainer.TryGetNode(nodeContainer, entity.Comp.PortName, out PortablePipeNode? portNode))
+        if (!_nodeContainer.TryGetNode(entity.Owner, entity.Comp.PortName, out PortablePipeNode? portNode))
             return;
 
         if (!TryComp(entity, out CryoPodAirComponent? cryoPodAir))
@@ -279,14 +276,10 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem
         if (!TryComp(entity, out CryoPodAirComponent? cryoPodAir))
             return;
 
-        var gasMixDict = new Dictionary<string, GasMixture?> { { Name(entity.Owner), cryoPodAir.Air } };
+        args.GasMixtures ??= new Dictionary<string, GasMixture?> { { Name(entity.Owner), cryoPodAir.Air } };
         // If it's connected to a port, include the port side
-        if (TryComp(entity, out NodeContainerComponent? nodeContainer))
-        {
-            if (_nodeContainer.TryGetNode(nodeContainer, entity.Comp.PortName, out PipeNode? port))
-                gasMixDict.Add(entity.Comp.PortName, port.Air);
-        }
-        args.GasMixtures = gasMixDict;
+        if (_nodeContainer.TryGetNode(entity.Owner, entity.Comp.PortName, out PipeNode? port))
+            args.GasMixtures.Add(entity.Comp.PortName, port.Air);
     }
 
     private void OnEjected(Entity<CryoPodComponent> cryoPod, ref EntRemovedFromContainerMessage args)
index 99d18aeb3f9940bffd0ecaf6d91864df43616ba5..19b811a287f7be19ba9bb2817d1cf434955acf64 100644 (file)
@@ -14,6 +14,7 @@ namespace Content.Server.NodeContainer.EntitySystems
     public sealed class NodeContainerSystem : EntitySystem
     {
         [Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!;
+        private EntityQuery<NodeContainerComponent> _query;
 
         public override void Initialize()
         {
@@ -26,6 +27,8 @@ namespace Content.Server.NodeContainer.EntitySystems
             SubscribeLocalEvent<NodeContainerComponent, ReAnchorEvent>(OnReAnchor);
             SubscribeLocalEvent<NodeContainerComponent, MoveEvent>(OnMoveEvent);
             SubscribeLocalEvent<NodeContainerComponent, ExaminedEvent>(OnExamine);
+
+            _query = GetEntityQuery<NodeContainerComponent>();
         }
 
         public bool TryGetNode<T>(NodeContainerComponent component, string? identifier, [NotNullWhen(true)] out T? node) where T : Node
@@ -46,6 +49,77 @@ namespace Content.Server.NodeContainer.EntitySystems
             return false;
         }
 
+        public bool TryGetNode<T>(Entity<NodeContainerComponent?> ent, string identifier, [NotNullWhen(true)] out T? node) where T : Node
+        {
+            if (_query.Resolve(ent, ref ent.Comp, false)
+                && ent.Comp.Nodes.TryGetValue(identifier, out var n)
+                && n is T t)
+            {
+                node = t;
+                return true;
+            }
+
+            node = null;
+            return false;
+        }
+
+        public bool TryGetNodes<T1, T2>(
+            Entity<NodeContainerComponent?> ent,
+            string id1,
+            string id2,
+            [NotNullWhen(true)] out T1? node1,
+            [NotNullWhen(true)] out T2? node2)
+            where T1 : Node
+            where T2 : Node
+        {
+            if (_query.Resolve(ent, ref ent.Comp, false)
+                && ent.Comp.Nodes.TryGetValue(id1, out var n1)
+                && n1 is T1 t1
+                && ent.Comp.Nodes.TryGetValue(id2, out var n2)
+                && n2 is T2 t2)
+            {
+                node1 = t1;
+                node2 = t2;
+                return true;
+            }
+
+            node1 = null;
+            node2 = null;
+            return false;
+        }
+
+        public bool TryGetNodes<T1, T2, T3>(
+            Entity<NodeContainerComponent?> ent,
+            string id1,
+            string id2,
+            string id3,
+            [NotNullWhen(true)] out T1? node1,
+            [NotNullWhen(true)] out T2? node2,
+            [NotNullWhen(true)] out T3? node3)
+            where T1 : Node
+            where T2 : Node
+            where T3 : Node
+        {
+            if (_query.Resolve(ent, ref ent.Comp, false)
+                && ent.Comp.Nodes.TryGetValue(id1, out var n1)
+                && n1 is T1 t1
+                && ent.Comp.Nodes.TryGetValue(id2, out var n2)
+                && n2 is T2 t2
+                && ent.Comp.Nodes.TryGetValue(id3, out var n3)
+                && n2 is T3 t3)
+            {
+                node1 = t1;
+                node2 = t2;
+                node3 = t3;
+                return true;
+            }
+
+            node1 = null;
+            node2 = null;
+            node3 = null;
+            return false;
+        }
+
         private void OnInitEvent(EntityUid uid, NodeContainerComponent component, ComponentInit args)
         {
             foreach (var (key, node) in component.Nodes)
index 60f0603074d8d2e6ff679dbae47cad35153e8390..6e0e0c503a9ef8a40ba80f8dbe2909b4faa97dd6 100644 (file)
@@ -94,7 +94,7 @@ public sealed class PneumaticCannonSystem : SharedPneumaticCannonSystem
             return;
 
         // this should always be possible, as we'll eject the gas tank when it no longer is
-        var environment = _atmos.GetContainingMixture(cannon, false, true);
+        var environment = _atmos.GetContainingMixture(cannon.Owner, false, true);
         var removed = _gasTank.RemoveAir(gas.Value, component.GasUsage);
         if (environment != null && removed != null)
         {
index bd9c62ba80851fcb29fe86adee25038b950be83a..51d68b99fdc6d37006afc323b9910b7b599cc4f4 100644 (file)
@@ -4,7 +4,7 @@
     public sealed partial class CableVisComponent : Component
     {
         [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("node")]
-        public string? Node;
+        [DataField("node", required:true)]
+        public string Node;
     }
 }
index ec08523d447f07a0bd7d1cab631cabe66dec3f3b..1a68e87ad611de342ebfc1629fd012f3805bbfe2 100644 (file)
@@ -23,10 +23,7 @@ namespace Content.Server.Power.EntitySystems
 
         private void UpdateAppearance(EntityUid uid, CableVisComponent cableVis, ref NodeGroupsRebuilt args)
         {
-            if (!TryComp(uid, out NodeContainerComponent? nodeContainer) || !TryComp(uid, out AppearanceComponent? appearance))
-                return;
-
-            if (!_nodeContainer.TryGetNode<CableNode>(nodeContainer, cableVis.Node, out var node))
+            if (!_nodeContainer.TryGetNode(uid, cableVis.Node, out CableNode? node))
                 return;
 
             var transform = Transform(uid);
@@ -55,7 +52,7 @@ namespace Content.Server.Power.EntitySystems
                 };
             }
 
-            _appearance.SetData(uid, WireVisVisuals.ConnectedMask, mask, appearance);
+            _appearance.SetData(uid, WireVisVisuals.ConnectedMask, mask);
         }
     }
 }
index 76cf90c3693327cc2bed00ce8118f2f4a55deac6..5f79906c9951a284e12cb5ce4c72829904566bf9 100644 (file)
@@ -26,12 +26,8 @@ public sealed class GasPowerReceiverSystem : EntitySystem
     {
         var timeDelta = args.dt;
 
-        if (!HasComp<AtmosDeviceComponent>(uid)
-            || !TryComp<NodeContainerComponent>(uid, out var nodeContainer)
-            || !_nodeContainer.TryGetNode<PipeNode>(nodeContainer, "pipe", out var pipe))
-        {
+        if (!_nodeContainer.TryGetNode(uid, "pipe", out PipeNode? pipe))
             return;
-        }
 
         // if we're below the max temperature, then we are simply consuming our target gas
         if (pipe.Air.Temperature <= component.MaxTemperature)
@@ -57,7 +53,7 @@ public sealed class GasPowerReceiverSystem : EntitySystem
                 if (component.OffVentGas)
                 {
                     // eject the gas into the atmosphere
-                    var mix = _atmosphereSystem.GetContainingMixture(uid, false, true);
+                    var mix = _atmosphereSystem.GetContainingMixture(uid, args.Grid, args.Map, false, true);
                     if (mix is not null)
                         _atmosphereSystem.Merge(res, mix);
                 }
index 671c281d1f4059caf4c765ecb37e7cd69df3bbe2..fe14d86aa1dadab8298418283f20c48b657a83c0 100644 (file)
@@ -231,10 +231,9 @@ public sealed class SpreaderSystem : EntitySystem
         // Add the normal neighbors.
         for (var i = 0; i < 4; i++)
         {
-            var direction = (Direction) (i * 2);
-            var atmosDir = direction.ToAtmosDirection();
-            var neighborPos = SharedMapSystem.GetDirection(tile, direction);
-            neighborTiles.Add((comp.GridUid.Value, grid, neighborPos, atmosDir, atmosDir.GetOpposite()));
+            var atmosDir = (AtmosDirection) (1 << i);
+            var neighborPos = tile.Offset(atmosDir);
+            neighborTiles.Add((comp.GridUid.Value, grid, neighborPos, atmosDir, i.ToOppositeDir()));
         }
 
         foreach (var (neighborEnt, neighborGrid, neighborPos, ourAtmosDir, otherAtmosDir) in neighborTiles)
index a25c9d553c5aaf5801666d742736f6be8809a8be..09ba521aa96d4499b2e343a90bc893226ce657f8 100644 (file)
@@ -1,4 +1,5 @@
-using System.Runtime.CompilerServices;
+using System.Numerics;
+using System.Runtime.CompilerServices;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Atmos
@@ -15,6 +16,8 @@ namespace Content.Shared.Atmos
         South   = 1 << 1,                   // 2
         East    = 1 << 2,                   // 4
         West    = 1 << 3,                   // 8
+        // If more directions are added, note that AtmosDirectionHelpers.ToOppositeIndex() expects opposite directions
+        // to come in pairs
 
         NorthEast = North | East,           // 5
         SouthEast = South | East,           // 6
@@ -42,6 +45,22 @@ namespace Content.Shared.Atmos
             };
         }
 
+        /// <summary>
+        /// This returns the index that corresponds to the opposite direction of some other direction index.
+        /// I.e., <c>1&lt;&lt;OppositeIndex(i) == (1&lt;&lt;i).GetOpposite()</c>
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int ToOppositeIndex(this int index)
+        {
+            return index ^ 1;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static AtmosDirection ToOppositeDir(this int index)
+        {
+            return (AtmosDirection) (1 << (index ^ 1));
+        }
+
         public static Direction ToDirection(this AtmosDirection direction)
         {
             return direction switch
@@ -119,10 +138,11 @@ namespace Content.Shared.Atmos
             return angle.GetDir().ToAtmosDirection();
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static int ToIndex(this AtmosDirection direction)
         {
             // This will throw if you pass an invalid direction. Not this method's fault, but yours!
-            return (int) Math.Log2((int) direction);
+            return BitOperations.Log2((uint)direction);
         }
 
         public static AtmosDirection WithFlag(this AtmosDirection direction, AtmosDirection other)
index f887ed3049f767925597c5c8b74785059bebe81c..b0ea68f713fc69fb1fd0c68f38575ee8866db858 100644 (file)
@@ -15,14 +15,7 @@ public sealed class WeldableSystem : EntitySystem
     [Dependency] private readonly SharedToolSystem _toolSystem = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SharedPhysicsSystem _physics = default!;
-
-    public bool IsWelded(EntityUid uid, WeldableComponent? component = null)
-    {
-        if (!Resolve(uid, ref component, false))
-            return false;
-
-        return component.IsWelded;
-    }
+    private EntityQuery<WeldableComponent> _query;
 
     public override void Initialize()
     {
@@ -31,6 +24,13 @@ public sealed class WeldableSystem : EntitySystem
         SubscribeLocalEvent<WeldableComponent, WeldFinishedEvent>(OnWeldFinished);
         SubscribeLocalEvent<LayerChangeOnWeldComponent, WeldableChangedEvent>(OnWeldChanged);
         SubscribeLocalEvent<WeldableComponent, ExaminedEvent>(OnExamine);
+
+        _query = GetEntityQuery<WeldableComponent>();
+    }
+
+    public bool IsWelded(EntityUid uid, WeldableComponent? component = null)
+    {
+        return _query.Resolve(uid, ref component, false) && component.IsWelded;
     }
 
     private void OnExamine(EntityUid uid, WeldableComponent component, ExaminedEvent args)
@@ -49,7 +49,7 @@ public sealed class WeldableSystem : EntitySystem
 
     private bool CanWeld(EntityUid uid, EntityUid tool, EntityUid user, WeldableComponent? component = null)
     {
-        if (!Resolve(uid, ref component))
+        if (!_query.Resolve(uid, ref component))
             return false;
 
         // Other component systems
@@ -63,7 +63,7 @@ public sealed class WeldableSystem : EntitySystem
 
     private bool TryWeld(EntityUid uid, EntityUid tool, EntityUid user, WeldableComponent? component = null)
     {
-        if (!Resolve(uid, ref component))
+        if (!_query.Resolve(uid, ref component))
             return false;
 
         if (!CanWeld(uid, tool, user, component))
@@ -115,17 +115,13 @@ public sealed class WeldableSystem : EntitySystem
 
     private void UpdateAppearance(EntityUid uid, WeldableComponent? component = null)
     {
-        if (!Resolve(uid, ref component))
-            return;
-
-        if (!TryComp(uid, out AppearanceComponent? appearance))
-            return;
-        _appearance.SetData(uid, WeldableVisuals.IsWelded, component.IsWelded, appearance);
+        if (_query.Resolve(uid, ref component))
+            _appearance.SetData(uid, WeldableVisuals.IsWelded, component.IsWelded);
     }
 
     public void SetWeldedState(EntityUid uid, bool state, WeldableComponent? component = null)
     {
-        if (!Resolve(uid, ref component))
+        if (!_query.Resolve(uid, ref component))
             return;
 
         if (component.IsWelded == state)
@@ -141,7 +137,7 @@ public sealed class WeldableSystem : EntitySystem
 
     public void SetWeldingTime(EntityUid uid, TimeSpan time, WeldableComponent? component = null)
     {
-        if (!Resolve(uid, ref component))
+        if (!_query.Resolve(uid, ref component))
             return;
 
         if (component.WeldingTime.Equals(time))
index 497071ee9394b3be2bffa58b973495a46fbdf940..ac65245191eaa1da89d3c9eb5482b05b63b90cc5 100644 (file)
@@ -1,7 +1,7 @@
 # Special entity used to attach to power networks as load when somebody gets electrocuted.
 - type: entity
   id: VirtualElectrocutionLoadBase
-  noSpawn: true
+  abstract: true
   components:
   - type: Electrocution
   - type: Icon