Files
crystall-punk-14/Content.Server/Explosion/EntitySystems/ExplosionTileFlood.cs

199 lines
7.9 KiB
C#
Raw Permalink Normal View History

Explosion refactor (#5230) * Explosions * fix yaml typo and prevent silly UI inputs * oop * Use modified contains() checks And remove IEnumerable * Buff nuke, nerf meteors * optimize the entity lookup stuff a bit * fix tile (0,0) error forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile. * remove celebration * byte -> int * remove diag edge tile dict * fix one bug but there is another * fix the other bug turns out dividing a ushort leads to rounding errors. Why TF is the grid tile size even a ushort in the first place. * improve edge map * fix minor bug If the initial-explosion tile had an airtight entity on it, the tile was processed twice. * some reviews (transform queries, eye.mapid, and tilesizes in overlays) * Apply suggestions from code review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * is map paused * GetAllTiles ignores space by default * WriteLine -> WriteError * First -> FirstOrDefault() * default prototype const string * entity query * misc review changes * grid edge max distance * fix fire texture defn bad use of type serializer and ioc-resolves * Remove ExplosionLaunched And allow nukes to throw items towards the outer part of an explosion * no hot-reload disclaimer * replace prototype id string with int index * optimise damage a tiiiiny bit. * entity queries * comments * misc mirror comments * cvars * admin logs * move intensity-per-state to prototype * update tile event to ECS event * git mv * Tweak rpg & minibomb also fix merge bug * you don't exist anymore go away * Fix build Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-04-01 15:39:26 +13:00
using Content.Shared.Atmos;
using System.Runtime.CompilerServices;
namespace Content.Server.Explosion.EntitySystems;
/// <summary>
2022-04-05 19:22:35 +12:00
/// This class exists to facilitate the iterative neighbor-finding / flooding algorithm used by explosions in <see
/// cref="ExplosionSystem.GetExplosionTiles"/>. This is the base class for <see cref="ExplosionSpaceTileFlood"/> and
/// <see cref="ExplosionGridTileFlood"/>, each of which contains additional code fro logic specific to grids or space.
Explosion refactor (#5230) * Explosions * fix yaml typo and prevent silly UI inputs * oop * Use modified contains() checks And remove IEnumerable * Buff nuke, nerf meteors * optimize the entity lookup stuff a bit * fix tile (0,0) error forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile. * remove celebration * byte -> int * remove diag edge tile dict * fix one bug but there is another * fix the other bug turns out dividing a ushort leads to rounding errors. Why TF is the grid tile size even a ushort in the first place. * improve edge map * fix minor bug If the initial-explosion tile had an airtight entity on it, the tile was processed twice. * some reviews (transform queries, eye.mapid, and tilesizes in overlays) * Apply suggestions from code review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * is map paused * GetAllTiles ignores space by default * WriteLine -> WriteError * First -> FirstOrDefault() * default prototype const string * entity query * misc review changes * grid edge max distance * fix fire texture defn bad use of type serializer and ioc-resolves * Remove ExplosionLaunched And allow nukes to throw items towards the outer part of an explosion * no hot-reload disclaimer * replace prototype id string with int index * optimise damage a tiiiiny bit. * entity queries * comments * misc mirror comments * cvars * admin logs * move intensity-per-state to prototype * update tile event to ECS event * git mv * Tweak rpg & minibomb also fix merge bug * you don't exist anymore go away * Fix build Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-04-01 15:39:26 +13:00
/// </summary>
2022-04-05 19:22:35 +12:00
/// <remarks>
/// The class stores information about the tiles that the explosion has currently reached, and provides functions to
/// perform a neighbor-finding iteration to expand the explosion area. It also has some functionality that allows
/// tiles to move between grids/space.
/// </remarks>
public abstract class ExplosionTileFlood
Explosion refactor (#5230) * Explosions * fix yaml typo and prevent silly UI inputs * oop * Use modified contains() checks And remove IEnumerable * Buff nuke, nerf meteors * optimize the entity lookup stuff a bit * fix tile (0,0) error forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile. * remove celebration * byte -> int * remove diag edge tile dict * fix one bug but there is another * fix the other bug turns out dividing a ushort leads to rounding errors. Why TF is the grid tile size even a ushort in the first place. * improve edge map * fix minor bug If the initial-explosion tile had an airtight entity on it, the tile was processed twice. * some reviews (transform queries, eye.mapid, and tilesizes in overlays) * Apply suggestions from code review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * is map paused * GetAllTiles ignores space by default * WriteLine -> WriteError * First -> FirstOrDefault() * default prototype const string * entity query * misc review changes * grid edge max distance * fix fire texture defn bad use of type serializer and ioc-resolves * Remove ExplosionLaunched And allow nukes to throw items towards the outer part of an explosion * no hot-reload disclaimer * replace prototype id string with int index * optimise damage a tiiiiny bit. * entity queries * comments * misc mirror comments * cvars * admin logs * move intensity-per-state to prototype * update tile event to ECS event * git mv * Tweak rpg & minibomb also fix merge bug * you don't exist anymore go away * Fix build Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-04-01 15:39:26 +13:00
{
// Main tile data sets, mapping iterations onto tile lists
public Dictionary<int, List<Vector2i>> TileLists = new();
protected Dictionary<int, List<Vector2i>> BlockedTileLists = new();
protected Dictionary<int, HashSet<Vector2i>> FreedTileLists = new();
// The new tile lists added each iteration. I **could** just pass these along to every function, but IMO it is more
// readable if they are just private variables.
protected List<Vector2i> NewTiles = default!;
protected List<Vector2i> NewBlockedTiles = default!;
protected HashSet<Vector2i> NewFreedTiles = default!;
// HashSets used to ensure uniqueness of tiles. Prevents the explosion from looping back in on itself.
protected UniqueVector2iSet ProcessedTiles = new();
protected UniqueVector2iSet UnenteredBlockedTiles = new();
protected UniqueVector2iSet EnteredBlockedTiles = new();
public abstract void InitTile(Vector2i initialTile);
protected abstract void ProcessNewTile(int iteration, Vector2i tile, AtmosDirection entryDirections);
protected abstract AtmosDirection GetUnblockedDirectionOrAll(Vector2i tile);
protected void AddNewDiagonalTiles(int iteration, IEnumerable<Vector2i> tiles, bool ignoreLocalBlocker = false)
{
AtmosDirection entryDirection = AtmosDirection.Invalid;
foreach (var tile in tiles)
{
var freeDirections = ignoreLocalBlocker ? AtmosDirection.All : GetUnblockedDirectionOrAll(tile);
// Get the free directions of the directly adjacent tiles
Explosion refactor (#5230) * Explosions * fix yaml typo and prevent silly UI inputs * oop * Use modified contains() checks And remove IEnumerable * Buff nuke, nerf meteors * optimize the entity lookup stuff a bit * fix tile (0,0) error forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile. * remove celebration * byte -> int * remove diag edge tile dict * fix one bug but there is another * fix the other bug turns out dividing a ushort leads to rounding errors. Why TF is the grid tile size even a ushort in the first place. * improve edge map * fix minor bug If the initial-explosion tile had an airtight entity on it, the tile was processed twice. * some reviews (transform queries, eye.mapid, and tilesizes in overlays) * Apply suggestions from code review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * is map paused * GetAllTiles ignores space by default * WriteLine -> WriteError * First -> FirstOrDefault() * default prototype const string * entity query * misc review changes * grid edge max distance * fix fire texture defn bad use of type serializer and ioc-resolves * Remove ExplosionLaunched And allow nukes to throw items towards the outer part of an explosion * no hot-reload disclaimer * replace prototype id string with int index * optimise damage a tiiiiny bit. * entity queries * comments * misc mirror comments * cvars * admin logs * move intensity-per-state to prototype * update tile event to ECS event * git mv * Tweak rpg & minibomb also fix merge bug * you don't exist anymore go away * Fix build Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-04-01 15:39:26 +13:00
var freeDirectionsN = GetUnblockedDirectionOrAll(tile.Offset(AtmosDirection.North));
var freeDirectionsE = GetUnblockedDirectionOrAll(tile.Offset(AtmosDirection.East));
var freeDirectionsS = GetUnblockedDirectionOrAll(tile.Offset(AtmosDirection.South));
var freeDirectionsW = GetUnblockedDirectionOrAll(tile.Offset(AtmosDirection.West));
// North East
if (freeDirections.IsFlagSet(AtmosDirection.North) && freeDirectionsN.IsFlagSet(AtmosDirection.SouthEast))
entryDirection |= AtmosDirection.West;
if (freeDirections.IsFlagSet(AtmosDirection.East) && freeDirectionsE.IsFlagSet(AtmosDirection.NorthWest))
entryDirection |= AtmosDirection.South;
if (entryDirection != AtmosDirection.Invalid)
{
ProcessNewTile(iteration, tile + (1, 1), entryDirection);
entryDirection = AtmosDirection.Invalid;
}
// North West
if (freeDirections.IsFlagSet(AtmosDirection.North) && freeDirectionsN.IsFlagSet(AtmosDirection.SouthWest))
entryDirection |= AtmosDirection.East;
if (freeDirections.IsFlagSet(AtmosDirection.West) && freeDirectionsW.IsFlagSet(AtmosDirection.NorthEast))
entryDirection |= AtmosDirection.West;
if (entryDirection != AtmosDirection.Invalid)
{
ProcessNewTile(iteration, tile + (-1, 1), entryDirection);
entryDirection = AtmosDirection.Invalid;
}
// South East
if (freeDirections.IsFlagSet(AtmosDirection.South) && freeDirectionsS.IsFlagSet(AtmosDirection.NorthEast))
entryDirection |= AtmosDirection.West;
if (freeDirections.IsFlagSet(AtmosDirection.East) && freeDirectionsE.IsFlagSet(AtmosDirection.SouthWest))
entryDirection |= AtmosDirection.North;
if (entryDirection != AtmosDirection.Invalid)
{
ProcessNewTile(iteration, tile + (1, -1), entryDirection);
entryDirection = AtmosDirection.Invalid;
}
// South West
if (freeDirections.IsFlagSet(AtmosDirection.South) && freeDirectionsS.IsFlagSet(AtmosDirection.NorthWest))
entryDirection |= AtmosDirection.West;
if (freeDirections.IsFlagSet(AtmosDirection.West) && freeDirectionsW.IsFlagSet(AtmosDirection.SouthEast))
entryDirection |= AtmosDirection.North;
if (entryDirection != AtmosDirection.Invalid)
{
ProcessNewTile(iteration, tile + (-1, -1), entryDirection);
entryDirection = AtmosDirection.Invalid;
}
}
}
/// <summary>
/// Merge all tile lists into a single output tile list.
/// </summary>
public void CleanUp()
{
foreach (var (iteration, blocked) in BlockedTileLists)
{
if (TileLists.TryGetValue(iteration, out var tiles))
tiles.AddRange(blocked);
else
TileLists[iteration] = blocked;
}
}
}
/// <summary>
/// This is a data structure can be used to ensure the uniqueness of Vector2i indices.
/// </summary>
/// <remarks>
/// This basically exists to replace the use of HashSet&lt;Vector2i&gt; if all you need is the the functions Contains()
Explosion refactor (#5230) * Explosions * fix yaml typo and prevent silly UI inputs * oop * Use modified contains() checks And remove IEnumerable * Buff nuke, nerf meteors * optimize the entity lookup stuff a bit * fix tile (0,0) error forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile. * remove celebration * byte -> int * remove diag edge tile dict * fix one bug but there is another * fix the other bug turns out dividing a ushort leads to rounding errors. Why TF is the grid tile size even a ushort in the first place. * improve edge map * fix minor bug If the initial-explosion tile had an airtight entity on it, the tile was processed twice. * some reviews (transform queries, eye.mapid, and tilesizes in overlays) * Apply suggestions from code review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * is map paused * GetAllTiles ignores space by default * WriteLine -> WriteError * First -> FirstOrDefault() * default prototype const string * entity query * misc review changes * grid edge max distance * fix fire texture defn bad use of type serializer and ioc-resolves * Remove ExplosionLaunched And allow nukes to throw items towards the outer part of an explosion * no hot-reload disclaimer * replace prototype id string with int index * optimise damage a tiiiiny bit. * entity queries * comments * misc mirror comments * cvars * admin logs * move intensity-per-state to prototype * update tile event to ECS event * git mv * Tweak rpg & minibomb also fix merge bug * you don't exist anymore go away * Fix build Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-04-01 15:39:26 +13:00
/// and Add(). This is both faster and apparently allocates less. Does not support iterating over contents
/// </remarks>
public sealed class UniqueVector2iSet
{
private const int ChunkSize = 32; // # of bits in an integer.
private Dictionary<Vector2i, VectorChunk> _chunks = new();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2i ToChunkIndices(Vector2i indices)
{
var x = (int) Math.Floor(indices.X / (float) ChunkSize);
var y = (int) Math.Floor(indices.Y / (float) ChunkSize);
return new Vector2i(x, y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Add(Vector2i index)
{
var chunkIndex = ToChunkIndices(index);
if (_chunks.TryGetValue(chunkIndex, out var chunk))
{
return chunk.Add(index);
}
chunk = new();
chunk.Add(index);
_chunks[chunkIndex] = chunk;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(Vector2i index)
{
if (!_chunks.TryGetValue(ToChunkIndices(index), out var chunk))
return false;
return chunk.Contains(index);
}
private sealed class VectorChunk
{
// 32*32 chunk represented via 32 ints with 32 bits each. Basic testing showed that this was faster than using
// 16-sized chunks with ushorts, a bool[,], or just having each chunk be a HashSet.
private readonly int[] _tiles = new int[ChunkSize];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Add(Vector2i index)
{
var x = MathHelper.Mod(index.X, ChunkSize);
var y = MathHelper.Mod(index.Y, ChunkSize);
var oldFlags = _tiles[x];
var newFlags = oldFlags | (1 << y);
if (newFlags == oldFlags)
return false;
_tiles[x] = newFlags;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(Vector2i index)
{
var x = MathHelper.Mod(index.X, ChunkSize);
var y = MathHelper.Mod(index.Y, ChunkSize);
return (_tiles[x] & (1 << y)) != 0;
}
}
}