Fix tile equalization terrible mistake

This commit is contained in:
Vera Aguilera Puerto
2020-12-05 14:19:36 +01:00
parent 8dd59fe3d7
commit 983aa9ed0f

View File

@@ -401,171 +401,171 @@ namespace Content.Server.Atmos
takerTiles[takerTilesLength++] = tile; takerTiles[takerTilesLength++] = tile;
} }
} }
}
// This is the part that can become O(n^2). // This is the part that can become O(n^2).
if (giverTilesLength < takerTilesLength) 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++)
{ {
// 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 giver = giverTiles[j];
var queue = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount); giver._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
for (var j = 0; j < giverTilesLength; j++) 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]; if (giver._tileAtmosInfo.MoleDelta <= 0)
giver._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid; break; // We're done here now. Let's not do more work than needed.
giver._tileAtmosInfo.CurrentTransferAmount = 0;
var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var tile = queue[i];
var queueLength = 0; for (var k = 0; k < Atmospherics.Directions; k++)
queue[queueLength++] = giver;
giver._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow;
for (var i = 0; i < queueLength; i++)
{ {
if (giver._tileAtmosInfo.MoleDelta <= 0) var direction = (AtmosDirection) (1 << k);
break; // We're done here now. Let's not do more work than needed. 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]; queue[queueLength++] = tile2;
for (var k = 0; k < Atmospherics.Directions; k++) tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow;
tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite();
tile2._tileAtmosInfo.CurrentTransferAmount = 0;
if (tile2._tileAtmosInfo.MoleDelta < 0)
{ {
var direction = (AtmosDirection) (1 << k); // This tile needs gas. Let's give it to 'em.
if (!tile._adjacentBits.IsFlagSet(direction)) continue; if (-tile2._tileAtmosInfo.MoleDelta > giver._tileAtmosInfo.MoleDelta)
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. // We don't have enough gas!
if (-tile2._tileAtmosInfo.MoleDelta > giver._tileAtmosInfo.MoleDelta) tile2._tileAtmosInfo.CurrentTransferAmount -= giver._tileAtmosInfo.MoleDelta;
{ tile2._tileAtmosInfo.MoleDelta += giver._tileAtmosInfo.MoleDelta;
// We don't have enough gas! giver._tileAtmosInfo.MoleDelta = 0;
tile2._tileAtmosInfo.CurrentTransferAmount -= giver._tileAtmosInfo.MoleDelta; }
tile2._tileAtmosInfo.MoleDelta += giver._tileAtmosInfo.MoleDelta; else
giver._tileAtmosInfo.MoleDelta = 0; {
} // We have enough gas.
else tile2._tileAtmosInfo.CurrentTransferAmount += tile2._tileAtmosInfo.MoleDelta;
{ giver._tileAtmosInfo.MoleDelta += tile2._tileAtmosInfo.MoleDelta;
// We have enough gas. tile2._tileAtmosInfo.MoleDelta = 0;
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); // Putting this loop here helps make it O(n^2) over O(n^3)
} for (var i = queueLength - 1; i >= 0; i--)
else
{
var queue = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount);
for (var j = 0; j < takerTilesLength; j++)
{ {
var taker = takerTiles[j]; var tile = queue[i];
taker._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid; if (tile._tileAtmosInfo.CurrentTransferAmount != 0 && tile._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.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.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount);
tile._adjacentTiles[tile._tileAtmosInfo.CurrentTransferDirection.ToIndex()] tile._adjacentTiles[tile._tileAtmosInfo.CurrentTransferDirection.ToIndex()]
._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; ._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount;
tile._tileAtmosInfo.CurrentTransferAmount = 0; tile._tileAtmosInfo.CurrentTransferAmount = 0;
} }
} }
ArrayPool<TileAtmosphere>.Shared.Return(queue);
} }
for (var i = 0; i < tileCount; i++) ArrayPool<TileAtmosphere>.Shared.Return(queue);
}
else
{
var queue = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount);
for (var j = 0; j < takerTilesLength; j++)
{ {
var tile = tiles[i]; var taker = takerTiles[j];
tile.FinalizeEq(); taker._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
} taker._tileAtmosInfo.CurrentTransferAmount = 0;
var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl;
for (var i = 0; i < tileCount; i++) var queueLength = 0;
{ queue[queueLength++] = taker;
var tile = tiles[i]; taker._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow;
for (var j = 0; j < Atmospherics.Directions; j++) for (var i = 0; i < queueLength; i++)
{ {
var direction = (AtmosDirection) (1 << j); if (taker._tileAtmosInfo.MoleDelta >= 0)
if (!tile._adjacentBits.IsFlagSet(direction)) continue; break; // We're done here now. Let's not do more work than needed.
var tile2 = tile._adjacentTiles[j];
if (tile2?.Air?.Compare(Air) == GasMixture.GasCompareResult.NoExchange) continue; var tile = queue[i];
_gridAtmosphereComponent.AddActiveTile(tile2); for (var k = 0; k < Atmospherics.Directions; k++)
break; {
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<TileAtmosphere>.Shared.Return(tiles); ArrayPool<TileAtmosphere>.Shared.Return(queue);
ArrayPool<TileAtmosphere>.Shared.Return(giverTiles);
ArrayPool<TileAtmosphere>.Shared.Return(takerTiles);
} }
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<TileAtmosphere>.Shared.Return(tiles);
ArrayPool<TileAtmosphere>.Shared.Return(giverTiles);
ArrayPool<TileAtmosphere>.Shared.Return(takerTiles);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]