//[MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExplosivelyDepressurize(int cycleNum) { if (Air == null) { return; } var totalGasesRemoved = 0f; var queueCycle = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var tiles = new List <TileAtmosphere>(); var spaceTiles = new List <TileAtmosphere>(); tiles.Add(this); _tileAtmosInfo = new TileAtmosInfo { LastQueueCycle = queueCycle, CurrentTransferDirection = Direction.Invalid }; var tileCount = 1; for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; tile._tileAtmosInfo.LastCycle = cycleNum; tile._tileAtmosInfo.CurrentTransferDirection = Direction.Invalid; if (tile.Air.Immutable) { spaceTiles.Add(tile); tile.PressureSpecificTarget = tile; } else { if (i > Atmospherics.ZumosHardTileLimit) { continue; } foreach (var direction in Cardinal) { if (!_adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } if (tile2?.Air == null) { continue; } if (tile2._tileAtmosInfo.LastQueueCycle == queueCycle) { continue; } tile.ConsiderFirelocks(tile2); if (tile._adjacentTiles[direction]?.Air != null) { tile2._tileAtmosInfo = new TileAtmosInfo { LastQueueCycle = queueCycle }; tiles.Add(tile2); tileCount++; } } } } var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var progressionOrder = new List <TileAtmosphere>(); foreach (var tile in spaceTiles) { progressionOrder.Add(tile); tile._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; tile._tileAtmosInfo.CurrentTransferDirection = Direction.Invalid; } var progressionCount = progressionOrder.Count; for (int i = 0; i < progressionCount; i++) { var tile = progressionOrder[i]; foreach (var direction in Cardinal) { if (!_adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } if (tile2?._tileAtmosInfo.LastQueueCycle != queueCycle) { continue; } if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) { continue; } if (tile2.Air.Immutable) { continue; } tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2._tileAtmosInfo.CurrentTransferAmount = 0; tile2.PressureSpecificTarget = tile.PressureSpecificTarget; tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; progressionOrder.Add(tile2); progressionCount++; } } for (int i = 0; i < progressionCount; i++) { var tile = progressionOrder[i]; if (tile._tileAtmosInfo.CurrentTransferDirection == Direction.Invalid) { continue; } var hpdLength = _gridAtmosphereComponent.HighPressureDeltaCount; var inHdp = _gridAtmosphereComponent.HasHighPressureDelta(tile); if (!inHdp) { _gridAtmosphereComponent.AddHighPressureDelta(tile); } if (!tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection, out var tile2) || tile2.Air == null) { continue; } var sum = tile2.Air.TotalMoles; totalGasesRemoved += sum; tile._tileAtmosInfo.CurrentTransferAmount += sum; tile2._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; tile.PressureDifference = tile._tileAtmosInfo.CurrentTransferAmount; tile._pressureDirection = tile._tileAtmosInfo.CurrentTransferDirection; if (tile2._tileAtmosInfo.CurrentTransferDirection == Direction.Invalid) { tile2.PressureDifference = tile2._tileAtmosInfo.CurrentTransferAmount; tile2._pressureDirection = tile._tileAtmosInfo.CurrentTransferDirection; } tile.Air.Clear(); tile.UpdateVisuals(); tile.HandleDecompressionFloorRip(sum); } }
private void ResetTileAtmosInfo() { _tileAtmosInfo = new TileAtmosInfo { CurrentTransferDirection = Direction.Invalid }; }
//[MethodImpl(MethodImplOptions.AggressiveInlining)] public void EqualizePressureInZone(int cycleNum) { if (Air == null || (_tileAtmosInfo.LastCycle >= cycleNum)) { return; // Already done. } _tileAtmosInfo = new TileAtmosInfo(); var startingMoles = Air.TotalMoles; var runAtmos = false; // We need to figure if this is necessary foreach (var(direction, other) in _adjacentTiles) { if (other?.Air == null) { continue; } var comparisonMoles = other.Air.TotalMoles; if (!(MathF.Abs(comparisonMoles - startingMoles) > Atmospherics.MinimumMolesDeltaToMove)) { continue; } runAtmos = true; break; } if (!runAtmos) // There's no need so we don't bother. { _tileAtmosInfo.LastCycle = cycleNum; return; } var queueCycle = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var totalMoles = 0f; var tiles = new TileAtmosphere[Atmospherics.ZumosHardTileLimit]; tiles[0] = this; _tileAtmosInfo.LastQueueCycle = queueCycle; var tileCount = 1; for (var i = 0; i < tileCount; i++) { if (i > Atmospherics.ZumosHardTileLimit) { break; } var exploring = tiles[i]; if (i < Atmospherics.ZumosTileLimit) { var tileMoles = exploring.Air.TotalMoles; exploring._tileAtmosInfo.MoleDelta = tileMoles; totalMoles += tileMoles; } foreach (var(_, adj) in exploring._adjacentTiles) { if (adj?.Air == null) { continue; } if (adj._tileAtmosInfo.LastQueueCycle == queueCycle) { continue; } adj._tileAtmosInfo = new TileAtmosInfo(); adj._tileAtmosInfo.LastQueueCycle = queueCycle; if (tileCount < Atmospherics.ZumosHardTileLimit) { tiles[tileCount++] = adj; } if (adj.Air.Immutable) { // Looks like someone opened an airlock to space! ExplosivelyDepressurize(cycleNum); return; } } } if (tileCount > Atmospherics.ZumosTileLimit) { for (var i = Atmospherics.ZumosTileLimit; i < tileCount; i++) { //We unmark them. We shouldn't be pushing/pulling gases to/from them. var tile = tiles[i]; if (tile == null) { continue; } tiles[i]._tileAtmosInfo.LastQueueCycle = 0; } tileCount = Atmospherics.ZumosTileLimit; } //tiles = tiles.AsSpan().Slice(0, tileCount).ToArray(); // According to my benchmarks, this is much slower. Array.Resize(ref tiles, tileCount); var averageMoles = totalMoles / (tiles.Length); var giverTiles = new List <TileAtmosphere>(); var takerTiles = new List <TileAtmosphere>(); for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; tile._tileAtmosInfo.LastCycle = cycleNum; tile._tileAtmosInfo.MoleDelta -= averageMoles; if (tile._tileAtmosInfo.MoleDelta > 0) { giverTiles.Add(tile); } else { takerTiles.Add(tile); } } var logN = MathF.Log2(tiles.Length); // Optimization - try to spread gases using an O(nlogn) algorithm that has a chance of not working first to avoid O(n^2) if (giverTiles.Count > logN && takerTiles.Count > logN) { // Even if it fails, it will speed up the next part. Array.Sort(tiles, (a, b) => a._tileAtmosInfo.MoleDelta.CompareTo(b._tileAtmosInfo.MoleDelta)); foreach (var tile in tiles) { tile._tileAtmosInfo.FastDone = true; if (!(tile._tileAtmosInfo.MoleDelta > 0)) { continue; } Direction eligibleAdjBits = 0; var amtEligibleAdj = 0; foreach (var direction in Cardinal) { if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } // skip anything that isn't part of our current processing block. Original one didn't do this unfortunately, which probably cause some massive lag. if (tile2._tileAtmosInfo.FastDone || tile2._tileAtmosInfo.LastQueueCycle != queueCycle) { continue; } eligibleAdjBits |= direction; amtEligibleAdj++; } if (amtEligibleAdj <= 0) { continue; // Oof we've painted ourselves into a corner. Bad luck. Next part will handle this. } var molesToMove = tile._tileAtmosInfo.MoleDelta / amtEligibleAdj; foreach (var direction in Cardinal) { if ((eligibleAdjBits & direction) == 0 || !tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } tile.AdjustEqMovement(direction, molesToMove); tile._tileAtmosInfo.MoleDelta -= molesToMove; tile2._tileAtmosInfo.MoleDelta += molesToMove; } } giverTiles.Clear(); takerTiles.Clear(); foreach (var tile in tiles) { if (tile._tileAtmosInfo.MoleDelta > 0) { giverTiles.Add(tile); } else { takerTiles.Add(tile); } } // This is the part that can become O(n^2). if (giverTiles.Count < takerTiles.Count) { // as an optimization, we choose one of two methods based on which list is smaller. We really want to avoid O(n^2) if we can. var queue = new List <TileAtmosphere>(takerTiles.Count); foreach (var giver in giverTiles) { giver._tileAtmosInfo.CurrentTransferDirection = (Direction)(-1); giver._tileAtmosInfo.CurrentTransferAmount = 0; var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; queue.Clear(); queue.Add(giver); giver._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; var queueCount = queue.Count; for (var i = 0; i < queueCount; i++) { if (giver._tileAtmosInfo.MoleDelta <= 0) { break; // We're done here now. Let's not do more work than needed. } var tile = queue[i]; foreach (var direction in Cardinal) { if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } if (giver._tileAtmosInfo.MoleDelta <= 0) { break; // We're done here now. Let's not do more work than needed. } if (tile2?._tileAtmosInfo == null || tile2._tileAtmosInfo.LastQueueCycle != queueCycle) { continue; } if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) { continue; } queue.Add(tile2); queueCount++; tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2._tileAtmosInfo.CurrentTransferAmount = 0; if (tile2._tileAtmosInfo.MoleDelta < 0) { // This tile needs gas. Let's give it to 'em. if (-tile2._tileAtmosInfo.MoleDelta > giver._tileAtmosInfo.MoleDelta) { // We don't have enough gas! tile2._tileAtmosInfo.CurrentTransferAmount -= giver._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta += giver._tileAtmosInfo.MoleDelta; giver._tileAtmosInfo.MoleDelta = 0; } else { // We have enough gas. tile2._tileAtmosInfo.CurrentTransferAmount += tile2._tileAtmosInfo.MoleDelta; giver._tileAtmosInfo.MoleDelta += tile2._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta = 0; } } } } // Putting this loop here helps make it O(n^2) over O(n^3) for (var i = queue.Count - 1; i >= 0; i--) { var tile = queue[i]; if (tile._tileAtmosInfo.CurrentTransferAmount != 0 && tile._tileAtmosInfo.CurrentTransferDirection != (Direction)(-1)) { tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount); if (tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection, out var adjacent)) { adjacent._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; } tile._tileAtmosInfo.CurrentTransferAmount = 0; } } } } else { var queue = new List <TileAtmosphere>(giverTiles.Count); foreach (var taker in takerTiles) { taker._tileAtmosInfo.CurrentTransferDirection = Direction.Invalid; taker._tileAtmosInfo.CurrentTransferAmount = 0; var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; queue.Clear(); queue.Add(taker); taker._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; var queueCount = queue.Count; for (int i = 0; i < queueCount; i++) { if (taker._tileAtmosInfo.MoleDelta >= 0) { break; // We're done here now. Let's not do more work than needed. } var tile = queue[i]; foreach (var direction in Cardinal) { if (!tile._adjacentTiles.ContainsKey(direction)) { continue; } var tile2 = tile._adjacentTiles[direction]; if (taker._tileAtmosInfo.MoleDelta >= 0) { break; // We're done here now. Let's not do more work than needed. } if (tile2?._tileAtmosInfo == null || tile2._tileAtmosInfo.LastQueueCycle != queueCycle) { continue; } if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) { continue; } queue.Add(tile2); queueCount++; tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2._tileAtmosInfo.CurrentTransferAmount = 0; if (tile2._tileAtmosInfo.MoleDelta > 0) { // This tile has gas we can suck, so let's if (tile2._tileAtmosInfo.MoleDelta > -taker._tileAtmosInfo.MoleDelta) { // They have enough gas tile2._tileAtmosInfo.CurrentTransferAmount -= taker._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta += taker._tileAtmosInfo.MoleDelta; taker._tileAtmosInfo.MoleDelta = 0; } else { // They don't have enough gas! tile2._tileAtmosInfo.CurrentTransferAmount += tile2._tileAtmosInfo.MoleDelta; taker._tileAtmosInfo.MoleDelta += tile2._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta = 0; } } } } for (var i = queue.Count - 1; i >= 0; i--) { var tile = queue[i]; if (tile._tileAtmosInfo.CurrentTransferAmount == 0 || tile._tileAtmosInfo.CurrentTransferDirection == Direction.Invalid) { continue; } tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount); if (tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection, out var adjacent)) { adjacent._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; } tile._tileAtmosInfo.CurrentTransferAmount = 0; } } } foreach (var tile in tiles) { tile.FinalizeEq(); } foreach (var tile in tiles) { foreach (var direction in Cardinal) { if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } if (tile2?.Air?.Compare(Air) == GasMixture.GasCompareResult.NoExchange) { continue; } _gridAtmosphereComponent.AddActiveTile(tile2); break; } } } }
public void EqualizePressureInZone(int cycleNum) { if (Air == null || (_tileAtmosInfo.LastCycle >= cycleNum)) return; // Already done. _tileAtmosInfo = new TileAtmosInfo(); var startingMoles = Air.TotalMoles; var runAtmos = false; // We need to figure if this is necessary for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); if (!_adjacentBits.HasFlag(direction)) continue; var other = _adjacentTiles[i]; if (other?.Air == null) continue; var comparisonMoles = other.Air.TotalMoles; if (!(MathF.Abs(comparisonMoles - startingMoles) > Atmospherics.MinimumMolesDeltaToMove)) continue; runAtmos = true; break; } if (!runAtmos) // There's no need so we don't bother. { _tileAtmosInfo.LastCycle = cycleNum; return; } var queueCycle = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var totalMoles = 0f; var tiles = ArrayPool<TileAtmosphere>.Shared.Rent(Atmospherics.ZumosHardTileLimit); tiles[0] = this; _tileAtmosInfo.LastQueueCycle = queueCycle; var tileCount = 1; for (var i = 0; i < tileCount; i++) { if (i > Atmospherics.ZumosHardTileLimit) break; var exploring = tiles[i]; if (i < Atmospherics.ZumosTileLimit) { var tileMoles = exploring.Air.TotalMoles; exploring._tileAtmosInfo.MoleDelta = tileMoles; totalMoles += tileMoles; } for (var j = 0; j < Atmospherics.Directions; j++) { var direction = (AtmosDirection) (1 << j); if (!exploring._adjacentBits.HasFlag(direction)) continue; var adj = exploring._adjacentTiles[j]; if (adj?.Air == null) continue; if(adj._tileAtmosInfo.LastQueueCycle == queueCycle) continue; adj._tileAtmosInfo = new TileAtmosInfo {LastQueueCycle = queueCycle}; if(tileCount < Atmospherics.ZumosHardTileLimit) tiles[tileCount++] = adj; if (adj.Air.Immutable) { // Looks like someone opened an airlock to space! ExplosivelyDepressurize(cycleNum); return; } } } if (tileCount > Atmospherics.ZumosTileLimit) { for (var i = Atmospherics.ZumosTileLimit; i < tileCount; i++) { //We unmark them. We shouldn't be pushing/pulling gases to/from them. var tile = tiles[i]; if (tile == null) continue; tiles[i]._tileAtmosInfo.LastQueueCycle = 0; } tileCount = Atmospherics.ZumosTileLimit; } //tiles = tiles.AsSpan().Slice(0, tileCount).ToArray(); // According to my benchmarks, this is much slower. //Array.Resize(ref tiles, tileCount); var averageMoles = totalMoles / (tileCount); var giverTiles = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount); var takerTiles = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount); var giverTilesLength = 0; var takerTilesLength = 0; for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; tile._tileAtmosInfo.LastCycle = cycleNum; tile._tileAtmosInfo.MoleDelta -= averageMoles; if (tile._tileAtmosInfo.MoleDelta > 0) { giverTiles[giverTilesLength++] = tile; } else { takerTiles[takerTilesLength++] = tile; } } var logN = MathF.Log2(tileCount); // Optimization - try to spread gases using an O(nlogn) algorithm that has a chance of not working first to avoid O(n^2) if (giverTilesLength > logN && takerTilesLength > logN) { // Even if it fails, it will speed up the next part. Array.Sort(tiles, 0, tileCount, Comparer); for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; tile._tileAtmosInfo.FastDone = true; if (!(tile._tileAtmosInfo.MoleDelta > 0)) continue; var eligibleDirections = AtmosDirection.Invalid; var eligibleDirectionCount = 0; for (var j = 0; j < Atmospherics.Directions; j++) { var direction = (AtmosDirection) (1 << j); if (!tile._adjacentBits.HasFlag(direction)) continue; var tile2 = tile._adjacentTiles[j]; // skip anything that isn't part of our current processing block. if (tile2._tileAtmosInfo.FastDone || tile2._tileAtmosInfo.LastQueueCycle != queueCycle) continue; eligibleDirections |= direction; eligibleDirectionCount++; } if (eligibleDirectionCount <= 0) continue; // Oof we've painted ourselves into a corner. Bad luck. Next part will handle this. var molesToMove = tile._tileAtmosInfo.MoleDelta / eligibleDirectionCount; for (var j = 0; j < Atmospherics.Directions; j++) { var direction = (AtmosDirection) (1 << j); if (!eligibleDirections.HasFlag(direction)) continue; tile.AdjustEqMovement(direction, molesToMove); tile._tileAtmosInfo.MoleDelta -= molesToMove; tile._adjacentTiles[j]._tileAtmosInfo.MoleDelta += molesToMove; } } giverTilesLength = 0; takerTilesLength = 0; for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; if (tile._tileAtmosInfo.MoleDelta > 0) { giverTiles[giverTilesLength++] = tile; } else { takerTiles[takerTilesLength++] = tile; } } // This is the part that can become O(n^2). if (giverTilesLength < takerTilesLength) { // as an optimization, we choose one of two methods based on which list is smaller. We really want to avoid O(n^2) if we can. var queue = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount); for (var j = 0; j < giverTilesLength; j++) { var giver = giverTiles[j]; giver._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid; giver._tileAtmosInfo.CurrentTransferAmount = 0; var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var queueLength = 0; queue[queueLength++] = giver; giver._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; for (var i = 0; i < queueLength; i++) { if (giver._tileAtmosInfo.MoleDelta <= 0) break; // We're done here now. Let's not do more work than needed. var tile = queue[i]; for (var k = 0; k < Atmospherics.Directions; k++) { var direction = (AtmosDirection) (1 << k); if (!tile._adjacentBits.HasFlag(direction)) continue; var tile2 = tile._adjacentTiles[k]; if (giver._tileAtmosInfo.MoleDelta <= 0) break; // We're done here now. Let's not do more work than needed. if (tile2._tileAtmosInfo.LastQueueCycle != queueCycle) continue; if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) continue; queue[queueLength++] = tile2; tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2._tileAtmosInfo.CurrentTransferAmount = 0; if (tile2._tileAtmosInfo.MoleDelta < 0) { // This tile needs gas. Let's give it to 'em. if (-tile2._tileAtmosInfo.MoleDelta > giver._tileAtmosInfo.MoleDelta) { // We don't have enough gas! tile2._tileAtmosInfo.CurrentTransferAmount -= giver._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta += giver._tileAtmosInfo.MoleDelta; giver._tileAtmosInfo.MoleDelta = 0; } else { // We have enough gas. tile2._tileAtmosInfo.CurrentTransferAmount += tile2._tileAtmosInfo.MoleDelta; giver._tileAtmosInfo.MoleDelta += tile2._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta = 0; } } } } // Putting this loop here helps make it O(n^2) over O(n^3) for (var i = queueLength - 1; i >= 0; i--) { var tile = queue[i]; if (tile._tileAtmosInfo.CurrentTransferAmount != 0 && tile._tileAtmosInfo.CurrentTransferDirection != AtmosDirection.Invalid) { tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount); tile._adjacentTiles[tile._tileAtmosInfo.CurrentTransferDirection.ToIndex()] ._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; tile._tileAtmosInfo.CurrentTransferAmount = 0; } } } ArrayPool<TileAtmosphere>.Shared.Return(queue); } else { var queue = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount); for (var j = 0; j < takerTilesLength; j++) { var taker = takerTiles[j]; taker._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid; taker._tileAtmosInfo.CurrentTransferAmount = 0; var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var queueLength = 0; queue[queueLength++] = taker; taker._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; for (var i = 0; i < queueLength; i++) { if (taker._tileAtmosInfo.MoleDelta >= 0) break; // We're done here now. Let's not do more work than needed. var tile = queue[i]; for (var k = 0; k < Atmospherics.Directions; k++) { var direction = (AtmosDirection) (1 << k); if (!tile._adjacentBits.HasFlag(direction)) continue; var tile2 = tile._adjacentTiles[k]; if (taker._tileAtmosInfo.MoleDelta >= 0) break; // We're done here now. Let's not do more work than needed. if (tile2._tileAtmosInfo.LastQueueCycle != queueCycle) continue; if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) continue; queue[queueLength++] = tile2; tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2._tileAtmosInfo.CurrentTransferAmount = 0; if (tile2._tileAtmosInfo.MoleDelta > 0) { // This tile has gas we can suck, so let's if (tile2._tileAtmosInfo.MoleDelta > -taker._tileAtmosInfo.MoleDelta) { // They have enough gas tile2._tileAtmosInfo.CurrentTransferAmount -= taker._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta += taker._tileAtmosInfo.MoleDelta; taker._tileAtmosInfo.MoleDelta = 0; } else { // They don't have enough gas! tile2._tileAtmosInfo.CurrentTransferAmount += tile2._tileAtmosInfo.MoleDelta; taker._tileAtmosInfo.MoleDelta += tile2._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta = 0; } } } } for (var i = queueLength - 1; i >= 0; i--) { var tile = queue[i]; if (tile._tileAtmosInfo.CurrentTransferAmount == 0 || tile._tileAtmosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue; tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount); tile._adjacentTiles[tile._tileAtmosInfo.CurrentTransferDirection.ToIndex()] ._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; tile._tileAtmosInfo.CurrentTransferAmount = 0; } } ArrayPool<TileAtmosphere>.Shared.Return(queue); } for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; tile.FinalizeEq(); } for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; for (var j = 0; j < Atmospherics.Directions; j++) { var direction = (AtmosDirection) (1 << j); if (!tile._adjacentBits.HasFlag(direction)) continue; var tile2 = tile._adjacentTiles[j]; if (tile2?.Air?.Compare(Air) == GasMixture.GasCompareResult.NoExchange) continue; _gridAtmosphereComponent.AddActiveTile(tile2); break; } } ArrayPool<TileAtmosphere>.Shared.Return(tiles); ArrayPool<TileAtmosphere>.Shared.Return(giverTiles); ArrayPool<TileAtmosphere>.Shared.Return(takerTiles); } }