From 983aa9ed0f163d414f81fa7806f19e21d2371656 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Sat, 5 Dec 2020 14:19:36 +0100 Subject: [PATCH] Fix tile equalization terrible mistake --- Content.Server/Atmos/TileAtmosphere.cs | 274 ++++++++++++------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs index aa71837fdc..e56b03ecbb 100644 --- a/Content.Server/Atmos/TileAtmosphere.cs +++ b/Content.Server/Atmos/TileAtmosphere.cs @@ -401,171 +401,171 @@ namespace Content.Server.Atmos takerTiles[takerTilesLength++] = tile; } } + } - // This is the part that can become O(n^2). - if (giverTilesLength < takerTilesLength) + // 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.Shared.Rent(tileCount); + for (var j = 0; j < giverTilesLength; j++) { - // 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.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++) { - 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++) { - if (giver._tileAtmosInfo.MoleDelta <= 0) - break; // We're done here now. Let's not do more work than needed. + var direction = (AtmosDirection) (1 << k); + if (!tile._adjacentBits.IsFlagSet(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; - var tile = queue[i]; - for (var k = 0; k < Atmospherics.Directions; k++) + queue[queueLength++] = tile2; + tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; + tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); + tile2._tileAtmosInfo.CurrentTransferAmount = 0; + if (tile2._tileAtmosInfo.MoleDelta < 0) { - var direction = (AtmosDirection) (1 << k); - if (!tile._adjacentBits.IsFlagSet(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) { - // 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; - } + // 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.Shared.Return(queue); - } - else - { - var queue = ArrayPool.Shared.Rent(tileCount); - for (var j = 0; j < takerTilesLength; j++) + // Putting this loop here helps make it O(n^2) over O(n^3) + for (var i = queueLength - 1; i >= 0; i--) { - 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++) + var tile = queue[i]; + if (tile._tileAtmosInfo.CurrentTransferAmount != 0 && tile._tileAtmosInfo.CurrentTransferDirection != AtmosDirection.Invalid) { - 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.IsFlagSet(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.Shared.Return(queue); } - for (var i = 0; i < tileCount; i++) + ArrayPool.Shared.Return(queue); + } + else + { + var queue = ArrayPool.Shared.Rent(tileCount); + for (var j = 0; j < takerTilesLength; j++) { - 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 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++) { - var direction = (AtmosDirection) (1 << j); - if (!tile._adjacentBits.IsFlagSet(direction)) continue; - var tile2 = tile._adjacentTiles[j]; - if (tile2?.Air?.Compare(Air) == GasMixture.GasCompareResult.NoExchange) continue; - _gridAtmosphereComponent.AddActiveTile(tile2); - break; + 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.IsFlagSet(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.Shared.Return(tiles); - ArrayPool.Shared.Return(giverTiles); - ArrayPool.Shared.Return(takerTiles); + ArrayPool.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.IsFlagSet(direction)) continue; + var tile2 = tile._adjacentTiles[j]; + if (tile2?.Air?.Compare(Air) == GasMixture.GasCompareResult.NoExchange) continue; + _gridAtmosphereComponent.AddActiveTile(tile2); + break; + } + } + + ArrayPool.Shared.Return(tiles); + ArrayPool.Shared.Return(giverTiles); + ArrayPool.Shared.Return(takerTiles); } [MethodImpl(MethodImplOptions.AggressiveInlining)]