fix: Adds multis to map iterators, fixes searching empty nested containers (#1581)
### Summary
Eliminates `IPooledEnumerable<BaseMulti>` and `eable.Free()` from `Map` for multis. This drastically simplifies code that iterates in range, for example:
```cs
foreach (var m in m.GetMultisInRange(5))
{
}
```
The code above no longer requires an eable and calling `Free()`.
### Bug Fixes
- [X] Fixes an issue with searching through nested empty containers.
This commit is contained in:
parent
1f04a13f67
commit
ca3df9cfa7
12 changed files with 960 additions and 860 deletions
|
|
@ -15,430 +15,489 @@
|
|||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Server.Collections;
|
||||
|
||||
namespace Server.Items;
|
||||
|
||||
// Adds support for the specific value link list on sectors for multis, separate from items
|
||||
public partial class BaseMulti : BaseMulti.ISectorMultiLinkListNode<BaseMulti>
|
||||
public partial class BaseMulti
|
||||
{
|
||||
public interface ISectorMultiLinkListNode<T> where T : class
|
||||
{
|
||||
public T SectorMultiNext { get; set; }
|
||||
public T SectorMultiPrevious { get; set; }
|
||||
public bool OnSectorMultiLinkList { get; set; }
|
||||
}
|
||||
|
||||
public struct SectorMultiLinkList<T> where T : class, ISectorMultiLinkListNode<T>
|
||||
{
|
||||
public int Count { get; internal set; }
|
||||
public T First { get; internal set; }
|
||||
public T Last { get; internal set; }
|
||||
|
||||
public void Remove(T node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (node.SectorMultiPrevious == null)
|
||||
{
|
||||
// If previous is null, then it is the first element.
|
||||
if (First != node)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (First == Last)
|
||||
{
|
||||
Last = null;
|
||||
First = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
First = node.SectorMultiNext;
|
||||
}
|
||||
|
||||
if (node.SectorMultiNext != null)
|
||||
{
|
||||
node.SectorMultiNext.SectorMultiPrevious = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node.SectorMultiPrevious.SectorMultiNext = node.SectorMultiNext;
|
||||
|
||||
// If next is null, then it is the last element.
|
||||
if (node.SectorMultiNext == null)
|
||||
{
|
||||
Last = node.SectorMultiPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.SectorMultiNext.SectorMultiPrevious = node.SectorMultiPrevious;
|
||||
}
|
||||
}
|
||||
|
||||
node.SectorMultiNext = null;
|
||||
node.SectorMultiPrevious = null;
|
||||
node.OnSectorMultiLinkList = false;
|
||||
Count--;
|
||||
}
|
||||
|
||||
// Remove all entries before this node, not including this node.
|
||||
public void RemoveAllBefore(T e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove nodes before a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (e.SectorMultiPrevious == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var current = e.SectorMultiPrevious;
|
||||
e.SectorMultiPrevious = null;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
var previous = current.SectorMultiPrevious;
|
||||
|
||||
current.OnSectorMultiLinkList = false;
|
||||
current.SectorMultiNext = null;
|
||||
current.SectorMultiPrevious = null;
|
||||
Count--;
|
||||
|
||||
current = previous;
|
||||
}
|
||||
|
||||
First = e;
|
||||
}
|
||||
|
||||
// Remove all entries after this node, not including this node.
|
||||
public void RemoveAllAfter(T e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove nodes after a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (e.SectorMultiNext == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var current = e.SectorMultiNext;
|
||||
e.SectorMultiNext = null;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
var next = current.SectorMultiNext;
|
||||
|
||||
current.OnSectorMultiLinkList = false;
|
||||
current.SectorMultiNext = null;
|
||||
current.SectorMultiPrevious = null;
|
||||
Count--;
|
||||
|
||||
current = next;
|
||||
}
|
||||
|
||||
Last = e;
|
||||
}
|
||||
|
||||
public void AddLast(T e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
if (Last != null)
|
||||
{
|
||||
AddAfter(Last, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
First = e;
|
||||
Last = e;
|
||||
Count++;
|
||||
}
|
||||
|
||||
e.OnSectorMultiLinkList = true;
|
||||
}
|
||||
|
||||
public void AddFirst(T e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
if (First != null)
|
||||
{
|
||||
AddBefore(First, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
First = e;
|
||||
Last = e;
|
||||
Count++;
|
||||
}
|
||||
|
||||
e.OnSectorMultiLinkList = true;
|
||||
}
|
||||
|
||||
public void AddBefore(T existing, T node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(existing);
|
||||
|
||||
if (!existing.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException($"Argument '{nameof(existing)}' must be a node on a list.");
|
||||
}
|
||||
|
||||
if (node.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
node.SectorMultiNext = existing;
|
||||
node.SectorMultiPrevious = existing.SectorMultiPrevious;
|
||||
|
||||
if (existing.SectorMultiPrevious != null)
|
||||
{
|
||||
existing.SectorMultiPrevious.SectorMultiNext = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
First = node;
|
||||
}
|
||||
|
||||
existing.SectorMultiPrevious = node;
|
||||
node.OnSectorMultiLinkList = true;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public void AddAfter(T existing, T node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(existing);
|
||||
|
||||
if (!existing.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException($"Argument '{nameof(existing)}' must be a node on a list.");
|
||||
}
|
||||
|
||||
if (node.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
node.SectorMultiPrevious = existing;
|
||||
node.SectorMultiNext = existing.SectorMultiNext;
|
||||
|
||||
if (existing.SectorMultiNext != null)
|
||||
{
|
||||
existing.SectorMultiNext.SectorMultiPrevious = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
Last = node;
|
||||
}
|
||||
|
||||
existing.SectorMultiNext = node;
|
||||
node.OnSectorMultiLinkList = true;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
var current = First;
|
||||
while (current != null)
|
||||
{
|
||||
var next = current.SectorMultiNext;
|
||||
|
||||
current.OnSectorMultiLinkList = false;
|
||||
current.SectorMultiNext = null;
|
||||
current.SectorMultiPrevious = null;
|
||||
current = next;
|
||||
}
|
||||
|
||||
First = null;
|
||||
Last = null;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
public void AddLast(ref SectorMultiLinkList<T> otherList, T start, T end)
|
||||
{
|
||||
// Should we check if start and end actually exist on the other list?
|
||||
if (otherList.Count == 0 || otherList.Count == 1 && (start != end || otherList.First != start))
|
||||
{
|
||||
throw new ArgumentException("Attempted to add nodes that are not on the specified linklist.");
|
||||
}
|
||||
|
||||
if (start.SectorMultiPrevious != null)
|
||||
{
|
||||
start.SectorMultiPrevious.SectorMultiNext = end.SectorMultiNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start is first
|
||||
otherList.First = end.SectorMultiNext;
|
||||
}
|
||||
|
||||
if (end.SectorMultiNext != null)
|
||||
{
|
||||
end.SectorMultiNext.SectorMultiPrevious = start.SectorMultiPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
otherList.Last = start.SectorMultiPrevious;
|
||||
}
|
||||
|
||||
var count = 1;
|
||||
var current = start;
|
||||
|
||||
// Assume start and end are in the right order, or bad things happen (crash).
|
||||
while (current != end)
|
||||
{
|
||||
count++;
|
||||
current = current.SectorMultiNext;
|
||||
}
|
||||
|
||||
otherList.Count -= count;
|
||||
|
||||
if (Last != null)
|
||||
{
|
||||
Last.SectorMultiNext = start;
|
||||
start.SectorMultiPrevious = Last;
|
||||
}
|
||||
else
|
||||
{
|
||||
First = start;
|
||||
}
|
||||
|
||||
Last = end;
|
||||
Count += count;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public SectorMultiListEnumerator GetEnumerator() => new(First);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public DescendingSectorMultiListEnumerator ByDescending() => new(Last);
|
||||
|
||||
public ref struct SectorMultiListEnumerator
|
||||
{
|
||||
private T _head;
|
||||
private T _current;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public SectorMultiListEnumerator(T head)
|
||||
{
|
||||
_head = head;
|
||||
_current = null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_current == null)
|
||||
{
|
||||
_current = _head;
|
||||
_head = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_current = _current.SectorMultiNext;
|
||||
}
|
||||
|
||||
return _current != null;
|
||||
}
|
||||
|
||||
public T Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct DescendingSectorMultiListEnumerator
|
||||
{
|
||||
private T _tail;
|
||||
private T _current;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public DescendingSectorMultiListEnumerator(T head)
|
||||
{
|
||||
_tail = head;
|
||||
_current = null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_current == null)
|
||||
{
|
||||
_current = _tail;
|
||||
_tail = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_current = _current.SectorMultiPrevious;
|
||||
}
|
||||
|
||||
return _current != null;
|
||||
}
|
||||
|
||||
public T Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public DescendingSectorMultiListEnumerator GetEnumerator() => this;
|
||||
}
|
||||
}
|
||||
|
||||
// Sectors, specifically for multis
|
||||
public BaseMulti SectorMultiNext { get; set; }
|
||||
public BaseMulti SectorMultiPrevious { get; set; }
|
||||
public bool OnSectorMultiLinkList { get; set; }
|
||||
}
|
||||
|
||||
public struct SectorMultiValueLinkList
|
||||
{
|
||||
public int Count { get; internal set; }
|
||||
internal BaseMulti _first;
|
||||
internal BaseMulti _last;
|
||||
|
||||
public int Version { get; private set; }
|
||||
|
||||
public void Remove(BaseMulti node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (node.SectorMultiPrevious == null)
|
||||
{
|
||||
// If SectorMultiPrevious is null, then it is the first element.
|
||||
if (_first != node)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (_first == _last)
|
||||
{
|
||||
_last = null;
|
||||
_first = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_first = node.SectorMultiNext;
|
||||
}
|
||||
|
||||
if (node.SectorMultiNext != null)
|
||||
{
|
||||
node.SectorMultiNext.SectorMultiPrevious = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node.SectorMultiPrevious.SectorMultiNext = node.SectorMultiNext;
|
||||
|
||||
// If SectorMultiNext is null, then it is the last element.
|
||||
if (node.SectorMultiNext == null)
|
||||
{
|
||||
_last = node.SectorMultiPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.SectorMultiNext.SectorMultiPrevious = node.SectorMultiPrevious;
|
||||
}
|
||||
}
|
||||
|
||||
node.SectorMultiNext = null;
|
||||
node.SectorMultiPrevious = null;
|
||||
node.OnSectorMultiLinkList = false;
|
||||
Count--;
|
||||
Version++;
|
||||
|
||||
if (Count < 0)
|
||||
{
|
||||
throw new Exception("Count is negative!");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all entries before this node, not including this node.
|
||||
public void RemoveAllBefore(BaseMulti e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove nodes before a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (e.SectorMultiPrevious == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var current = e.SectorMultiPrevious;
|
||||
e.SectorMultiPrevious = null;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
var SectorMultiPrevious = current.SectorMultiPrevious;
|
||||
|
||||
current.OnSectorMultiLinkList = false;
|
||||
current.SectorMultiNext = null;
|
||||
current.SectorMultiPrevious = null;
|
||||
Count--;
|
||||
|
||||
if (Count < 0)
|
||||
{
|
||||
throw new Exception("Count is negative!");
|
||||
}
|
||||
|
||||
current = SectorMultiPrevious;
|
||||
}
|
||||
|
||||
_first = e;
|
||||
Version++;
|
||||
}
|
||||
|
||||
// Remove all entries after this node, not including this node.
|
||||
public void RemoveAllAfter(BaseMulti e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to remove nodes after a node that is not on the list.");
|
||||
}
|
||||
|
||||
if (e.SectorMultiNext == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var current = e.SectorMultiNext;
|
||||
e.SectorMultiNext = null;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
var SectorMultiNext = current.SectorMultiNext;
|
||||
|
||||
current.OnSectorMultiLinkList = false;
|
||||
current.SectorMultiNext = null;
|
||||
current.SectorMultiPrevious = null;
|
||||
Count--;
|
||||
|
||||
if (Count < 0)
|
||||
{
|
||||
throw new Exception("Count is negative!");
|
||||
}
|
||||
|
||||
current = SectorMultiNext;
|
||||
}
|
||||
|
||||
_last = e;
|
||||
Version++;
|
||||
}
|
||||
|
||||
public void AddLast(BaseMulti e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
if (_last != null)
|
||||
{
|
||||
AddAfter(_last, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
_first = e;
|
||||
_last = e;
|
||||
Count = 1;
|
||||
Version++;
|
||||
e.OnSectorMultiLinkList = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFirst(BaseMulti e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
if (_first != null)
|
||||
{
|
||||
AddBefore(_first, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
_first = e;
|
||||
_last = e;
|
||||
Count = 1;
|
||||
Version++;
|
||||
e.OnSectorMultiLinkList = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBefore(BaseMulti existing, BaseMulti node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(existing);
|
||||
|
||||
if (!existing.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException($"Argument '{nameof(existing)}' must be a node on a list.");
|
||||
}
|
||||
|
||||
if (node.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
node.SectorMultiNext = existing;
|
||||
node.SectorMultiPrevious = existing.SectorMultiPrevious;
|
||||
|
||||
if (existing.SectorMultiPrevious != null)
|
||||
{
|
||||
existing.SectorMultiPrevious.SectorMultiNext = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
_first = node;
|
||||
}
|
||||
|
||||
existing.SectorMultiPrevious = node;
|
||||
node.OnSectorMultiLinkList = true;
|
||||
Count++;
|
||||
Version++;
|
||||
}
|
||||
|
||||
public void AddAfter(BaseMulti existing, BaseMulti node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(existing);
|
||||
|
||||
if (!existing.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException($"Argument '{nameof(existing)}' must be a node on a list.");
|
||||
}
|
||||
|
||||
if (node.OnSectorMultiLinkList)
|
||||
{
|
||||
throw new ArgumentException("Attempted to add a node that is already on a list.");
|
||||
}
|
||||
|
||||
node.SectorMultiPrevious = existing;
|
||||
node.SectorMultiNext = existing.SectorMultiNext;
|
||||
|
||||
if (existing.SectorMultiNext != null)
|
||||
{
|
||||
existing.SectorMultiNext.SectorMultiPrevious = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
_last = node;
|
||||
}
|
||||
|
||||
existing.SectorMultiNext = node;
|
||||
node.OnSectorMultiLinkList = true;
|
||||
Count++;
|
||||
Version++;
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
var current = _first;
|
||||
while (current != null)
|
||||
{
|
||||
var SectorMultiNext = current.SectorMultiNext;
|
||||
|
||||
current.OnSectorMultiLinkList = false;
|
||||
current.SectorMultiNext = null;
|
||||
current.SectorMultiPrevious = null;
|
||||
current = SectorMultiNext;
|
||||
}
|
||||
|
||||
_first = null;
|
||||
_last = null;
|
||||
Count = 0;
|
||||
Version++;
|
||||
}
|
||||
|
||||
public void AddLast(ref SectorMultiValueLinkList otherList, BaseMulti start, BaseMulti end)
|
||||
{
|
||||
// Should we check if start and end actually exist on the other list?
|
||||
if (otherList.Count == 0 || otherList.Count == 1 && (start != end || otherList._first != start))
|
||||
{
|
||||
throw new ArgumentException("Attempted to add nodes that are not on the specified linklist.");
|
||||
}
|
||||
|
||||
if (start.SectorMultiPrevious != null)
|
||||
{
|
||||
start.SectorMultiPrevious.SectorMultiNext = end.SectorMultiNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start is first
|
||||
otherList._first = end.SectorMultiNext;
|
||||
}
|
||||
|
||||
if (end.SectorMultiNext != null)
|
||||
{
|
||||
end.SectorMultiNext.SectorMultiPrevious = start.SectorMultiPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
otherList._last = start.SectorMultiPrevious;
|
||||
}
|
||||
|
||||
var count = 1;
|
||||
var current = start;
|
||||
|
||||
// Assume start and end are in the right order, or bad things happen (crash).
|
||||
while (current != end)
|
||||
{
|
||||
count++;
|
||||
current = current.SectorMultiNext;
|
||||
}
|
||||
|
||||
otherList.Count -= count;
|
||||
|
||||
if (otherList.Count < 0)
|
||||
{
|
||||
throw new Exception("Count is negative!");
|
||||
}
|
||||
|
||||
if (_last != null)
|
||||
{
|
||||
_last.SectorMultiNext = start;
|
||||
start.SectorMultiPrevious = _last;
|
||||
}
|
||||
else
|
||||
{
|
||||
_first = start;
|
||||
}
|
||||
|
||||
_last = end;
|
||||
Count += count;
|
||||
Version++;
|
||||
}
|
||||
|
||||
public BaseMulti[] ToArray()
|
||||
{
|
||||
var arr = new BaseMulti[Count];
|
||||
|
||||
var index = 0;
|
||||
foreach (var t in this)
|
||||
{
|
||||
arr[index++] = t;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public ref struct SectorMultiValueListEnumerator
|
||||
{
|
||||
private bool _started;
|
||||
private BaseMulti _current;
|
||||
private ref readonly SectorMultiValueLinkList _linkList;
|
||||
private int _version;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public SectorMultiValueListEnumerator(in SectorMultiValueLinkList linkList)
|
||||
{
|
||||
_linkList = ref linkList;
|
||||
_started = false;
|
||||
_current = null;
|
||||
_version = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (!_started)
|
||||
{
|
||||
_current = _linkList._first;
|
||||
_started = true;
|
||||
_version = _linkList.Version;
|
||||
}
|
||||
else if (_linkList.Version != _version)
|
||||
{
|
||||
throw new InvalidOperationException(CollectionThrowStrings.InvalidOperation_EnumFailedVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
_current = _current.SectorMultiNext;
|
||||
}
|
||||
|
||||
return _current != null;
|
||||
}
|
||||
|
||||
public BaseMulti Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct DescendingSectorMultiValueListEnumerator
|
||||
{
|
||||
private bool _started;
|
||||
private BaseMulti _current;
|
||||
private ref readonly SectorMultiValueLinkList _linkList;
|
||||
private int _version;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public DescendingSectorMultiValueListEnumerator(in SectorMultiValueLinkList linkList)
|
||||
{
|
||||
_linkList = ref linkList;
|
||||
_started = false;
|
||||
_current = null;
|
||||
_version = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (!_started)
|
||||
{
|
||||
_current = _linkList._last;
|
||||
_started = true;
|
||||
_version = _linkList.Version;
|
||||
}
|
||||
else if (_linkList.Version != _version)
|
||||
{
|
||||
throw new InvalidOperationException(CollectionThrowStrings.InvalidOperation_EnumFailedVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
_current = _current.SectorMultiPrevious;
|
||||
}
|
||||
|
||||
return _current != null;
|
||||
}
|
||||
|
||||
public BaseMulti Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public DescendingSectorMultiValueListEnumerator GetEnumerator() => this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SectorMultiValueLinkListExt
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static SectorMultiValueLinkList.SectorMultiValueListEnumerator GetEnumerator(this in SectorMultiValueLinkList linkList)
|
||||
=> new(in linkList);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static SectorMultiValueLinkList.DescendingSectorMultiValueListEnumerator ByDescending(this in SectorMultiValueLinkList linkList)
|
||||
=> new(in linkList);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,14 +161,17 @@ public partial class Container
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool SetNextContainer()
|
||||
{
|
||||
if (!_containers.TryDequeue(out var c))
|
||||
while (_containers.TryDequeue(out var c))
|
||||
{
|
||||
return false;
|
||||
_items = CollectionsMarshal.AsSpan(c.m_Items);
|
||||
_index = 0;
|
||||
if (SetNextItem())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_items = CollectionsMarshal.AsSpan(c.m_Items);
|
||||
_index = 0;
|
||||
return SetNextItem();
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
|
|||
263
Projects/Server/Maps/Map.MultiEnumerator.cs
Normal file
263
Projects/Server/Maps/Map.MultiEnumerator.cs
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2023 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Map.MultiEnumerator.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server;
|
||||
|
||||
public partial class Map
|
||||
{
|
||||
private static SectorMultiValueLinkList _emptyMultiLinkList = new();
|
||||
public static ref readonly SectorMultiValueLinkList EmptyMultiLinkList => ref _emptyMultiLinkList;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerable<BaseMulti> GetMultisAt(Point3D p) => GetMultisAt<BaseMulti>(p);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerable<T> GetMultisAt<T>(Point3D p) where T : BaseMulti => GetMultisAt<T>(new Point2D(p.X, p.Y));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerable<BaseMulti> GetMultisAt(int x, int y) => GetMultisAt<BaseMulti>(new Point2D(x, y));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerable<T> GetMultisAt<T>(int x, int y) where T : BaseMulti => GetMultisAt<T>(new Point2D(x, y));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerable<BaseMulti> GetMultisAt(Point2D p) => GetMultisAt<BaseMulti>(p);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerable<T> GetMultisAt<T>(Point2D p) where T : BaseMulti => new(this, p);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<BaseMulti> GetMultisInRange(Point3D p) => GetMultisInRange<BaseMulti>(p);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<BaseMulti> GetMultisInRange(Point3D p, int range) => GetMultisInRange<BaseMulti>(p, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<T> GetMultisInRange<T>(Point3D p) where T : BaseMulti => GetMultisInRange<T>(p, Core.GlobalMaxUpdateRange);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<T> GetMultisInRange<T>(Point3D p, int range) where T : BaseMulti =>
|
||||
GetMultisInRange<T>(p.m_X, p.m_Y, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<BaseMulti> GetMultisInRange(Point2D p) => GetMultisInRange<BaseMulti>(p);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<BaseMulti> GetMultisInRange(Point2D p, int range) => GetMultisInRange<BaseMulti>(p, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<T> GetMultisInRange<T>(Point2D p) where T : BaseMulti => GetMultisInRange<T>(p, Core.GlobalMaxUpdateRange);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<T> GetMultisInRange<T>(Point2D p, int range) where T : BaseMulti =>
|
||||
GetMultisInRange<T>(p.m_X, p.m_Y, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<T> GetMultisInRange<T>(int x, int y, int range) where T : BaseMulti =>
|
||||
GetMultisInBounds<T>(new Rectangle2D(x - range, y - range, range * 2 + 1, range * 2 + 1));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<BaseMulti> GetMultisInBounds(Rectangle2D bounds) => GetMultisInBounds<BaseMulti>(bounds);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiBoundsEnumerable<T> GetMultisInBounds<T>(Rectangle2D bounds, bool makeBoundsInclusive = false) where T : BaseMulti =>
|
||||
new(this, bounds, makeBoundsInclusive);
|
||||
|
||||
public ref struct MultiAtEnumerable<T> where T : BaseMulti
|
||||
{
|
||||
public static MultiAtEnumerable<T> Empty
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new();
|
||||
}
|
||||
|
||||
private readonly Map _map;
|
||||
private readonly Point2D _location;
|
||||
|
||||
public MultiAtEnumerable(Map map, Point2D loc)
|
||||
{
|
||||
_map = map;
|
||||
_location = loc;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerator<T> GetEnumerator() => new(_map, _location);
|
||||
}
|
||||
|
||||
public ref struct MultiAtEnumerator<T> where T : BaseMulti
|
||||
{
|
||||
private Point2D _location;
|
||||
private readonly Span<BaseMulti> _list;
|
||||
private int _index;
|
||||
private T _current;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiAtEnumerator(Map map, Point2D loc)
|
||||
{
|
||||
_location = loc;
|
||||
_list = map == null
|
||||
? Span<BaseMulti>.Empty
|
||||
: CollectionsMarshal.AsSpan(map.GetRealSector(loc.m_X, loc.m_Y).Multis);
|
||||
|
||||
_index = 0;
|
||||
_current = null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
ref var loc = ref _location;
|
||||
|
||||
while ((uint)_index < (uint)_list.Length)
|
||||
{
|
||||
var current = _list[_index++];
|
||||
if (current is T { Deleted: false } o && o.X == loc.m_X && o.Y == loc.m_Y)
|
||||
{
|
||||
_current = o;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public T Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct MultiBoundsEnumerable<T> where T : BaseMulti
|
||||
{
|
||||
public static MultiBoundsEnumerable<T> Empty
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new(null, Rectangle2D.Empty, false);
|
||||
}
|
||||
|
||||
private Map _map;
|
||||
private Rectangle2D _bounds;
|
||||
private bool _makeBoundsInclusive;
|
||||
|
||||
public MultiBoundsEnumerable(Map map, Rectangle2D bounds, bool makeBoundsInclusive)
|
||||
{
|
||||
_map = map;
|
||||
_bounds = bounds;
|
||||
_makeBoundsInclusive = makeBoundsInclusive;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiEnumerator<T> GetEnumerator() => new(_map, _bounds, _makeBoundsInclusive);
|
||||
}
|
||||
|
||||
public ref struct MultiEnumerator<T> where T : BaseMulti
|
||||
{
|
||||
private readonly Map _map;
|
||||
private readonly int _sectorStartX;
|
||||
private readonly int _sectorEndX;
|
||||
private readonly int _sectorEndY;
|
||||
private Rectangle2D _bounds;
|
||||
|
||||
private int _currentSectorX;
|
||||
private int _currentSectorY;
|
||||
|
||||
private Span<BaseMulti> _list;
|
||||
private T _current;
|
||||
private int _index;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiEnumerator(Map map, Rectangle2D bounds, bool makeBoundsInclusive)
|
||||
{
|
||||
_map = map;
|
||||
_bounds = bounds;
|
||||
|
||||
if (makeBoundsInclusive)
|
||||
{
|
||||
++bounds.Width;
|
||||
++bounds.Height;
|
||||
}
|
||||
|
||||
_bounds = bounds;
|
||||
|
||||
map.CalculateSectors(bounds, out _sectorStartX, out var _sectorStartY, out _sectorEndX, out _sectorEndY);
|
||||
|
||||
// We start the X sector one short because it gets incremented immediately in MoveNext()
|
||||
_currentSectorX = _sectorStartX - 1;
|
||||
_currentSectorY = _sectorStartY;
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool GetMulti()
|
||||
{
|
||||
ref Rectangle2D bounds = ref _bounds;
|
||||
|
||||
while ((uint)_index < (uint)_list.Length)
|
||||
{
|
||||
var current = _list[_index++];
|
||||
if (current is T { Deleted: false } o && bounds.Contains(o.Location))
|
||||
{
|
||||
_current = o;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool GetSector()
|
||||
{
|
||||
var currentSectorX = _currentSectorX;
|
||||
var currentSectorY = _currentSectorY;
|
||||
var sectorEndX = _sectorEndX;
|
||||
var sectorEndY = _sectorEndY;
|
||||
|
||||
// Move to next sector
|
||||
if (currentSectorX < sectorEndX)
|
||||
{
|
||||
_currentSectorX = ++currentSectorX;
|
||||
}
|
||||
else if (currentSectorY < sectorEndY)
|
||||
{
|
||||
_currentSectorX = currentSectorX = _sectorStartX;
|
||||
_currentSectorY = ++currentSectorY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ran out of sectors
|
||||
return false;
|
||||
}
|
||||
|
||||
_list = CollectionsMarshal.AsSpan(_map.GetRealSector(currentSectorX, currentSectorY).Multis);
|
||||
return GetMulti();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext() => _map != null && (GetMulti() || GetSector());
|
||||
|
||||
public T Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Projects/Server/Maps/Map.MultiTileEnumerator.cs
Normal file
121
Projects/Server/Maps/Map.MultiTileEnumerator.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2023 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Map.MultiTileEnumerator.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server;
|
||||
|
||||
public partial class Map
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiTilesAtEnumerable GetMultiTilesAt(int x, int y) => GetMultiTilesAt(new Point2D(x, y));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiTilesAtEnumerable GetMultiTilesAt(Point2D p) => new(this, p);
|
||||
|
||||
public ref struct MultiTilesAtEnumerable
|
||||
{
|
||||
public static MultiTilesAtEnumerable Empty
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new();
|
||||
}
|
||||
|
||||
private readonly Map _map;
|
||||
private readonly Point2D _location;
|
||||
|
||||
public MultiTilesAtEnumerable(Map map, Point2D loc)
|
||||
{
|
||||
_map = map;
|
||||
_location = loc;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiTilesAtEnumerator GetEnumerator() => new(_map, _location);
|
||||
}
|
||||
|
||||
public ref struct MultiTilesAtEnumerator
|
||||
{
|
||||
private Point2D _location;
|
||||
private MultiAtEnumerator<BaseMulti> _multis;
|
||||
private BaseMulti _currentMulti;
|
||||
private StaticTile[] _current;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MultiTilesAtEnumerator(Map map, Point2D loc)
|
||||
{
|
||||
_multis = (map == null ? MultiAtEnumerable<BaseMulti>.Empty : map.GetMultisAt(loc)).GetEnumerator();
|
||||
|
||||
_current = null;
|
||||
_location = loc;
|
||||
_currentMulti = null;
|
||||
}
|
||||
|
||||
private bool SetStaticTiles()
|
||||
{
|
||||
var mcl = _currentMulti.Components;
|
||||
var x = _location.X;
|
||||
var xo = x - (_currentMulti.X + mcl.Min.X);
|
||||
|
||||
var y = _location.Y;
|
||||
if (xo < 0 || xo >= mcl.Width)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var yo = y - (_currentMulti.Y + mcl.Min.Y);
|
||||
if (yo < 0 || yo >= mcl.Height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = mcl.Tiles[xo][yo];
|
||||
|
||||
// TODO: Remove the allocation.
|
||||
var r = new StaticTile[t.Length];
|
||||
|
||||
for (var i = 0; i < t.Length; i++)
|
||||
{
|
||||
r[i] = t[i];
|
||||
r[i].Z += _currentMulti.Z;
|
||||
}
|
||||
|
||||
_current = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
while (_multis.MoveNext())
|
||||
{
|
||||
_currentMulti = _multis.Current;
|
||||
if (SetStaticTiles())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public StaticTile[] Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
m_Name = name;
|
||||
Rules = rules;
|
||||
Regions = new Dictionary<string, Region>(StringComparer.OrdinalIgnoreCase);
|
||||
InvalidSector = new Sector(0, 0, this);
|
||||
_invalidSector = new Sector(0, 0, this);
|
||||
m_SectorsWidth = width >> SectorShift;
|
||||
m_SectorsHeight = height >> SectorShift;
|
||||
m_Sectors = new Sector[m_SectorsWidth][];
|
||||
|
|
@ -123,7 +123,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
|
||||
public MapRules Rules { get; set; }
|
||||
|
||||
public Sector InvalidSector { get; }
|
||||
private readonly Sector _invalidSector;
|
||||
|
||||
public string Name
|
||||
{
|
||||
|
|
@ -566,7 +566,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
for (var y = cy - SectorActiveRange; y <= cy + SectorActiveRange; ++y)
|
||||
{
|
||||
var sect = GetRealSector(x, y);
|
||||
if (sect != InvalidSector)
|
||||
if (sect != _invalidSector)
|
||||
{
|
||||
sect.Activate();
|
||||
}
|
||||
|
|
@ -581,7 +581,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
for (var y = cy - SectorActiveRange; y <= cy + SectorActiveRange; ++y)
|
||||
{
|
||||
var sect = GetRealSector(x, y);
|
||||
if (sect != InvalidSector && !PlayersInRange(sect, SectorActiveRange))
|
||||
if (sect != _invalidSector && !PlayersInRange(sect, SectorActiveRange))
|
||||
{
|
||||
sect.Deactivate();
|
||||
}
|
||||
|
|
@ -596,7 +596,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
for (var y = sect.Y - range; y <= sect.Y + range; ++y)
|
||||
{
|
||||
var check = GetRealSector(x, y);
|
||||
if (check != InvalidSector && check.Clients.Count > 0)
|
||||
if (check != _invalidSector && check.Clients.Count > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -690,7 +690,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
}
|
||||
}
|
||||
|
||||
public void RemoveMulti(BaseMulti m, Sector start, Sector end)
|
||||
private void RemoveMulti(BaseMulti m, Sector start, Sector end)
|
||||
{
|
||||
if (this == Internal)
|
||||
{
|
||||
|
|
@ -706,7 +706,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
}
|
||||
}
|
||||
|
||||
public void AddMulti(BaseMulti m, Sector start, Sector end)
|
||||
private void AddMulti(BaseMulti m, Sector start, Sector end)
|
||||
{
|
||||
if (this == Internal)
|
||||
{
|
||||
|
|
@ -862,9 +862,6 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
return p;
|
||||
}
|
||||
|
||||
public IPooledEnumerable<StaticTile[]> GetMultiTilesAt(int x, int y) =>
|
||||
PooledEnumeration.GetMultiTiles(this, new Rectangle2D(x, y, 1, 1));
|
||||
|
||||
public bool CanFit(
|
||||
Point3D p, int height, bool checkBlocksFit = false, bool checkMobiles = true,
|
||||
bool requireSurface = true
|
||||
|
|
@ -1011,7 +1008,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
return sec;
|
||||
}
|
||||
|
||||
return InvalidSector;
|
||||
return _invalidSector;
|
||||
}
|
||||
|
||||
public bool LineOfSight(Point3D org, Point3D dest)
|
||||
|
|
@ -1408,13 +1405,12 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
public class Sector
|
||||
{
|
||||
// TODO: Can we avoid this?
|
||||
private static readonly List<BaseMulti> m_DefaultMultiList = new();
|
||||
private static readonly List<Region> m_DefaultRectList = new();
|
||||
private bool m_Active;
|
||||
private ValueLinkList<NetState> _clients;
|
||||
private ValueLinkList<Item> _items;
|
||||
private ValueLinkList<Mobile> _mobiles;
|
||||
private List<BaseMulti> _multis;
|
||||
private List<BaseMulti> _multis = new();
|
||||
private List<Region> _regions;
|
||||
|
||||
public Sector(int x, int y, Map owner)
|
||||
|
|
@ -1427,7 +1423,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
|
||||
public List<Region> Regions => _regions ?? m_DefaultRectList;
|
||||
|
||||
public List<BaseMulti> Multis => _multis ?? m_DefaultMultiList;
|
||||
internal List<BaseMulti> Multis => _multis;
|
||||
|
||||
internal ref ValueLinkList<Mobile> Mobiles => ref _mobiles;
|
||||
|
||||
|
|
@ -1553,12 +1549,12 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
|
||||
public void OnMultiEnter(BaseMulti multi)
|
||||
{
|
||||
Utility.Add(ref _multis, multi);
|
||||
_multis.Add(multi);
|
||||
}
|
||||
|
||||
public void OnMultiLeave(BaseMulti multi)
|
||||
{
|
||||
Utility.Remove(ref _multis, multi);
|
||||
_multis.Remove(multi);
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
|
|
|
|||
|
|
@ -1,298 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2023 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: PooledEnumeration.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server;
|
||||
|
||||
public interface IPooledEnumerable<T> : IEnumerable<T>, IDisposable
|
||||
{
|
||||
}
|
||||
|
||||
public static class PooledEnumeration
|
||||
{
|
||||
public delegate IEnumerable<T> Selector<out T>(Map.Sector sector, Rectangle2D bounds);
|
||||
|
||||
static PooledEnumeration()
|
||||
{
|
||||
MultiSelector = SelectMultis;
|
||||
MultiTileSelector = SelectMultiTiles;
|
||||
}
|
||||
|
||||
public static Selector<BaseMulti> MultiSelector { get; set; }
|
||||
public static Selector<StaticTile[]> MultiTileSelector { get; set; }
|
||||
|
||||
public static IEnumerable<BaseMulti> SelectMultis(Map.Sector s, Rectangle2D bounds)
|
||||
{
|
||||
var entities = new List<BaseMulti>(s.Multis.Count);
|
||||
for (int i = s.Multis.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BaseMulti multi = s.Multis[i];
|
||||
if (multi is { Deleted: false } && bounds.Contains(multi.Location))
|
||||
{
|
||||
entities.Add(multi);
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
public static IEnumerable<StaticTile[]> SelectMultiTiles(Map.Sector s, Rectangle2D bounds)
|
||||
{
|
||||
for (int l = s.Multis.Count - 1; l >= 0; --l)
|
||||
{
|
||||
BaseMulti o = s.Multis[l];
|
||||
if (o?.Deleted != false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MultiComponentList c = o.Components;
|
||||
|
||||
int x, y, xo, yo;
|
||||
StaticTile[] t, r;
|
||||
|
||||
for (x = bounds.Start.X; x < bounds.End.X; x++)
|
||||
{
|
||||
xo = x - (o.X + c.Min.X);
|
||||
|
||||
if (xo < 0 || xo >= c.Width)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = bounds.Start.Y; y < bounds.End.Y; y++)
|
||||
{
|
||||
yo = y - (o.Y + c.Min.Y);
|
||||
|
||||
if (yo < 0 || yo >= c.Height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
t = c.Tiles[xo][yo];
|
||||
|
||||
if (t.Length <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
r = new StaticTile[t.Length];
|
||||
|
||||
for (var i = 0; i < t.Length; i++)
|
||||
{
|
||||
r[i] = t[i];
|
||||
r[i].Z += o.Z;
|
||||
}
|
||||
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static PooledEnumerable<BaseMulti> GetMultis(Map map, Rectangle2D bounds) =>
|
||||
PooledEnumerable<BaseMulti>.Instantiate(map, bounds, MultiSelector ?? SelectMultis);
|
||||
|
||||
public static PooledEnumerable<StaticTile[]> GetMultiTiles(Map map, Rectangle2D bounds) =>
|
||||
PooledEnumerable<StaticTile[]>.Instantiate(map, bounds, MultiTileSelector ?? SelectMultiTiles);
|
||||
|
||||
public static IEnumerable<Map.Sector> EnumerateSectors(Map map, Rectangle2D bounds)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var x1 = bounds.Start.X;
|
||||
var y1 = bounds.Start.Y;
|
||||
var x2 = bounds.End.X;
|
||||
var y2 = bounds.End.Y;
|
||||
|
||||
if (!Bound(map, ref x1, ref y1, ref x2, ref y2, out var xSector, out var ySector))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
|
||||
while (NextSector(map, x1, y1, x2, y2, ref index, ref xSector, ref ySector, out var s))
|
||||
{
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Bound(
|
||||
Map map,
|
||||
ref int x1,
|
||||
ref int y1,
|
||||
ref int x2,
|
||||
ref int y2,
|
||||
out int xSector,
|
||||
out int ySector
|
||||
)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
xSector = ySector = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
map.Bound(x1, y1, out x1, out y1);
|
||||
map.Bound(x2 - 1, y2 - 1, out x2, out y2);
|
||||
|
||||
x1 >>= Map.SectorShift;
|
||||
y1 >>= Map.SectorShift;
|
||||
x2 >>= Map.SectorShift;
|
||||
y2 >>= Map.SectorShift;
|
||||
|
||||
xSector = x1;
|
||||
ySector = y1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool NextSector(
|
||||
Map map,
|
||||
int x1,
|
||||
int y1,
|
||||
int x2,
|
||||
int y2,
|
||||
ref int index,
|
||||
ref int xSector,
|
||||
ref int ySector,
|
||||
out Map.Sector s
|
||||
)
|
||||
{
|
||||
if (map == null)
|
||||
{
|
||||
s = null;
|
||||
xSector = ySector = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map == Map.Internal)
|
||||
{
|
||||
s = map.InvalidSector;
|
||||
xSector = ySector = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index++ > 0)
|
||||
{
|
||||
if (++ySector > y2)
|
||||
{
|
||||
ySector = y1;
|
||||
|
||||
if (++xSector > x2)
|
||||
{
|
||||
xSector = x1;
|
||||
|
||||
s = map.InvalidSector;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s = map.GetRealSector(xSector, ySector);
|
||||
return true;
|
||||
}
|
||||
|
||||
public class NullEnumerable<T> : IPooledEnumerable<T>
|
||||
{
|
||||
public static readonly NullEnumerable<T> Instance = new();
|
||||
|
||||
private readonly IEnumerable<T> m_Empty = Enumerable.Empty<T>();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => m_Empty.GetEnumerator();
|
||||
|
||||
public IEnumerator<T> GetEnumerator() => m_Empty.GetEnumerator();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PooledEnumerable<T> : IPooledEnumerable<T>
|
||||
{
|
||||
private static readonly Queue<PooledEnumerable<T>> _Buffer = new(0x400);
|
||||
|
||||
private bool m_IsDisposed;
|
||||
|
||||
private List<T> m_Pool = new(0x40);
|
||||
|
||||
public PooledEnumerable(IEnumerable<T> pool)
|
||||
{
|
||||
m_Pool.AddRange(pool);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_IsDisposed = true;
|
||||
|
||||
m_Pool.Clear();
|
||||
m_Pool.Capacity = Math.Max(m_Pool.Capacity, 0x100);
|
||||
|
||||
lock (((ICollection)_Buffer).SyncRoot)
|
||||
{
|
||||
_Buffer.Enqueue(this);
|
||||
}
|
||||
}
|
||||
|
||||
~PooledEnumerable()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => m_Pool.GetEnumerator();
|
||||
|
||||
public IEnumerator<T> GetEnumerator() => m_Pool.GetEnumerator();
|
||||
|
||||
|
||||
#pragma warning disable CA1000 // Do not declare static members on generic types
|
||||
public static PooledEnumerable<T> Instantiate(
|
||||
Map map, Rectangle2D bounds, Selector<T> selector
|
||||
)
|
||||
{
|
||||
PooledEnumerable<T> e = null;
|
||||
|
||||
lock (((ICollection)_Buffer).SyncRoot)
|
||||
{
|
||||
if (_Buffer.Count > 0)
|
||||
{
|
||||
e = _Buffer.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
var pool = EnumerateSectors(map, bounds).SelectMany(s => selector(s, bounds));
|
||||
|
||||
if (e == null)
|
||||
{
|
||||
return new PooledEnumerable<T>(pool);
|
||||
}
|
||||
|
||||
e.m_Pool.AddRange(pool);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,18 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2023 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: TileList.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
@ -6,33 +21,17 @@ namespace Server;
|
|||
|
||||
public class TileList
|
||||
{
|
||||
private static readonly StaticTile[] m_EmptyTiles = Array.Empty<StaticTile>();
|
||||
private StaticTile[] m_Tiles;
|
||||
|
||||
public TileList()
|
||||
{
|
||||
m_Tiles = new StaticTile[8];
|
||||
Count = 0;
|
||||
}
|
||||
private static readonly StaticTile[] _emptyTiles = Array.Empty<StaticTile>();
|
||||
private StaticTile[] _tiles;
|
||||
|
||||
public int Count { get; private set; }
|
||||
|
||||
public void AddRange(StaticTile[] tiles)
|
||||
public void AddRange(ReadOnlySpan<StaticTile> tiles)
|
||||
{
|
||||
if (Count + tiles.Length > m_Tiles.Length)
|
||||
{
|
||||
var old = m_Tiles;
|
||||
m_Tiles = new StaticTile[(Count + tiles.Length) * 2];
|
||||
|
||||
for (var i = 0; i < old.Length; ++i)
|
||||
{
|
||||
m_Tiles[i] = old[i];
|
||||
}
|
||||
}
|
||||
|
||||
TryResize(tiles.Length);
|
||||
for (var i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
m_Tiles[Count++] = tiles[i];
|
||||
_tiles[Count++] = tiles[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,15 +40,15 @@ public class TileList
|
|||
|
||||
public void Add(StaticTile tile)
|
||||
{
|
||||
TryResize();
|
||||
m_Tiles[Count] = tile;
|
||||
TryResize(1);
|
||||
_tiles[Count] = tile;
|
||||
++Count;
|
||||
}
|
||||
|
||||
public void Add(ushort id, byte x, byte y, sbyte z, short hue = 0)
|
||||
{
|
||||
TryResize();
|
||||
ref var tile = ref m_Tiles[Count];
|
||||
TryResize(1);
|
||||
ref var tile = ref _tiles[Count];
|
||||
tile.m_ID = id;
|
||||
tile.m_X = x;
|
||||
tile.m_Y = y;
|
||||
|
|
@ -60,22 +59,24 @@ public class TileList
|
|||
|
||||
public void Add(ushort id, sbyte z)
|
||||
{
|
||||
TryResize();
|
||||
m_Tiles[Count].m_ID = id;
|
||||
m_Tiles[Count].m_Z = z;
|
||||
TryResize(1);
|
||||
_tiles[Count].m_ID = id;
|
||||
_tiles[Count].m_Z = z;
|
||||
++Count;
|
||||
}
|
||||
|
||||
private void TryResize()
|
||||
private void TryResize(int length)
|
||||
{
|
||||
if (Count + 1 > m_Tiles.Length)
|
||||
_tiles ??= new StaticTile[length];
|
||||
|
||||
if (Count + length > _tiles.Length)
|
||||
{
|
||||
var old = m_Tiles;
|
||||
m_Tiles = new StaticTile[old.Length * 2];
|
||||
var old = _tiles;
|
||||
_tiles = new StaticTile[old.Length * 2];
|
||||
|
||||
for (var i = 0; i < old.Length; ++i)
|
||||
{
|
||||
m_Tiles[i] = old[i];
|
||||
_tiles[i] = old[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,16 +85,13 @@ public class TileList
|
|||
{
|
||||
if (Count == 0)
|
||||
{
|
||||
return m_EmptyTiles;
|
||||
return _emptyTiles;
|
||||
}
|
||||
|
||||
var tiles = new StaticTile[Count];
|
||||
|
||||
for (var i = 0; i < Count; ++i)
|
||||
{
|
||||
tiles[i] = m_Tiles[i];
|
||||
}
|
||||
Array.Resize(ref _tiles, Count);
|
||||
var tiles = _tiles;
|
||||
|
||||
_tiles = null;
|
||||
Count = 0;
|
||||
|
||||
return tiles;
|
||||
|
|
|
|||
|
|
@ -240,38 +240,27 @@ public class TileMatrix
|
|||
{
|
||||
var tiles = GetStaticBlock(x >> 3, y >> 3);
|
||||
|
||||
if (multis)
|
||||
if (!multis)
|
||||
{
|
||||
var eable = _map.GetMultiTilesAt(x, y);
|
||||
|
||||
if (eable == PooledEnumeration.NullEnumerable<StaticTile[]>.Instance)
|
||||
{
|
||||
return tiles[x & 0x7][y & 0x7];
|
||||
}
|
||||
|
||||
var any = false;
|
||||
|
||||
foreach (var multiTiles in eable)
|
||||
{
|
||||
if (!any)
|
||||
{
|
||||
any = true;
|
||||
}
|
||||
|
||||
m_TilesList.AddRange(multiTiles);
|
||||
}
|
||||
|
||||
if (!any)
|
||||
{
|
||||
return tiles[x & 0x7][y & 0x7];
|
||||
}
|
||||
|
||||
m_TilesList.AddRange(tiles[x & 0x7][y & 0x7]);
|
||||
|
||||
return m_TilesList.ToArray();
|
||||
return tiles[x & 0x7][y & 0x7];
|
||||
}
|
||||
|
||||
return tiles[x & 0x7][y & 0x7];
|
||||
var any = false;
|
||||
|
||||
foreach (var multiTiles in _map.GetMultiTilesAt(x, y))
|
||||
{
|
||||
any = true;
|
||||
m_TilesList.AddRange(multiTiles);
|
||||
}
|
||||
|
||||
if (!any)
|
||||
{
|
||||
return tiles[x & 0x7][y & 0x7];
|
||||
}
|
||||
|
||||
m_TilesList.AddRange(tiles[x & 0x7][y & 0x7]);
|
||||
|
||||
return m_TilesList.ToArray();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
|
|
|
|||
|
|
@ -243,11 +243,9 @@ namespace Server.Multis
|
|||
|
||||
public static BaseBoat FindBoatAt(Point3D loc, Map map)
|
||||
{
|
||||
var sector = map.GetSector(loc);
|
||||
|
||||
for (var i = 0; i < sector.Multis.Count; i++)
|
||||
foreach (var boat in map.GetMultisAt<BaseBoat>(loc))
|
||||
{
|
||||
if (sector.Multis[i] is BaseBoat boat && boat.Contains(loc.X, loc.Y))
|
||||
if (boat.Contains(loc.X, loc.Y))
|
||||
{
|
||||
return boat;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1401,11 +1401,9 @@ namespace Server.Multis
|
|||
return null;
|
||||
}
|
||||
|
||||
var sector = map.GetSector(loc);
|
||||
|
||||
for (var i = 0; i < sector.Multis.Count; ++i)
|
||||
foreach (var house in map.GetMultisAt<BaseHouse>(loc))
|
||||
{
|
||||
if (sector.Multis[i] is BaseHouse house && house.IsInside(loc, height))
|
||||
if (house.IsInside(loc, height))
|
||||
{
|
||||
return house;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,58 +370,35 @@ namespace Server.Multis
|
|||
}
|
||||
}
|
||||
|
||||
var _sectors = new List<Map.Sector>();
|
||||
var _houses = new List<BaseHouse>();
|
||||
|
||||
for (var i = 0; i < yard.Count; i++)
|
||||
{
|
||||
var sector = map.GetSector(yard[i]);
|
||||
var yardPoint = yard[i];
|
||||
|
||||
if (!_sectors.Contains(sector))
|
||||
foreach (var house in map.GetMultisAt<BaseHouse>(yardPoint))
|
||||
{
|
||||
_sectors.Add(sector);
|
||||
|
||||
for (var j = 0; j < sector.Multis?.Count; j++)
|
||||
{
|
||||
if (sector.Multis[j] is BaseHouse)
|
||||
{
|
||||
var _house = (BaseHouse)sector.Multis[j];
|
||||
if (!_houses.Contains(_house))
|
||||
{
|
||||
_houses.Add(_house);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < yard.Count; ++i)
|
||||
{
|
||||
foreach (var b in _houses)
|
||||
{
|
||||
if (b.Contains(yard[i]))
|
||||
if (house.Contains(yard[i]))
|
||||
{
|
||||
return HousePlacementResult.BadStatic; // Broke rule #3
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Point2D yardPoint = yard[i];
|
||||
|
||||
IPooledEnumerable eable = map.GetMultiTilesAt( yardPoint.X, yardPoint.Y );
|
||||
|
||||
foreach ( StaticTile[] tile in eable )
|
||||
{
|
||||
for ( int j = 0; j < tile.Length; ++j )
|
||||
{
|
||||
if ((TileData.ItemTable[tile[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0)
|
||||
{
|
||||
eable.Free();
|
||||
return HousePlacementResult.BadStatic; // Broke rule #3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();*/
|
||||
// TODO: Should we check for MultiTilesAt each yard point?
|
||||
// for (var i = 0; i < yard.Count; i++)
|
||||
// {
|
||||
// var yardPoint = yard[i];
|
||||
//
|
||||
// foreach (var tiles in map.GetMultiTilesAt(yardPoint))
|
||||
// {
|
||||
// for (int j = 0; j < tiles.Length; ++j)
|
||||
// {
|
||||
// if ((TileData.ItemTable[tiles[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0)
|
||||
// {
|
||||
// return HousePlacementResult.BadStatic; // Broke rule #3
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return HousePlacementResult.Valid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,12 +158,8 @@ namespace Server.Spells
|
|||
return false;
|
||||
}
|
||||
|
||||
var sector = map.GetSector(p.X, p.Y);
|
||||
|
||||
for (var i = 0; i < sector.Multis.Count; ++i)
|
||||
foreach (var multi in map.GetMultisAt(p))
|
||||
{
|
||||
var multi = sector.Multis[i];
|
||||
|
||||
if (multi is BaseHouse bh)
|
||||
{
|
||||
if (houses && bh.IsInside(p, 16) || housingrange > 0 && bh.InRange(p, housingrange))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue