mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 11:40:52 +01:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6cadfedd5 | ||
|
|
9f57b705d7 | ||
|
|
68be9712ad | ||
|
|
aaa446254c | ||
|
|
5e2d2ab317 | ||
|
|
20ae63fbbd | ||
|
|
a92c0cbef4 |
Submodule Arch/Arch updated: c4c96fbe4e...c76d18feb7
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
|
||||
|
||||
@@ -54,6 +54,22 @@ END TEMPLATE-->
|
||||
*None yet*
|
||||
|
||||
|
||||
## 182.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Add EntityUid's generation / version to the hashcode.
|
||||
|
||||
|
||||
## 181.0.2
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix exceptions from having too many lights on screen and causing the game to go black.
|
||||
* Fix components having events raised in ClientGameStateManager before fully set and causing nullable reference exceptions.
|
||||
* Replace tile intersection IEnumerables with TileEnumerator internally. Also made it public for external callers that wish to avoid IEnumerable.
|
||||
|
||||
|
||||
## 181.0.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
@@ -1306,13 +1306,23 @@ namespace Robust.Client.GameStates
|
||||
// To avoid shuffling the archetype we'll set the component range up-front.
|
||||
if (addedComps.Count > 0)
|
||||
{
|
||||
// TODO: This fucking sucks but
|
||||
// - Frequent archetype changes PER COMPONENT sucks
|
||||
// - the components will be null in event handlers until it's done.
|
||||
_entityManager.AddComponentRange(uid, addedCompTypes);
|
||||
|
||||
for (var i = 0; i < addedComps.Count; i++)
|
||||
{
|
||||
var comp = addedComps[i];
|
||||
var component = addedComps[i];
|
||||
var reg = addedRegistrations[i];
|
||||
_entityManager.AddComponentInternal(uid, comp, reg, false, meta);
|
||||
_entityManager.AddComponentInternalOnly(uid, component, reg, meta);
|
||||
}
|
||||
|
||||
for (var i = 0; i < addedComps.Count; i++)
|
||||
{
|
||||
var component = addedComps[i];
|
||||
var reg = addedRegistrations[i];
|
||||
_entityManager.AddComponentEvents(uid, component, reg, false, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private (PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot)[] _lightsToRenderList = default!;
|
||||
|
||||
private LightCapacityComparer _lightCap = new();
|
||||
private ShadowCapacityComparer _shadowCap = new ShadowCapacityComparer();
|
||||
|
||||
private unsafe void InitLighting()
|
||||
{
|
||||
|
||||
@@ -570,6 +573,28 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return true;
|
||||
}
|
||||
|
||||
private sealed class LightCapacityComparer : IComparer<(PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot)>
|
||||
{
|
||||
public int Compare(
|
||||
(PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot) x,
|
||||
(PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot) y)
|
||||
{
|
||||
if (x.light.CastShadows && !y.light.CastShadows) return 1;
|
||||
if (!x.light.CastShadows && y.light.CastShadows) return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ShadowCapacityComparer : IComparer<(PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot)>
|
||||
{
|
||||
public int Compare(
|
||||
(PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot) x,
|
||||
(PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot) y)
|
||||
{
|
||||
return x.distanceSquared.CompareTo(y.distanceSquared);
|
||||
}
|
||||
}
|
||||
|
||||
private (int count, Box2 expandedBounds) GetLightsToRender(
|
||||
MapId map,
|
||||
in Box2Rotated worldBounds,
|
||||
@@ -595,20 +620,10 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// First, partition the array based on whether the lights are shadow casting or not
|
||||
// (non shadow casting lights should be the first partition, shadow casting lights the second)
|
||||
Array.Sort(_lightsToRenderList, 0, state.count,
|
||||
Comparer<(PointLightComponent light, Vector2 pos, float distanceSquared)>.Create((x, y) =>
|
||||
{
|
||||
if (x.light.CastShadows && !y.light.CastShadows) return 1;
|
||||
else if (!x.light.CastShadows && y.light.CastShadows) return -1;
|
||||
else return 0;
|
||||
}));
|
||||
Array.Sort(_lightsToRenderList, 0, state.count, _lightCap);
|
||||
|
||||
// Next, sort just the shadow casting lights by distance.
|
||||
Array.Sort(_lightsToRenderList, state.count - state.shadowCastingCount, state.shadowCastingCount,
|
||||
Comparer<(PointLightComponent light, Vector2 pos, float distanceSquared)>.Create((x, y) =>
|
||||
{
|
||||
return x.distanceSquared.CompareTo(y.distanceSquared);
|
||||
}));
|
||||
Array.Sort(_lightsToRenderList, state.count - state.shadowCastingCount, state.shadowCastingCount, _shadowCap);
|
||||
|
||||
// Then effectively delete the furthest lights, by setting the end of the array to exclude N
|
||||
// number of shadow casting lights (where N is the number above the max number per scene.)
|
||||
|
||||
@@ -42,15 +42,20 @@ public sealed class TileEdgeOverlay : Overlay
|
||||
_grids.Clear();
|
||||
_mapManager.FindGridsIntersecting(args.MapId, args.WorldBounds, ref _grids);
|
||||
|
||||
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
||||
var mapSystem = _entManager.System<SharedMapSystem>();
|
||||
var xformSystem = _entManager.System<SharedTransformSystem>();
|
||||
|
||||
foreach (var grid in _grids)
|
||||
{
|
||||
var tileSize = grid.Comp.TileSize;
|
||||
var tileDimensions = new Vector2(tileSize, tileSize);
|
||||
var xform = xformQuery.GetComponent(grid);
|
||||
args.WorldHandle.SetTransform(xform.WorldMatrix);
|
||||
var (_, _, worldMatrix, invMatrix) = xformSystem.GetWorldPositionRotationMatrixWithInv(grid.Owner);
|
||||
args.WorldHandle.SetTransform(worldMatrix);
|
||||
var localAABB = invMatrix.TransformBox(args.WorldBounds);
|
||||
|
||||
foreach (var tileRef in grid.Comp.GetTilesIntersecting(args.WorldBounds, false))
|
||||
var enumerator = mapSystem.GetLocalTilesEnumerator(grid.Owner, grid.Comp, localAABB, false);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
var tileDef = _tileDefManager[tileRef.Tile.TypeId];
|
||||
|
||||
@@ -66,7 +71,7 @@ public sealed class TileEdgeOverlay : Overlay
|
||||
continue;
|
||||
|
||||
var neighborIndices = new Vector2i(tileRef.GridIndices.X + x, tileRef.GridIndices.Y + y);
|
||||
var neighborTile = grid.Comp.GetTileRef(neighborIndices);
|
||||
var neighborTile = mapSystem.GetTileRef(grid.Owner, grid.Comp, neighborIndices);
|
||||
var neighborDef = _tileDefManager[neighborTile.Tile.TypeId];
|
||||
|
||||
// If it's the same tile then no edge to be drawn.
|
||||
@@ -118,9 +123,9 @@ public sealed class TileEdgeOverlay : Overlay
|
||||
}
|
||||
|
||||
if (angle == Angle.Zero)
|
||||
args.WorldHandle.DrawTextureRect(texture, box);
|
||||
args.WorldHandle.DrawTextureRect(texture.Texture, box);
|
||||
else
|
||||
args.WorldHandle.DrawTextureRect(texture, new Box2Rotated(box, angle, box.Center));
|
||||
args.WorldHandle.DrawTextureRect(texture.Texture, new Box2Rotated(box, angle, box.Center));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,30 +5,26 @@ namespace Robust.Shared.GameObjects;
|
||||
|
||||
internal struct ArchetypeIterator
|
||||
{
|
||||
private readonly Query _query;
|
||||
private readonly PooledList<Archetype> _archetypes;
|
||||
|
||||
internal ArchetypeIterator(in Query query, PooledList<Archetype> archetypes)
|
||||
internal ArchetypeIterator(PooledList<Archetype> archetypes)
|
||||
{
|
||||
_query = query;
|
||||
_archetypes = archetypes;
|
||||
}
|
||||
|
||||
public ArchetypeEnumerator GetEnumerator()
|
||||
{
|
||||
return new ArchetypeEnumerator(_query, _archetypes);
|
||||
return new ArchetypeEnumerator(_archetypes);
|
||||
}
|
||||
}
|
||||
|
||||
internal struct ArchetypeEnumerator
|
||||
{
|
||||
private readonly Query _query;
|
||||
private readonly PooledList<Archetype> _archetypes;
|
||||
private int _index;
|
||||
|
||||
public ArchetypeEnumerator(in Query query, PooledList<Archetype> archetypes)
|
||||
public ArchetypeEnumerator(PooledList<Archetype> archetypes)
|
||||
{
|
||||
_query = query;
|
||||
_archetypes = archetypes;
|
||||
_index = _archetypes.Count;
|
||||
}
|
||||
@@ -38,7 +34,7 @@ internal struct ArchetypeEnumerator
|
||||
while (--_index >= 0)
|
||||
{
|
||||
var archetype = Current;
|
||||
if (archetype.Entities > 0)
|
||||
if (archetype.EntityCount > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ internal struct ArchChunkEnumerator
|
||||
|
||||
if (_archetypes.MoveNext())
|
||||
{
|
||||
_chunkIndex = _archetypes.Current.Size;
|
||||
_chunkIndex = _archetypes.Current.ChunkCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ internal struct ArchChunkEnumerator
|
||||
return false;
|
||||
}
|
||||
|
||||
_chunkIndex = _archetypes.Current.Size - 1;
|
||||
_chunkIndex = _archetypes.Current.ChunkCount - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ internal static partial class QueryExtensions
|
||||
{
|
||||
internal static ArchChunkIterator ChunkIterator(this in Query query, World world)
|
||||
{
|
||||
var archetypeEnumerator = new ArchetypeEnumerator(in query, query.Matches);
|
||||
var archetypeEnumerator = new ArchetypeEnumerator(query.Matches);
|
||||
return new ArchChunkIterator(in archetypeEnumerator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +222,9 @@ namespace Robust.Shared.GameObjects
|
||||
AddComponentInternal(uid, component, reg, skipInit, metadata);
|
||||
}
|
||||
|
||||
internal void AddComponentInternal<T>(EntityUid uid, T component, ComponentRegistration reg, bool skipInit, MetaDataComponent? metadata = null) where T : IComponent
|
||||
// TODO: Clean up this mess.
|
||||
|
||||
internal void AddComponentInternalOnly<T>(EntityUid uid, T component, ComponentRegistration reg, MetaDataComponent? metadata = null) where T : IComponent
|
||||
{
|
||||
// We can't use typeof(T) here in case T is just Component
|
||||
DebugTools.Assert(component is MetaDataComponent ||
|
||||
@@ -231,7 +233,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
// We can't use typeof(T) here in case T is just Component
|
||||
DebugTools.Assert(component is MetaDataComponent ||
|
||||
(metadata ?? MetaQuery.GetComponent(uid)).EntityLifeStage < EntityLifeStage.Terminating,
|
||||
(metadata ?? MetaQuery.GetComponent(uid)).EntityLifeStage < EntityLifeStage.Terminating,
|
||||
$"Attempted to add a {reg.Name} component to an entity ({ToPrettyString(uid)}) while it is terminating");
|
||||
|
||||
// TODO optimize this
|
||||
@@ -257,7 +259,11 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
component.Networked = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddComponentEvents<T>(EntityUid uid, T component, ComponentRegistration reg, bool skipInit,
|
||||
MetaDataComponent? metadata = null) where T : IComponent
|
||||
{
|
||||
var eventArgs = new AddedComponentEventArgs(new ComponentEventArgs(component, uid), reg);
|
||||
ComponentAdded?.Invoke(eventArgs);
|
||||
_eventBus.OnComponentAdded(eventArgs);
|
||||
@@ -285,6 +291,12 @@ namespace Robust.Shared.GameObjects
|
||||
EventBus.RaiseComponentEvent(component, MapInitEventInstance);
|
||||
}
|
||||
|
||||
internal void AddComponentInternal<T>(EntityUid uid, T component, ComponentRegistration reg, bool skipInit, MetaDataComponent? metadata = null) where T : IComponent
|
||||
{
|
||||
AddComponentInternalOnly(uid, component, reg, metadata);
|
||||
AddComponentEvents(uid, component, reg, skipInit, metadata);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool RemoveComponent<T>(EntityUid uid, MetaDataComponent? meta = null)
|
||||
@@ -724,6 +736,7 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
if (IsAlive(uid) && _world.TryGet(uid, out component))
|
||||
{
|
||||
DebugTools.Assert(component != null);
|
||||
if (!component!.Deleted)
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -115,7 +115,10 @@ namespace Robust.Shared.GameObjects
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Id;
|
||||
unchecked
|
||||
{
|
||||
return Id.GetHashCode() * 397 ^ Version.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -688,9 +688,8 @@ public abstract partial class SharedMapSystem
|
||||
|
||||
public IEnumerable<TileRef> GetAllTiles(EntityUid uid, MapGridComponent grid, bool ignoreEmpty = true)
|
||||
{
|
||||
foreach (var kvChunk in grid.Chunks)
|
||||
foreach (var chunk in grid.Chunks.Values)
|
||||
{
|
||||
var chunk = kvChunk.Value;
|
||||
for (ushort x = 0; x < grid.ChunkSize; x++)
|
||||
{
|
||||
for (ushort y = 0; y < grid.ChunkSize; y++)
|
||||
@@ -771,11 +770,54 @@ public abstract partial class SharedMapSystem
|
||||
RegenerateCollision(uid, grid, modified);
|
||||
}
|
||||
|
||||
public TilesEnumerator GetLocalTilesEnumerator(EntityUid uid, MapGridComponent grid, Box2 aabb,
|
||||
bool ignoreEmpty = true,
|
||||
Predicate<TileRef>? predicate = null)
|
||||
{
|
||||
var enumerator = new TilesEnumerator(this, ignoreEmpty, predicate, uid, grid, aabb);
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
public TilesEnumerator GetTilesEnumerator(EntityUid uid, MapGridComponent grid, Box2 aabb, bool ignoreEmpty = true,
|
||||
Predicate<TileRef>? predicate = null)
|
||||
{
|
||||
var invMatrix = _transform.GetInvWorldMatrix(uid);
|
||||
var localAABB = invMatrix.TransformBox(aabb);
|
||||
var enumerator = new TilesEnumerator(this, ignoreEmpty, predicate, uid, grid, localAABB);
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
public TilesEnumerator GetTilesEnumerator(EntityUid uid, MapGridComponent grid, Box2Rotated bounds, bool ignoreEmpty = true,
|
||||
Predicate<TileRef>? predicate = null)
|
||||
{
|
||||
var invMatrix = _transform.GetInvWorldMatrix(uid);
|
||||
var localAABB = invMatrix.TransformBox(bounds);
|
||||
var enumerator = new TilesEnumerator(this, ignoreEmpty, predicate, uid, grid, localAABB);
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
public IEnumerable<TileRef> GetLocalTilesIntersecting(EntityUid uid, MapGridComponent grid, Box2 localAABB, bool ignoreEmpty = true,
|
||||
Predicate<TileRef>? predicate = null)
|
||||
{
|
||||
var enumerator = new TilesEnumerator(this, ignoreEmpty, predicate, uid, grid, localAABB);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
yield return tileRef;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TileRef> GetLocalTilesIntersecting(EntityUid uid, MapGridComponent grid, Box2Rotated localArea, bool ignoreEmpty = true,
|
||||
Predicate<TileRef>? predicate = null)
|
||||
{
|
||||
var localAABB = localArea.CalcBoundingBox();
|
||||
return GetLocalTilesIntersecting(uid, grid, localAABB, ignoreEmpty, predicate);
|
||||
|
||||
var enumerator = new TilesEnumerator(this, ignoreEmpty, predicate, uid, grid, localAABB);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
yield return tileRef;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TileRef> GetTilesIntersecting(EntityUid uid, MapGridComponent grid, Box2Rotated worldArea, bool ignoreEmpty = true,
|
||||
@@ -784,9 +826,11 @@ public abstract partial class SharedMapSystem
|
||||
var matrix = _transform.GetInvWorldMatrix(uid);
|
||||
var localArea = matrix.TransformBox(worldArea);
|
||||
|
||||
foreach (var tile in GetLocalTilesIntersecting(uid, grid, localArea, ignoreEmpty, predicate))
|
||||
var enumerator = new TilesEnumerator(this, ignoreEmpty, predicate, uid, grid, localArea);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
yield return tile;
|
||||
yield return tileRef;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,46 +840,11 @@ public abstract partial class SharedMapSystem
|
||||
var matrix = _transform.GetInvWorldMatrix(uid);
|
||||
var localArea = matrix.TransformBox(worldArea);
|
||||
|
||||
foreach (var tile in GetLocalTilesIntersecting(uid, grid, localArea, ignoreEmpty, predicate))
|
||||
var enumerator = new TilesEnumerator(this, ignoreEmpty, predicate, uid, grid, localArea);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
yield return tile;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TileRef> GetLocalTilesIntersecting(EntityUid uid, MapGridComponent grid, Box2 localArea, bool ignoreEmpty = true,
|
||||
Predicate<TileRef>? predicate = null)
|
||||
{
|
||||
// TODO: Should move the intersecting calls onto mapmanager system and then allow people to pass in xform / xformquery
|
||||
// that way we can avoid the GetComp here.
|
||||
var gridTileLb = new Vector2i((int)Math.Floor(localArea.Left), (int)Math.Floor(localArea.Bottom));
|
||||
// If we have 20.1 we want to include that tile but if we have 20 then we don't.
|
||||
var gridTileRt = new Vector2i((int)Math.Ceiling(localArea.Right), (int)Math.Ceiling(localArea.Top));
|
||||
|
||||
for (var x = gridTileLb.X; x < gridTileRt.X; x++)
|
||||
{
|
||||
for (var y = gridTileLb.Y; y < gridTileRt.Y; y++)
|
||||
{
|
||||
var gridChunk = GridTileToChunkIndices(uid, grid, new Vector2i(x, y));
|
||||
|
||||
if (grid.Chunks.TryGetValue(gridChunk, out var chunk))
|
||||
{
|
||||
var chunkTile = chunk.GridTileToChunkTile(new Vector2i(x, y));
|
||||
var tile = GetTileRef(uid, grid, chunk, (ushort)chunkTile.X, (ushort)chunkTile.Y);
|
||||
|
||||
if (ignoreEmpty && tile.Tile.IsEmpty)
|
||||
continue;
|
||||
|
||||
if (predicate == null || predicate(tile))
|
||||
yield return tile;
|
||||
}
|
||||
else if (!ignoreEmpty)
|
||||
{
|
||||
var tile = new TileRef(uid, x, y, Tile.Empty);
|
||||
|
||||
if (predicate == null || predicate(tile))
|
||||
yield return tile;
|
||||
}
|
||||
}
|
||||
yield return tileRef;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,22 +1029,32 @@ public abstract partial class SharedMapSystem
|
||||
|
||||
public IEnumerable<EntityUid> GetLocalAnchoredEntities(EntityUid uid, MapGridComponent grid, Box2 localAABB)
|
||||
{
|
||||
foreach (var tile in GetLocalTilesIntersecting(uid, grid, localAABB, true, null))
|
||||
var enumerator = new TilesEnumerator(this, true, null, uid, grid, localAABB);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
foreach (var ent in GetAnchoredEntities(uid, grid, tile.GridIndices))
|
||||
var anchoredEnumerator = GetAnchoredEntitiesEnumerator(uid, grid, tileRef.GridIndices);
|
||||
|
||||
while (anchoredEnumerator.MoveNext(out var ent))
|
||||
{
|
||||
yield return ent;
|
||||
yield return ent.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityUid> GetAnchoredEntities(EntityUid uid, MapGridComponent grid, Box2 worldAABB)
|
||||
{
|
||||
foreach (var tile in GetTilesIntersecting(uid, grid, worldAABB))
|
||||
var invWorldMatrix = _transform.GetInvWorldMatrix(uid);
|
||||
var localAABB = invWorldMatrix.TransformBox(worldAABB);
|
||||
var enumerator = new TilesEnumerator(this, true, null, uid, grid, localAABB);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
foreach (var ent in GetAnchoredEntities(uid, grid, tile.GridIndices))
|
||||
var anchoredEnumerator = GetAnchoredEntitiesEnumerator(uid, grid, tileRef.GridIndices);
|
||||
|
||||
while (anchoredEnumerator.MoveNext(out var ent))
|
||||
{
|
||||
yield return ent;
|
||||
yield return ent.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1422,4 +1441,98 @@ public abstract partial class SharedMapSystem
|
||||
RegenerateCollision(uid, grid, mapChunk);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates the local tiles of the specified data.
|
||||
/// </summary>
|
||||
public struct TilesEnumerator
|
||||
{
|
||||
private readonly SharedMapSystem _mapSystem;
|
||||
|
||||
private readonly EntityUid _uid;
|
||||
private readonly MapGridComponent _grid;
|
||||
private readonly bool _ignoreEmpty;
|
||||
private readonly Predicate<TileRef>? _predicate;
|
||||
|
||||
private readonly int _lowerY;
|
||||
private readonly int _upperX;
|
||||
private readonly int _upperY;
|
||||
|
||||
private int _x;
|
||||
private int _y;
|
||||
|
||||
public TilesEnumerator(
|
||||
SharedMapSystem mapSystem,
|
||||
bool ignoreEmpty,
|
||||
Predicate<TileRef>? predicate,
|
||||
EntityUid uid,
|
||||
MapGridComponent grid,
|
||||
Box2 aabb)
|
||||
{
|
||||
_mapSystem = mapSystem;
|
||||
|
||||
_uid = uid;
|
||||
_grid = grid;
|
||||
_ignoreEmpty = ignoreEmpty;
|
||||
_predicate = predicate;
|
||||
|
||||
// TODO: Should move the intersecting calls onto mapmanager system and then allow people to pass in xform / xformquery
|
||||
// that way we can avoid the GetComp here.
|
||||
var gridTileLb = new Vector2i((int)Math.Floor(aabb.Left), (int)Math.Floor(aabb.Bottom));
|
||||
// If we have 20.1 we want to include that tile but if we have 20 then we don't.
|
||||
var gridTileRt = new Vector2i((int)Math.Ceiling(aabb.Right), (int)Math.Ceiling(aabb.Top));
|
||||
|
||||
_x = gridTileLb.X;
|
||||
_y = gridTileLb.Y;
|
||||
_lowerY = gridTileLb.Y;
|
||||
_upperX = gridTileRt.X;
|
||||
_upperY = gridTileRt.Y;
|
||||
}
|
||||
|
||||
public bool MoveNext(out TileRef tile)
|
||||
{
|
||||
if (_x >= _upperX)
|
||||
{
|
||||
tile = TileRef.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
var gridTile = new Vector2i(_x, _y);
|
||||
|
||||
_y++;
|
||||
|
||||
if (_y >= _upperY)
|
||||
{
|
||||
_x++;
|
||||
_y = _lowerY;
|
||||
}
|
||||
|
||||
var gridChunk = _mapSystem.GridTileToChunkIndices(_uid, _grid, gridTile);
|
||||
|
||||
if (_grid.Chunks.TryGetValue(gridChunk, out var chunk))
|
||||
{
|
||||
var chunkTile = chunk.GridTileToChunkTile(gridTile);
|
||||
tile = _mapSystem.GetTileRef(_uid, _grid, chunk, (ushort)chunkTile.X, (ushort)chunkTile.Y);
|
||||
|
||||
if (_ignoreEmpty && tile.Tile.IsEmpty)
|
||||
return MoveNext(out tile);
|
||||
|
||||
if (_predicate == null || _predicate(tile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (!_ignoreEmpty)
|
||||
{
|
||||
tile = new TileRef(_uid, gridTile.X, gridTile.Y, Tile.Empty);
|
||||
|
||||
if (_predicate == null || _predicate(tile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return MoveNext(out tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user