fix: Fixes searching multis/clients. Adds missing map enumeration tests (#2278)
> [!IMPORTANT] > **Dev Note:** This is an **important** patch as the bug could lead to major issues like: > * Multis/Players disappearing from view or not being counted during game logic. > * World processes (e.g., area checks, targeting) failing to detect entities correctly. > * General stability and correctness concerns for core map functionality. > > **Important Breaking Change**: Multis now properly use the map link list. This means modifying a multi while iterating will cause the server to crash. The crash _is expected_. Please modify/fix code accordingly to create a list using `PooledRefQueue` or `PooledRefList` instead of moving/deleting multis while inside the foreach. ### Summary * Fixes a bug where deleting/moving a multi (boat/house) in some circumstances can use undefined behavior due to unsafe changes to List<BaseMulti> * Fixes a bug where Multis may not be considered while searching due to a bug causing the sector search to end early.
This commit is contained in:
parent
5aed018232
commit
d3fdb180b3
9 changed files with 1923 additions and 571 deletions
|
|
@ -1,6 +1,6 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2023 - ModernUO Development Team *
|
||||
* Copyright 2019-2025 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Map.ClientEnumerator.cs *
|
||||
* *
|
||||
|
|
@ -76,6 +76,7 @@ public partial class Map
|
|||
|
||||
public ref struct ClientAtEnumerator
|
||||
{
|
||||
private readonly Map _map;
|
||||
private bool _started;
|
||||
private Point2D _location;
|
||||
private ref readonly ValueLinkList<NetState> _linkList;
|
||||
|
|
@ -85,9 +86,15 @@ public partial class Map
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ClientAtEnumerator(Map map, Point2D loc)
|
||||
{
|
||||
_map = map;
|
||||
_started = false;
|
||||
_location = loc;
|
||||
_linkList = ref map.GetSector(loc.m_X, loc.m_Y).Clients;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
_linkList = ref map.GetSector(loc.m_X, loc.m_Y).Clients;
|
||||
}
|
||||
|
||||
_version = 0;
|
||||
_current = null;
|
||||
}
|
||||
|
|
@ -95,6 +102,11 @@ public partial class Map
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_map == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ref var loc = ref _location;
|
||||
NetState current;
|
||||
Mobile m;
|
||||
|
|
@ -105,7 +117,7 @@ public partial class Map
|
|||
_started = true;
|
||||
_version = _linkList.Version;
|
||||
|
||||
m = current.Mobile;
|
||||
m = current?.Mobile;
|
||||
if (m?.Deleted == false && m.X == loc.m_X && m.Y == loc.m_Y)
|
||||
{
|
||||
_current = current;
|
||||
|
|
@ -125,7 +137,7 @@ public partial class Map
|
|||
{
|
||||
current = current.Next;
|
||||
|
||||
m = current.Mobile;
|
||||
m = current?.Mobile;
|
||||
if (m?.Deleted == false && m.X == loc.m_X && m.Y == loc.m_Y)
|
||||
{
|
||||
_current = current;
|
||||
|
|
@ -163,10 +175,10 @@ public partial class Map
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MobileEnumerator GetEnumerator() => new(_map, _bounds, _makeBoundsInclusive);
|
||||
public ClientBoundsEnumerator GetEnumerator() => new(_map, _bounds, _makeBoundsInclusive);
|
||||
}
|
||||
|
||||
public ref struct MobileEnumerator
|
||||
public ref struct ClientBoundsEnumerator
|
||||
{
|
||||
private readonly Map _map;
|
||||
private readonly int _sectorStartX;
|
||||
|
|
@ -182,7 +194,7 @@ public partial class Map
|
|||
private NetState _current;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MobileEnumerator(Map map, Rectangle2D bounds, bool makeBoundsInclusive)
|
||||
public ClientBoundsEnumerator(Map map, Rectangle2D bounds, bool makeBoundsInclusive)
|
||||
{
|
||||
_map = map;
|
||||
_bounds = bounds;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue