fix: Removes GetObjectsInRange and fixes boat planks closing (#1579)
## BREAKING CHANGE - Deletes `map.GetObjectsInRange` and `map.GetObejctsInBounds` ### Notes Developers are expected to enumerate mobiles and items separately now using `map.GetMobilesInRange` and `map.GetItemsInRange`. This helps keep the code streamlined so we don't have to maintain multiple copies of ref struct enumerators that do the same thing. ### Fixes - [X] Fixes bug with planks closing - [X] Fixes issue with iterating items/mobiles from a null map
This commit is contained in:
parent
cb1638591b
commit
977fdc2c5a
21 changed files with 543 additions and 461 deletions
|
|
@ -2445,15 +2445,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0;
|
||||
|
||||
public IPooledEnumerable<IEntity> GetObjectsInRange(int range)
|
||||
{
|
||||
var map = m_Map;
|
||||
|
||||
return map == null
|
||||
? PooledEnumeration.NullEnumerable<IEntity>.Instance
|
||||
: map.GetObjectsInRange(m_Parent == null ? m_Location : GetWorldLocation(), range);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Map.ItemAtEnumerable<Item> GetItemsAt() =>
|
||||
m_Map == null ? Map.ItemAtEnumerable<Item>.Empty : m_Map.GetItemsAt(m_Parent == null ? m_Location : GetWorldLocation());
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ namespace Server;
|
|||
|
||||
public partial class Map
|
||||
{
|
||||
private static ValueLinkList<Item> _emptyItemLinkList = new();
|
||||
public static ref readonly ValueLinkList<Item> EmptyItemLinkList => ref _emptyItemLinkList;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemAtEnumerable<Item> GetItemsAt(Point3D p) => GetItemsAt<Item>(p);
|
||||
|
||||
|
|
@ -110,7 +113,15 @@ public partial class Map
|
|||
{
|
||||
_started = false;
|
||||
_location = loc;
|
||||
_linkList = ref map.GetRealSector(loc.m_X, loc.m_Y).Items;
|
||||
if (map == null)
|
||||
{
|
||||
_linkList = ref EmptyItemLinkList;
|
||||
}
|
||||
else
|
||||
{
|
||||
_linkList = ref map.GetRealSector(loc.m_X, loc.m_Y).Items;
|
||||
}
|
||||
|
||||
_version = 0;
|
||||
_current = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ namespace Server;
|
|||
|
||||
public partial class Map
|
||||
{
|
||||
private static ValueLinkList<Mobile> _emptyMobileLinkList = new();
|
||||
public static ref readonly ValueLinkList<Mobile> EmptyMobileLinkList => ref _emptyMobileLinkList;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MobileAtEnumerable<Mobile> GetMobilesAt(Point3D p) => GetMobilesAt<Mobile>(p);
|
||||
|
||||
|
|
@ -110,7 +113,14 @@ public partial class Map
|
|||
{
|
||||
_started = false;
|
||||
_location = loc;
|
||||
_linkList = ref map.GetRealSector(loc.m_X, loc.m_Y).Mobiles;
|
||||
if (map == null)
|
||||
{
|
||||
_linkList = ref EmptyMobileLinkList;
|
||||
}
|
||||
else
|
||||
{
|
||||
_linkList = ref map.GetRealSector(loc.m_X, loc.m_Y).Mobiles;
|
||||
}
|
||||
_version = 0;
|
||||
_current = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -865,25 +865,15 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
public IPooledEnumerable<StaticTile[]> GetMultiTilesAt(int x, int y) =>
|
||||
PooledEnumeration.GetMultiTiles(this, new Rectangle2D(x, y, 1, 1));
|
||||
|
||||
public IPooledEnumerable<IEntity> GetObjectsInRange(Point3D p) => GetObjectsInRange(p, Core.GlobalMaxUpdateRange);
|
||||
|
||||
public IPooledEnumerable<IEntity> GetObjectsInRange(Point3D p, int range) =>
|
||||
GetObjectsInBounds(new Rectangle2D(p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1));
|
||||
|
||||
public IPooledEnumerable<IEntity> GetObjectsInBounds(Rectangle2D bounds) =>
|
||||
PooledEnumeration.GetEntities(this, bounds);
|
||||
|
||||
public bool CanFit(
|
||||
Point3D p, int height, bool checkBlocksFit = false, bool checkMobiles = true,
|
||||
bool requireSurface = true
|
||||
) =>
|
||||
CanFit(p.m_X, p.m_Y, p.m_Z, height, checkBlocksFit, checkMobiles, requireSurface);
|
||||
) => CanFit(p.m_X, p.m_Y, p.m_Z, height, checkBlocksFit, checkMobiles, requireSurface);
|
||||
|
||||
public bool CanFit(
|
||||
Point2D p, int z, int height, bool checkBlocksFit = false, bool checkMobiles = true,
|
||||
bool requireSurface = true
|
||||
) =>
|
||||
CanFit(p.m_X, p.m_Y, z, height, checkBlocksFit, checkMobiles, requireSurface);
|
||||
) => CanFit(p.m_X, p.m_Y, z, height, checkBlocksFit, checkMobiles, requireSurface);
|
||||
|
||||
public bool CanFit(
|
||||
int x, int y, int z, int height, bool checkBlocksFit = false, bool checkMobiles = true,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Collections;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server;
|
||||
|
|
@ -32,32 +31,13 @@ public static class PooledEnumeration
|
|||
|
||||
static PooledEnumeration()
|
||||
{
|
||||
EntitySelector = SelectEntities;
|
||||
MultiSelector = SelectMultis;
|
||||
MultiTileSelector = SelectMultiTiles;
|
||||
}
|
||||
|
||||
public static Selector<IEntity> EntitySelector { get; set; }
|
||||
public static Selector<Mobile> MobileSelector { get; set; }
|
||||
public static Selector<BaseMulti> MultiSelector { get; set; }
|
||||
public static Selector<StaticTile[]> MultiTileSelector { get; set; }
|
||||
|
||||
public static IEnumerable<IEntity> SelectEntities(Map.Sector s, Rectangle2D bounds)
|
||||
{
|
||||
var entities = new List<IEntity>(s.Mobiles.Count + s.Items.Count);
|
||||
foreach (var mob in s.Mobiles)
|
||||
{
|
||||
entities.Add(mob);
|
||||
}
|
||||
|
||||
foreach (var item in s.Items)
|
||||
{
|
||||
entities.Add(item);
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
public static IEnumerable<BaseMulti> SelectMultis(Map.Sector s, Rectangle2D bounds)
|
||||
{
|
||||
var entities = new List<BaseMulti>(s.Multis.Count);
|
||||
|
|
@ -126,9 +106,6 @@ public static class PooledEnumeration
|
|||
}
|
||||
}
|
||||
|
||||
public static PooledEnumerable<IEntity> GetEntities(Map map, Rectangle2D bounds) =>
|
||||
PooledEnumerable<IEntity>.Instantiate(map, bounds, EntitySelector ?? SelectEntities);
|
||||
|
||||
public static PooledEnumerable<BaseMulti> GetMultis(Map map, Rectangle2D bounds) =>
|
||||
PooledEnumerable<BaseMulti>.Instantiate(map, bounds, MultiSelector ?? SelectMultis);
|
||||
|
||||
|
|
|
|||
|
|
@ -4342,25 +4342,25 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
{
|
||||
using var moveQueue = PooledRefQueue<IEntity>.Create(2048);
|
||||
using var moveClientQueue = PooledRefQueue<Mobile>.Create(2048);
|
||||
var eable = m_Map.GetObjectsInRange(m_Location, Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var o in eable)
|
||||
foreach (var mob in m_Map.GetMobilesInRange(m_Location, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
if (o == this)
|
||||
if (mob == this)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (o is Mobile mob)
|
||||
if (mob.NetState != null)
|
||||
{
|
||||
if (mob.NetState != null)
|
||||
{
|
||||
moveClientQueue.Enqueue(mob);
|
||||
}
|
||||
|
||||
moveQueue.Enqueue(mob);
|
||||
moveClientQueue.Enqueue(mob);
|
||||
}
|
||||
else if (o is Item item && item.HandlesOnMovement)
|
||||
|
||||
moveQueue.Enqueue(mob);
|
||||
}
|
||||
|
||||
foreach (var item in m_Map.GetItemsInRange(m_Location, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
if (item.HandlesOnMovement)
|
||||
{
|
||||
moveQueue.Enqueue(item);
|
||||
}
|
||||
|
|
@ -5561,44 +5561,27 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
|
||||
if (m_Map != null)
|
||||
{
|
||||
var eable = m_Map.GetObjectsInRange(m_Location, range);
|
||||
|
||||
foreach (var o in eable)
|
||||
foreach (var heard in m_Map.GetMobilesInRange(m_Location, range))
|
||||
{
|
||||
if (o is Mobile heard)
|
||||
if (!heard.CanSee(this) || !NoSpeechLOS && heard.Player && !heard.InLOS(this))
|
||||
{
|
||||
if (!heard.CanSee(this) || !NoSpeechLOS && heard.Player && !heard.InLOS(this))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (heard.m_NetState != null)
|
||||
{
|
||||
hears.Add(heard);
|
||||
}
|
||||
|
||||
if (heard.HandlesOnSpeech(this))
|
||||
{
|
||||
onSpeech.Add(heard);
|
||||
}
|
||||
|
||||
for (var i = 0; i < heard.Items.Count; ++i)
|
||||
{
|
||||
var item = heard.Items[i];
|
||||
|
||||
if (item.HandlesOnSpeech)
|
||||
{
|
||||
onSpeech.Add(item);
|
||||
}
|
||||
|
||||
if (item is Container container)
|
||||
{
|
||||
AddSpeechItemsFrom(onSpeech, container);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (o is Item item)
|
||||
|
||||
if (heard.m_NetState != null)
|
||||
{
|
||||
hears.Add(heard);
|
||||
}
|
||||
|
||||
if (heard.HandlesOnSpeech(this))
|
||||
{
|
||||
onSpeech.Add(heard);
|
||||
}
|
||||
|
||||
for (var i = 0; i < heard.Items.Count; ++i)
|
||||
{
|
||||
var item = heard.Items[i];
|
||||
|
||||
if (item.HandlesOnSpeech)
|
||||
{
|
||||
onSpeech.Add(item);
|
||||
|
|
@ -5611,6 +5594,19 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var item in m_Map.GetItemsInRange(m_Location, range))
|
||||
{
|
||||
if (item.HandlesOnSpeech)
|
||||
{
|
||||
onSpeech.Add(item);
|
||||
}
|
||||
|
||||
if (item is Container container)
|
||||
{
|
||||
AddSpeechItemsFrom(onSpeech, container);
|
||||
}
|
||||
}
|
||||
|
||||
object mutateContext = null;
|
||||
var mutatedText = text;
|
||||
SpeechEventArgs mutatedArgs = null;
|
||||
|
|
@ -6856,23 +6852,19 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
return;
|
||||
}
|
||||
|
||||
var eable = m_Map.GetObjectsInRange(m_Location, Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var o in eable)
|
||||
foreach (var m in m_Map.GetMobilesInRange(m_Location, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
if (o is Mobile m)
|
||||
if (m != this && Utility.InUpdateRange(m_Location, m.m_Location))
|
||||
{
|
||||
if (m != this && Utility.InUpdateRange(m_Location, m.m_Location))
|
||||
{
|
||||
m_NetState.SendRemoveEntity(m.Serial);
|
||||
}
|
||||
m_NetState.SendRemoveEntity(m.Serial);
|
||||
}
|
||||
else if (o is Item item)
|
||||
}
|
||||
|
||||
foreach (var item in m_Map.GetItemsInRange(m_Location, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
if (InRange(item.Location, item.GetUpdateRange(this)))
|
||||
{
|
||||
if (InRange(item.Location, item.GetUpdateRange(this)))
|
||||
{
|
||||
m_NetState.SendRemoveEntity(item.Serial);
|
||||
}
|
||||
m_NetState.SendRemoveEntity(item.Serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6923,36 +6915,32 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
return;
|
||||
}
|
||||
|
||||
var eable = m_Map.GetObjectsInRange(m_Location, Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var o in eable)
|
||||
foreach (var m in m_Map.GetMobilesInRange(m_Location, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
if (o is Item item)
|
||||
if (CanSee(m) && Utility.InUpdateRange(m_Location, m.m_Location))
|
||||
{
|
||||
if (CanSee(item) && InRange(item.Location, item.GetUpdateRange(this)))
|
||||
ns.SendMobileIncoming(this, m);
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
item.SendInfoTo(ns);
|
||||
ns.SendMobileHealthbar(m, Healthbar.Poison);
|
||||
ns.SendMobileHealthbar(m, Healthbar.Yellow);
|
||||
}
|
||||
|
||||
if (m.IsDeadBondedPet)
|
||||
{
|
||||
ns.SendBondedStatus(m.Serial, true);
|
||||
}
|
||||
|
||||
m.SendOPLPacketTo(ns);
|
||||
}
|
||||
else if (o is Mobile m)
|
||||
}
|
||||
|
||||
foreach (var item in m_Map.GetItemsInRange(m_Location, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
if (CanSee(item) && InRange(item.Location, item.GetUpdateRange(this)))
|
||||
{
|
||||
if (CanSee(m) && Utility.InUpdateRange(m_Location, m.m_Location))
|
||||
{
|
||||
ns.SendMobileIncoming(this, m);
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
ns.SendMobileHealthbar(m, Healthbar.Poison);
|
||||
ns.SendMobileHealthbar(m, Healthbar.Yellow);
|
||||
}
|
||||
|
||||
if (m.IsDeadBondedPet)
|
||||
{
|
||||
ns.SendBondedStatus(m.Serial, true);
|
||||
}
|
||||
|
||||
m.SendOPLPacketTo(ns);
|
||||
}
|
||||
item.SendInfoTo(ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7310,67 +7298,70 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
if (ourState != null)
|
||||
{
|
||||
// We are attached to a client, so it's a bit more complex. We need to send new items and people to ourself, and ourself to other clients
|
||||
foreach (var o in map.GetObjectsInRange(newLocation, Core.GlobalMaxUpdateRange))
|
||||
|
||||
foreach (var m in map.GetMobilesInRange(newLocation, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
if (o is Item item)
|
||||
if (m == this)
|
||||
{
|
||||
var range = item.GetUpdateRange(this);
|
||||
var loc = item.Location;
|
||||
|
||||
if (!Utility.InRange(oldLocation, loc, range) && Utility.InRange(newLocation, loc, range) &&
|
||||
CanSee(item))
|
||||
{
|
||||
item.SendInfoTo(ourState);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (o != this && o is Mobile m)
|
||||
|
||||
if (!Utility.InUpdateRange(newLocation, m.m_Location))
|
||||
{
|
||||
if (!Utility.InUpdateRange(newLocation, m.m_Location))
|
||||
continue;
|
||||
}
|
||||
|
||||
var inOldRange = Utility.InUpdateRange(oldLocation, m.m_Location);
|
||||
var ns = m.m_NetState;
|
||||
|
||||
if (ns != null &&
|
||||
(isTeleport && (!ns.HighSeas || !NoMoveHS) || !inOldRange) && m.CanSee(this))
|
||||
{
|
||||
ns.SendMobileIncoming(m, this);
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
continue;
|
||||
ns.SendMobileHealthbar(this, Healthbar.Poison);
|
||||
ns.SendMobileHealthbar(this, Healthbar.Yellow);
|
||||
}
|
||||
|
||||
var inOldRange = Utility.InUpdateRange(oldLocation, m.m_Location);
|
||||
var ns = m.m_NetState;
|
||||
|
||||
if (ns != null &&
|
||||
(isTeleport && (!ns.HighSeas || !NoMoveHS) || !inOldRange) && m.CanSee(this))
|
||||
if (IsDeadBondedPet)
|
||||
{
|
||||
ns.SendMobileIncoming(m, this);
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
ns.SendMobileHealthbar(this, Healthbar.Poison);
|
||||
ns.SendMobileHealthbar(this, Healthbar.Yellow);
|
||||
}
|
||||
|
||||
if (IsDeadBondedPet)
|
||||
{
|
||||
ns.SendBondedStatus(Serial, true);
|
||||
}
|
||||
|
||||
SendOPLPacketTo(ns);
|
||||
ns.SendBondedStatus(Serial, true);
|
||||
}
|
||||
|
||||
if (inOldRange || !CanSee(m))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
SendOPLPacketTo(ns);
|
||||
}
|
||||
|
||||
ourState.SendMobileIncoming(this, m);
|
||||
if (inOldRange || !CanSee(m))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ourState.StygianAbyss)
|
||||
{
|
||||
ourState.SendMobileHealthbar(m, Healthbar.Poison);
|
||||
ourState.SendMobileHealthbar(m, Healthbar.Yellow);
|
||||
}
|
||||
ourState.SendMobileIncoming(this, m);
|
||||
|
||||
if (m.IsDeadBondedPet)
|
||||
{
|
||||
ourState.SendBondedStatus(m.Serial, true);
|
||||
}
|
||||
if (ourState.StygianAbyss)
|
||||
{
|
||||
ourState.SendMobileHealthbar(m, Healthbar.Poison);
|
||||
ourState.SendMobileHealthbar(m, Healthbar.Yellow);
|
||||
}
|
||||
|
||||
m.SendOPLPacketTo(ourState);
|
||||
if (m.IsDeadBondedPet)
|
||||
{
|
||||
ourState.SendBondedStatus(m.Serial, true);
|
||||
}
|
||||
|
||||
m.SendOPLPacketTo(ourState);
|
||||
}
|
||||
foreach (var item in map.GetItemsInRange(newLocation, Core.GlobalMaxUpdateRange))
|
||||
{
|
||||
var range = item.GetUpdateRange(this);
|
||||
var loc = item.Location;
|
||||
|
||||
if (!Utility.InRange(oldLocation, loc, range) && Utility.InRange(newLocation, loc, range) &&
|
||||
CanSee(item))
|
||||
{
|
||||
item.SendInfoTo(ourState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8098,10 +8089,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
public Map.ItemBoundsEnumerable<T> GetItemsInRange<T>(int range) where T : Item =>
|
||||
m_Map == null ? Map.ItemBoundsEnumerable<T>.Empty : m_Map.GetItemsInRange<T>(m_Location, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IPooledEnumerable<IEntity> GetObjectsInRange(int range) =>
|
||||
m_Map?.GetObjectsInRange(m_Location, range) ?? PooledEnumeration.NullEnumerable<IEntity>.Instance;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Map.MobileAtEnumerable<Mobile> GetMobilesInRange() => GetMobilesInRange<Mobile>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1762,7 +1762,7 @@ public static class Utility
|
|||
span == default || span.IsEmpty || span.IsWhiteSpace();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool InTypeList(this Item item, Type[] types) => item.GetType().InTypeList(types);
|
||||
public static bool InTypeList<T>(this T obj, Type[] types) => obj.GetType().InTypeList(types);
|
||||
|
||||
public static bool InTypeList(this Type t, Type[] types)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue