Overhaul InvasiveList iteration

This commit is contained in:
Crypto137 2026-03-23 13:39:19 +03:00
parent 03839a2699
commit a934f07f3a
7 changed files with 66 additions and 67 deletions

View file

@ -5,49 +5,28 @@ namespace MHServerEmu.Core.Collections
{
public class InvasiveList<T>
{
private readonly Iterator[] _iterators;
private int _numIterators;
public int Id { get; private set; }
public T Head { get; set; }
public T Head { get; private set; }
public T Tail { get; private set; }
public int Count { get; private set; }
private Iterator[] _iterators;
private int _numIterators;
private int _maxIterators;
public bool IsEmpty { get => Head == null; }
public InvasiveList(int maxIterators)
public InvasiveList(int maxIterators, int id = 0)
{
_maxIterators = maxIterators;
_iterators = new Iterator[_maxIterators];
}
public InvasiveList(int maxIterators, int id)
{
_maxIterators = maxIterators;
_iterators = new Iterator[_maxIterators];
_iterators = new Iterator[maxIterators];
Id = id;
}
public IEnumerable<T> Iterate()
public IEnumerator<T> GetEnumerator()
{
var iterator = new Iterator(this);
try
{
while (iterator.End() == false)
{
var element = iterator.Current;
iterator.MoveNext();
yield return element;
}
}
finally
{
UnregisterIterator(iterator);
}
return new Iterator(this);
}
public bool IsEmpty() => Head == null;
public void Remove(T element)
{
if (element == null || Contains(element) == false) return;
@ -138,7 +117,10 @@ namespace MHServerEmu.Core.Collections
Count++;
}
public virtual ref InvasiveListNode<T> GetInvasiveListNode(T element, int listId) => ref Unsafe.NullRef<InvasiveListNode<T>>();
public virtual ref InvasiveListNode<T> GetInvasiveListNode(T element, int listId)
{
return ref Unsafe.NullRef<InvasiveListNode<T>>();
}
public bool Contains(T element)
{
@ -150,8 +132,8 @@ namespace MHServerEmu.Core.Collections
private void RegisterIterator(Iterator iterator)
{
if (_numIterators >= _maxIterators)
throw new InvalidOperationException($"Too many iterators '{_maxIterators}' for invasive list");
if (_numIterators >= _iterators.Length)
throw new InvalidOperationException($"Too many iterators '{_iterators.Length}' for invasive list");
_iterators[_numIterators++] = iterator;
}
@ -172,36 +154,53 @@ namespace MHServerEmu.Core.Collections
throw new InvalidOperationException("Iterator not found in iterator collection of invasive list!");
}
public class Iterator : IEnumerator<T>
public sealed class Iterator : IEnumerator<T>
{
private InvasiveList<T> _list;
public bool SkipNext { get; set; }
private readonly InvasiveList<T> _list;
private bool _start = true;
public T Current { get; private set; }
object IEnumerator.Current { get => Current; }
public bool SkipNext { get; set; } = false;
public Iterator(InvasiveList<T> invasiveList)
{
_list = invasiveList;
Current = _list.Head;
SkipNext = false;
_list.RegisterIterator(this);
}
public T Current { get; private set; }
object IEnumerator.Current => Current;
public void Dispose() { }
public void Reset() { }
public void Dispose()
{
_list.UnregisterIterator(this);
}
public void Reset()
{
_start = true;
Current = default;
SkipNext = false;
}
public bool MoveNext()
{
if (SkipNext) SkipNext = false;
else if (Current != null)
Current = _list.GetInvasiveListNode(Current, _list.Id).Next;
if (_start)
{
Current = _list.Head;
_start = false;
}
else
{
if (SkipNext)
SkipNext = false;
else if (Current != null)
Current = _list.GetInvasiveListNode(Current, _list.Id).Next;
}
return true;
return Current != null;
}
public bool End() => Current == null;
}
}
public struct InvasiveListNode<T>

View file

@ -28,7 +28,7 @@ namespace MHServerEmu.Games.Entities
All = 3,
}
public class EntityInvasiveCollection : InvasiveList<Entity>
public sealed class EntityInvasiveCollection : InvasiveList<Entity>
{
public EntityInvasiveCollection(EntityCollection collectionType, int maxIterators = 8) : base(maxIterators, (int)collectionType) { }
public override ref InvasiveListNode<Entity> GetInvasiveListNode(Entity element, int listId) => ref element.GetInvasiveListNode(listId);
@ -449,7 +449,7 @@ namespace MHServerEmu.Games.Entities
public void LocomoteEntities()
{
foreach (var entity in LocomotionEntities.Iterate())
foreach (var entity in LocomotionEntities)
if (entity is WorldEntity worldEntity)
worldEntity?.Locomotor.Locomote();
}
@ -586,7 +586,7 @@ namespace MHServerEmu.Games.Entities
IsAIEnabled = enable;
if (enable)
foreach (var entity in SimulatedEntities.Iterate())
foreach (var entity in SimulatedEntities)
if (entity is Agent agent) agent.AIController?.SetIsEnabled(true);
foreach (var entity in _entityDict.Values)

View file

@ -15,7 +15,7 @@ namespace MHServerEmu.Games.Entities.Physics
}
}
public class ForceSystemMemberList : InvasiveList<ForceSystemMember>
public sealed class ForceSystemMemberList : InvasiveList<ForceSystemMember>
{
public ForceSystemMemberList(int maxIterators = 1) : base(maxIterators) { }
public override ref InvasiveListNode<ForceSystemMember> GetInvasiveListNode(ForceSystemMember element, int listId) => ref element.InvasiveListNode;

View file

@ -196,7 +196,7 @@ namespace MHServerEmu.Games.Entities.Physics
EntityManager entityManager = _game.EntityManager;
foreach (var member in forceSystem.Members.Iterate())
foreach (var member in forceSystem.Members)
{
if (member == null) continue;
bool active = false;
@ -684,7 +684,7 @@ namespace MHServerEmu.Games.Entities.Physics
float distanceSq = Vector3.DistanceSquared(epicenter, member.Position);
var pendingMembers = pendingForce.Members;
foreach (var pendingMember in pendingMembers.Iterate())
foreach (var pendingMember in pendingMembers)
if (distanceSq > Vector3.DistanceSquared(epicenter, pendingMember.Position))
{
pendingForce.Members.InsertBefore(member, pendingMember);

View file

@ -55,7 +55,7 @@ namespace MHServerEmu.Games.Navi
public void Release()
{
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
RemoveTriangle(triangle);
_lastTriangle = null;
@ -126,7 +126,7 @@ namespace MHServerEmu.Games.Navi
using var collinearEdgesHandle = ListPool<NaviEdge>.Instance.Get(out List<NaviEdge> collinearEdges);
using NaviSerialCheck naviSerialCheck = new(this);
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
foreach (var edge in triangle.Edges)
{
if (edge.Triangles[0] == null || edge.Triangles[1] == null) continue;
@ -925,7 +925,7 @@ namespace MHServerEmu.Games.Navi
{
StringBuilder hashes = new();
int id = 0;
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
hashes.AppendLine($"[{id++}] {triangle.ToHashString()}");
FileHelper.SaveTextFileToRoot(fileName, hashes.ToString());
}
@ -934,7 +934,7 @@ namespace MHServerEmu.Games.Navi
{
StringBuilder hashes = new();
int id = 0;
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
hashes.AppendLine($"[{id++}] {triangle.ToHashString2()}");
FileHelper.SaveTextFileToRoot(fileName, hashes.ToString());
}
@ -943,12 +943,12 @@ namespace MHServerEmu.Games.Navi
{
NaviSvgHelper svg = new(this);
Stack<NaviPoint> influences = new();
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
foreach (var edge in triangle.Edges)
foreach (var point in edge.Points)
if (point.InfluenceRadius > 0 && influences.Contains(point) == false)
influences.Push(point);
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
svg.AddTriangle(triangle);
foreach (var point in influences)
svg.AddCircle(point.Pos, point.InfluenceRadius);
@ -962,7 +962,7 @@ namespace MHServerEmu.Games.Navi
// Vertices
int newId = 1;
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
if (triangle.PathingFlags.HasFlag(filterFlags))
foreach (var edge in triangle.Edges)
foreach (var point in edge.Points)
@ -975,7 +975,7 @@ namespace MHServerEmu.Games.Navi
}
// Faces
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
if (triangle.PathingFlags.HasFlag(filterFlags))
{
var p0 = triangle.PointCW(0);

View file

@ -345,7 +345,7 @@ namespace MHServerEmu.Games.Navi
private void ReverseMarkupMesh()
{
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
for (int edgeIndex = 0; edgeIndex < 3; edgeIndex++)
{
NaviEdge edge = triangle.Edges[edgeIndex];
@ -367,7 +367,7 @@ namespace MHServerEmu.Games.Navi
private void ClearMarkup()
{
foreach (var triangle in TriangleList.Iterate())
foreach (var triangle in TriangleList)
{
triangle.ClearFlag(NaviTriangleFlags.Markup);
triangle.PathingFlags = PathFlags.None;

View file

@ -11,7 +11,7 @@ namespace MHServerEmu.Games.Navi
Markup = 1 << 1,
}
public class TriangleList : InvasiveList<NaviTriangle>
public sealed class TriangleList : InvasiveList<NaviTriangle>
{
public TriangleList(int maxIterators = 1) : base(maxIterators) { }
public override ref InvasiveListNode<NaviTriangle> GetInvasiveListNode(NaviTriangle element, int listId) => ref element.InvasiveListNode;