diff --git a/Projects/Benchmarks/Benchmarks/Map/MapSelectors.cs b/Projects/Benchmarks/Benchmarks/Map/MapSelectors.cs new file mode 100644 index 000000000..4c47b7189 --- /dev/null +++ b/Projects/Benchmarks/Benchmarks/Map/MapSelectors.cs @@ -0,0 +1,665 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; +using Server; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Benchmarks +{ + [SimpleJob(RuntimeMoniker.NetCoreApp50)] + public class MapSelectors + { + static readonly Sector sector = new Sector(); + static Server.Rectangle2D bounds = new Server.Rectangle2D(0, 0, 100, 100); + + public static void Init() + { + for (int i = 0; i < 50; ++i) + { + sector.Multis.Add(new BaseMulti()); + } + for (int i = 0; i < 1000; ++i) + { + sector.BItems.Add(new BItem()); + } + for (int i = 0; i < 1000; ++i) + { + sector.Mobiles.Add(new Mobile()); + } + } + + #region MultiTiles + [Benchmark] + public void SelectMultiTilesNew() + { + foreach(StaticTile[] tiles in SelectMultiTiles(sector, bounds)) + { + for(int i = 0; i < tiles.Length; ++i) + { + int id = tiles[i].ID; + } + } + } + + [Benchmark] + public void SelectMultiTilesLinq() + { + foreach(StaticTile[] tiles in SelectMultiTilesLinq(sector, bounds)) + { + for(int i = 0; i < tiles.Length; ++i) + { + int id = tiles[i].ID; + } + } + } + + public IEnumerable SelectMultiTilesLinq(Sector s, Server.Rectangle2D bounds) + { + foreach (var o in s.Multis.Where(o => o != null && !o.Deleted)) + { + var 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 IEnumerable SelectMultiTiles(Sector s, Server.Rectangle2D bounds) + { + for (int l = s.Multis.Count - 1; l >= 0; --l) + { + BaseMulti o = s.Multis[l]; + if (o != null && !o.Deleted) + { + 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; + } + } + } + } + } + + #endregion + + #region Multis + [Benchmark] + public void SelectMultisNew() + { + SelectMultis(sector, bounds); + } + + [Benchmark] + public void SelectMultisLinq() + { + SelectMultisLinq(sector, bounds); + } + + public IEnumerable SelectMultisLinq(Sector s, Server.Rectangle2D bounds) + { + return s.Multis.Where(o => o != null && !o.Deleted && bounds.Contains(o.Location)); + } + + public IEnumerable SelectMultis(Sector s, Server.Rectangle2D bounds) + { + List entities = new List(s.Multis.Count); + for (int i = s.Multis.Count - 1; i >= 0; --i) + { + BaseMulti BItem = s.Multis[i]; + if (BItem != null && !BItem.Deleted && bounds.Contains(BItem.Location)) + entities.Add(BItem); + } + return entities; + } + #endregion + + #region BItems + [Benchmark] + public void SelectBItemsNew() + { + SelectBItems(sector, bounds); + } + + [Benchmark] + public void SelectBItemsLinq() + { + SelectBItemsLinq(sector, bounds); + } + + public IEnumerable SelectBItemsLinq(Sector s, Server.Rectangle2D bounds) where T : BItem + { + return s.BItems.OfType().Where(o => o != null && !o.Deleted && o.Parent == null && bounds.Contains(o.Location)); + } + + public IEnumerable SelectBItems(Sector s, Server.Rectangle2D bounds) where T : BItem + { + List entities = new List(s.BItems.Count); + Type type = typeof(T); + for (int i = s.BItems.Count - 1; i >= 0; --i) + { + BItem BItem = s.BItems[i]; + if (BItem != null && !BItem.Deleted && BItem.Parent == null && bounds.Contains(BItem.Location) && type.IsAssignableFrom(BItem.GetType())) + entities.Add(BItem as T); + } + return entities; + } + #endregion + + #region Mobiles + [Benchmark] + public void SelectMobilesNew() + { + SelectMobiles(sector, bounds); + } + + [Benchmark] + public void SelectMobilesLinq() + { + SelectMobilesLinq(sector, bounds); + } + + public IEnumerable SelectMobilesLinq(Sector s, Server.Rectangle2D bounds) where T : Mobile + { + return s.Mobiles.OfType().Where(o => o != null && !o.Deleted && bounds.Contains(o.Location)); + } + + public IEnumerable SelectMobiles(Sector s, Server.Rectangle2D bounds) where T : Mobile + { + List entities = new List(s.Mobiles.Count); + Type type = typeof(T); + for (int i = s.Mobiles.Count - 1; i >= 0; --i) + { + Mobile mob = s.Mobiles[i]; + if (mob != null && !mob.Deleted && bounds.Contains(mob.Location) && type.IsAssignableFrom(mob.GetType())) + entities.Add(mob as T); + } + return entities; + } + #endregion + + #region Entities + [Benchmark] + public void SelectEntitiesNew() + { + SelectEntities(sector, bounds); + } + + [Benchmark] + public void SelectEntitiesLinq() + { + SelectEntitiesLinq(sector, bounds); + } + + public IEnumerable SelectEntitiesLinq(Sector s, Server.Rectangle2D bounds) + { + return Enumerable.Empty() + .Union(s.Mobiles.Where(o => o != null && !o.Deleted)) + .Union(s.BItems.Where(o => o != null && !o.Deleted && o.Parent == null)) + .Where(o => bounds.Contains(o.Location)); + } + + private readonly List entities = new (10); + public IEnumerable SelectEntities(Sector s, Server.Rectangle2D bounds) + { + entities.Clear(); + entities.Capacity = s.Mobiles.Count + s.BItems.Count; + for (int i = s.Mobiles.Count - 1, j = s.BItems.Count - 1; i >= 0 || j >= 0; --i, --j) + { + if (j >= 0) + { + BItem BItem = s.BItems[j]; + if (BItem != null && !BItem.Deleted && BItem.Parent == null && bounds.Contains(BItem.Location)) + entities.Add(BItem); + } + if (i >= 0) + { + Mobile mob = s.Mobiles[i]; + if (mob != null && !mob.Deleted && bounds.Contains(mob.Location)) + entities.Add(mob); + } + } + return entities; + } + #endregion + } + public class BItem : Server.IPoint3D, IEntity + { + public object Parent { get; set; } = null; + + public bool Deleted { get; set; } = false; + + public int Z { get; set; } = 1; + + public int X { get; set; } = 1; + + public int Y { get; set; } = 1; + + public Serial Serial => throw new System.NotImplementedException(); + + public Point3D Location { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Map Map { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + + public Region Region => throw new System.NotImplementedException(); + + public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public int Hue { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Direction Direction { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public int TypeRef => throw new NotImplementedException(); + + Point3D IEntity.Location => throw new NotImplementedException(); + + Map IEntity.Map => throw new NotImplementedException(); + + int IPoint3D.Z => throw new NotImplementedException(); + + int IPoint2D.X => throw new NotImplementedException(); + + int IPoint2D.Y => throw new NotImplementedException(); + + DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + int ISerializable.TypeRef => throw new NotImplementedException(); + + Serial ISerializable.Serial => throw new NotImplementedException(); + + bool ISerializable.Deleted => throw new NotImplementedException(); + + public BItem() + { + + } + + public void Delete() + { + throw new System.NotImplementedException(); + } + + public void ProcessDelta() + { + throw new System.NotImplementedException(); + } + + public void OnStatsQuery(Server.Mobile m) + { + throw new System.NotImplementedException(); + } + + public void InvalidateProperties() + { + throw new System.NotImplementedException(); + } + + public int CompareTo(object obj) + { + throw new System.NotImplementedException(); + } + + public int CompareTo(IEntity other) + { + throw new System.NotImplementedException(); + } + + public void MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + public bool InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + public bool InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + public void RemoveBItem(BItem BItem) + { + throw new NotImplementedException(); + } + + public void BeforeSerialize() + { + throw new NotImplementedException(); + } + + public void Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + public void Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + public void SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + void IEntity.MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + void IEntity.ProcessDelta() + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + void ISerializable.BeforeSerialize() + { + throw new NotImplementedException(); + } + + void ISerializable.Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + void ISerializable.Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + void ISerializable.Delete() + { + throw new NotImplementedException(); + } + + void ISerializable.SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + public void RemoveItem(Item item) + { + throw new NotImplementedException(); + } + } + + public class Mobile : Server.IPoint3D, IEntity + { + public bool Deleted { get; set; } = false; + + public int Z { get; set; } = 1; + + public int X { get; set; } = 1; + + public int Y { get; set; } = 1; + + public Serial Serial => throw new System.NotImplementedException(); + + public Point3D Location { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Map Map { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + + public Region Region => throw new System.NotImplementedException(); + + public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public int Hue { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Direction Direction { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public int TypeRef => throw new NotImplementedException(); + + Point3D IEntity.Location => throw new NotImplementedException(); + + Map IEntity.Map => throw new NotImplementedException(); + + int IPoint3D.Z => throw new NotImplementedException(); + + int IPoint2D.X => throw new NotImplementedException(); + + int IPoint2D.Y => throw new NotImplementedException(); + + DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + int ISerializable.TypeRef => throw new NotImplementedException(); + + Serial ISerializable.Serial => throw new NotImplementedException(); + + bool ISerializable.Deleted => throw new NotImplementedException(); + + public Mobile() + { + + } + + public void Delete() + { + throw new System.NotImplementedException(); + } + + public void ProcessDelta() + { + throw new System.NotImplementedException(); + } + + public void OnStatsQuery(Server.Mobile m) + { + throw new System.NotImplementedException(); + } + + public void InvalidateProperties() + { + throw new System.NotImplementedException(); + } + + public int CompareTo(object obj) + { + throw new System.NotImplementedException(); + } + + public int CompareTo(IEntity other) + { + throw new System.NotImplementedException(); + } + + public void MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + public bool InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + public bool InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + public void RemoveBItem(BItem BItem) + { + throw new NotImplementedException(); + } + + public void BeforeSerialize() + { + throw new NotImplementedException(); + } + + public void Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + public void Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + public void SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + void IEntity.MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + void IEntity.ProcessDelta() + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + void ISerializable.BeforeSerialize() + { + throw new NotImplementedException(); + } + + void ISerializable.Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + void ISerializable.Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + void ISerializable.Delete() + { + throw new NotImplementedException(); + } + + void ISerializable.SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + public void RemoveItem(Item item) + { + throw new NotImplementedException(); + } + } + + public class BaseMulti : BItem + { + public MultiComponentList Components = MultiComponentList.Empty; + + public BaseMulti() + { + for (int i = 0; i < 20; ++i) + for (int j = 0; j < 20; ++j) + for (int z = 0; z < 20; ++z) + Components.Add(123, i, j, z); + } + + } + + public class Sector + { + public List BItems { get; set; } = new List(); + public List Mobiles { get; set; } = new List(); + public List Multis { get; set; } = new List(); + } +} diff --git a/Projects/Benchmarks/Program.cs b/Projects/Benchmarks/Program.cs index 4b5671c0f..bfdadb1bc 100644 --- a/Projects/Benchmarks/Program.cs +++ b/Projects/Benchmarks/Program.cs @@ -15,6 +15,8 @@ namespace Benchmarks // var textEncoding = BenchmarkRunner.Run(); // var logging = BenchmarkRunner.Run(); // var gumpPacket = BenchmarkRunner.Run(); + // MapSelectors.Init(); + // var mapSelectors = BenchmarkRunner.Run(); // var rngTest = BenchmarkRunner.Run(); var doubleRngText = BenchmarkRunner.Run(); } diff --git a/Projects/Server/Maps/Map.cs b/Projects/Server/Maps/Map.cs index 5593ee918..f24ca663a 100644 --- a/Projects/Server/Maps/Map.cs +++ b/Projects/Server/Maps/Map.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -54,49 +55,97 @@ namespace Server public static IEnumerable SelectClients(Sector s, Rectangle2D bounds) { - return s.Clients.Where(o => o?.Mobile?.Deleted == false && bounds.Contains(o.Mobile.Location)); + var clients = new List(s.Clients.Count); + foreach (var client in s.Clients) + { + var m = client.Mobile; + + if (m?.Deleted == false && bounds.Contains(m.Location)) + { + clients.Add(client); + } + } + + return clients; } - public static IEnumerable SelectEntities(Sector s, Rectangle2D bounds) => - SelectEntities(s, true, true, bounds); - - public static IEnumerable SelectEntities(Sector s, bool items, bool mobiles, Rectangle2D bounds) + public static IEnumerable SelectEntities(Sector s, Rectangle2D bounds) { - var eable = Enumerable.Empty(); - if (mobiles) + var entities = new List(s.Mobiles.Count + s.Items.Count); + for (int i = s.Mobiles.Count - 1, j = s.Items.Count - 1; i >= 0 || j >= 0; --i, --j) { - eable = eable.Union(s.Mobiles.Where(o => o?.Deleted == false)); - } + if (j >= 0) + { + Item item = s.Items[j]; + if (item is { Deleted: false, Parent: null } && bounds.Contains(item.Location)) + { + entities.Add(item); + } + } - if (items) - { - eable = eable.Union(s.Items.Where(o => o?.Deleted == false && o.Parent == null)); + if (i >= 0) + { + Mobile mob = s.Mobiles[i]; + if (mob is { Deleted: false } && bounds.Contains(mob.Location)) + { + entities.Add(mob); + } + } } - - return eable.Where(o => bounds.Contains(o.Location)); + return entities; } public static IEnumerable SelectMobiles(Sector s, Rectangle2D bounds) where T : Mobile { - return s.Mobiles.OfType().Where(o => !o.Deleted && bounds.Contains(o.Location)); + var entities = new List(s.Mobiles.Count); + for (int i = s.Mobiles.Count - 1; i >= 0; --i) + { + if (s.Mobiles[i] is T { Deleted: false } mob && bounds.Contains(mob.Location)) + { + entities.Add(mob); + } + } + return entities; } public static IEnumerable SelectItems(Sector s, Rectangle2D bounds) where T : Item { - return s.Items.OfType() - .Where(o => o.Deleted == false && o.Parent == null && bounds.Contains(o.Location)); + var entities = new List(s.Items.Count); + for (int i = s.Items.Count - 1; i >= 0; --i) + { + if (s.Items[i] is T { Deleted: false, Parent: null } item && bounds.Contains(item.Location)) + { + entities.Add(item); + } + } + return entities; } public static IEnumerable SelectMultis(Sector s, Rectangle2D bounds) { - return s.Multis.Where(o => o?.Deleted == false && bounds.Contains(o.Location)); + var entities = new List(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 SelectMultiTiles(Sector s, Rectangle2D bounds) { - foreach (var o in s.Multis.Where(o => o?.Deleted == false)) + for (int l = s.Multis.Count - 1; l >= 0; --l) { - var c = o.Components; + BaseMulti o = s.Multis[l]; + if (o?.Deleted != false) + { + continue; + } + + MultiComponentList c = o.Components; int x, y, xo, yo; StaticTile[] t, r; @@ -143,10 +192,8 @@ namespace Server public static Map.PooledEnumerable GetClients(Map map, Rectangle2D bounds) => Map.PooledEnumerable.Instantiate(map, bounds, ClientSelector ?? SelectClients); - public static Map.PooledEnumerable GetEntities( - Map map, Rectangle2D bounds, bool items = true, - bool mobiles = true - ) => Map.PooledEnumerable.Instantiate(map, bounds, EntitySelector ?? SelectEntities); + public static Map.PooledEnumerable GetEntities(Map map, Rectangle2D bounds) => + Map.PooledEnumerable.Instantiate(map, bounds, EntitySelector ?? SelectEntities); public static Map.PooledEnumerable GetMobiles(Map map, Rectangle2D bounds) => GetMobiles(map, bounds); @@ -272,9 +319,6 @@ namespace Server public const int SectorShift = 4; public const int SectorActiveRange = 2; - private static readonly Queue> m_FixPool = new(128); - private static readonly List m_EmptyFixItems = new(); - private static ILogger _logger; private static ILogger Logger => _logger ??= LogFactory.GetLogger(typeof(Map)); @@ -389,9 +433,55 @@ namespace Server public int CompareTo(Map other) => other == null ? -1 : MapID.CompareTo(other.MapID); - public static string[] GetMapNames() => Maps.Where(m => m != null).Select(m => m.Name).ToArray(); + public static string[] GetMapNames() + { + var mapCount = 0; + for (var i = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapCount++; + } + } - public static Map[] GetMapValues() => Maps.Where(m => m != null).ToArray(); + var mapNames = new string[mapCount]; + for (int i = 0, mIndex = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapNames[mIndex++] = map.Name; + } + } + + return mapNames; + } + + public static Map[] GetMapValues() + { + var mapCount = 0; + for (var i = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapCount++; + } + } + + var mapValues = new Map[mapCount]; + for (int i = 0, mIndex = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapValues[mIndex++] = map; + } + } + + return mapValues; + } public static Map Parse(string value) { @@ -498,54 +588,31 @@ namespace Server public IPooledEnumerable GetMultiTilesAt(int x, int y) => PooledEnumeration.GetMultiTiles(this, new Rectangle2D(x, y, 1, 1)); - private static List AcquireFixItems(Map map, int x, int y) + private static void AcquireFixItems(Map map, int x, int y, Item[] pool, out int length) { + length = 0; if (map == null || map == Internal || x < 0 || x > map.Width || y < 0 || y > map.Height) - { - return m_EmptyFixItems; - } - - List pool = null; - - lock (m_FixPool) - { - if (m_FixPool.Count > 0) - { - pool = m_FixPool.Dequeue(); - } - } - - pool ??= new List(128); // Arbitrary limit - - var eable = map.GetItemsInRange(new Point3D(x, y, 0), 0); - - pool.AddRange( - eable.Where(item => item.ItemID <= TileData.MaxItemValue && item is not BaseMulti) - .OrderBy(item => item.Z) - .Take(pool.Capacity) - ); - - eable.Free(); - - return pool; - } - - private static void FreeFixItems(List pool) - { - if (pool == m_EmptyFixItems) { return; } - pool.Clear(); - - lock (m_FixPool) + var eable = map.GetItemsInRange(new Point3D(x, y, 0), 0); + foreach (var item in eable) { - if (m_FixPool.Count < 128) + if (item is not BaseMulti && item.ItemID <= TileData.MaxItemValue) { - m_FixPool.Enqueue(pool); + if (length == 128) + { + break; + } + + pool[length++] = item; } } + + eable.Free(); + + Array.Sort(pool, ZComparer.Default); } public void FixColumn(int x, int y) @@ -555,9 +622,10 @@ namespace Server GetAverageZ(x, y, out _, out var landAvg, out _); - var items = AcquireFixItems(this, x, y); + var items = ArrayPool.Shared.Rent(128); + AcquireFixItems(this, x, y, items, out var length); - for (var i = 0; i < items.Count; i++) + for (var i = 0; i < length; i++) { var toFix = items[i]; @@ -592,7 +660,7 @@ namespace Server } } - for (var j = 0; j < items.Count; ++j) + for (var j = 0; j < length; ++j) { if (j == i) { @@ -622,7 +690,7 @@ namespace Server } } - FreeFixItems(items); + ArrayPool.Shared.Return(items); } /* This could probably be re-implemented if necessary (perhaps via an ITile interface?). @@ -1031,15 +1099,11 @@ namespace Server public IPooledEnumerable GetObjectsInRange(Point3D p) => GetObjectsInRange(p, Core.GlobalMaxUpdateRange); - public IPooledEnumerable GetObjectsInRange(Point3D p, int range, bool items = true, bool mobiles = true) => - GetObjectsInBounds( - new Rectangle2D(p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1), - items, - mobiles - ); + public IPooledEnumerable GetObjectsInRange(Point3D p, int range) => + GetObjectsInBounds(new Rectangle2D(p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1)); - public IPooledEnumerable GetObjectsInBounds(Rectangle2D bounds, bool items = true, bool mobiles = true) => - PooledEnumeration.GetEntities(this, bounds, items, mobiles); + public IPooledEnumerable GetObjectsInBounds(Rectangle2D bounds) => + PooledEnumeration.GetEntities(this, bounds); public IPooledEnumerable GetClientsInRange(Point3D p) => GetClientsInRange(p, Core.GlobalMaxUpdateRange); @@ -1188,6 +1252,13 @@ namespace Server public bool CanSpawnMobile(int x, int y, int z) => Region.Find(new Point3D(x, y, z), this).AllowSpawn() && CanFit(x, y, z, 16); + private class ZComparer : IComparer + { + public static readonly ZComparer Default = new(); + + public int Compare(Item x, Item y) => x!.Z.CompareTo(y!.Z); + } + public Sector GetSector(Point3D p) => InternalGetSector(p.m_X >> SectorShift, p.m_Y >> SectorShift); public Sector GetSector(Point2D p) => InternalGetSector(p.m_X >> SectorShift, p.m_Y >> SectorShift); @@ -1529,9 +1600,7 @@ namespace Server { public static readonly NullEnumerable Instance = new(); - private readonly IEnumerable m_Empty; - - private NullEnumerable() => m_Empty = Enumerable.Empty(); + private readonly IEnumerable m_Empty = Enumerable.Empty(); IEnumerator IEnumerable.GetEnumerator() => m_Empty.GetEnumerator(); diff --git a/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs b/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs index 12a3694a1..e203e988a 100644 --- a/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs +++ b/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs @@ -43,13 +43,18 @@ namespace Server.Commands.Generic return; } - var eable = map.GetObjectsInBounds(rect, items, mobiles); + var eable = map.GetObjectsInBounds(rect); var objs = new List(); foreach (var obj in eable) { - if ((!mobiles || obj is not Mobile || BaseCommand.IsAccessible(from, obj)) && ext.IsValid(obj)) + if (!mobiles && obj is Mobile || !items && obj is Item) + { + continue; + } + + if (BaseCommand.IsAccessible(from, obj) && ext.IsValid(obj)) { objs.Add(obj); } diff --git a/Projects/UOContent/Engines/Factions/Core/Faction.cs b/Projects/UOContent/Engines/Factions/Core/Faction.cs index 43d67c6ca..9345a7328 100644 --- a/Projects/UOContent/Engines/Factions/Core/Faction.cs +++ b/Projects/UOContent/Engines/Factions/Core/Faction.cs @@ -273,9 +273,14 @@ namespace Server.Factions return false; } - var eable = mob.Map.GetObjectsInRange(mob.Location, range, items, mobs); + var eable = mob.Map.GetObjectsInRange(mob.Location, range); foreach (var obj in eable) { + if (!mobs && obj is Mobile || !items && obj is Item) + { + continue; + } + if (type.IsInstanceOfType(obj)) { eable.Free(); diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs index 01de15b12..a08b6a557 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs @@ -215,7 +215,7 @@ namespace Server.Items alchemyBonus = (int)(from.Skills.Alchemy.Value / (Core.AOS ? 5 : 10)); } - var eable = map.GetObjectsInRange(loc, ExplosionRange, LeveledExplosion); + var eable = map.GetObjectsInRange(loc, ExplosionRange); using var queue = PooledRefQueue.Create(); var toDamage = 0; @@ -234,7 +234,7 @@ namespace Server.Items queue.Enqueue(entity); } } - else if (entity is BaseExplosionPotion) + else if (LeveledExplosion && entity is BaseExplosionPotion) { queue.Enqueue(entity); }