fix: Prepares for IPooledEnumerable removal (#1548)

### Summary

- Removes `IPooledEnumerable` (non-generic)
- Changes `IPooledEnumerable<T>` so that  `Free()` is replaced with the `IDisposable` pattern
This commit is contained in:
Kamron Batman 2023-10-15 11:20:49 -07:00 committed by GitHub
parent c2d6578955
commit d57f1fecc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
92 changed files with 644 additions and 907 deletions

View file

@ -82,8 +82,6 @@ public static class Effects
OutgoingEffectPackets.CreateSoundEffect(buffer, soundID, p);
state.Send(buffer);
}
eable.Free();
}
}
@ -127,8 +125,6 @@ public static class Effects
}
}
}
eable.Free();
}
public static void SendLocationEffect(
@ -196,8 +192,6 @@ public static class Effects
state.Send(regular);
}
}
eable.Free();
}
public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue = 0, int renderMode = 0)
@ -258,8 +252,6 @@ public static class Effects
state.Send(regular);
}
}
eable.Free();
}
public static void SendMovingEffect(
@ -478,8 +470,6 @@ public static class Effects
state.Send(regular);
}
}
eable.Free();
}
public static void SendPacket(Point3D origin, Map map, Span<byte> effectBuffer)
@ -496,7 +486,5 @@ public static class Effects
state.Mobile.ProcessDelta();
state.Send(effectBuffer);
}
eable.Free();
}
}

View file

@ -346,8 +346,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
state.Send(removeEntity);
}
}
eable.Free();
}
Delta(ItemDelta.Update);
@ -1148,8 +1146,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
}
}
}
eable.Free();
}
RemDelta(ItemDelta.Update);
@ -1179,8 +1175,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
state.Send(removeEntity);
}
}
eable.Free();
}
var oldInternalLocation = m_Location;
@ -1200,8 +1194,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
}
}
eable.Free();
m_Map.OnMove(oldInternalLocation, this);
RemDelta(ItemDelta.Update);
@ -1403,8 +1395,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
SendOPLPacketTo(state);
}
}
eable.Free();
}
public virtual void Delete()
@ -1516,8 +1506,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
state.Send(removeEntity);
}
}
eable.Free();
}
var oldLoc = m_Location;
@ -1539,8 +1527,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
}
}
eable.Free();
RemDelta(ItemDelta.Update);
}
else
@ -3302,8 +3288,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
state.Send(buffer);
}
}
eable.Free();
}
public void PublicOverheadMessage(MessageType type, int hue, int number, string args = "")
@ -3336,8 +3320,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
state.Send(buffer);
}
}
eable.Free();
}
public virtual void OnAfterDelete()
@ -3589,8 +3571,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
items.Add(item);
}
eable.Free();
if (z == int.MinValue)
{
return false;
@ -3792,8 +3772,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
state.Send(removeEntity);
}
}
eable.Free();
}
public virtual int GetDropSound() => -1;

View file

@ -1,10 +1,24 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2023 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: Map.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.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using Server.Buffers;
using Server.Collections;
using Server.Items;
using Server.Logging;
using Server.Network;
@ -24,295 +38,6 @@ public enum MapRules
FeluccaRules = None
}
public interface IPooledEnumerable : IEnumerable
{
void Free();
}
public interface IPooledEnumerable<T> : IPooledEnumerable, IEnumerable<T>
{
}
public static class PooledEnumeration
{
public delegate IEnumerable<T> Selector<out T>(Sector sector, Rectangle2D bounds);
static PooledEnumeration()
{
ClientSelector = SelectClients;
EntitySelector = SelectEntities;
MobileSelector = SelectMobiles<Mobile>;
ItemSelector = SelectItems<Item>;
MultiSelector = SelectMultis;
MultiTileSelector = SelectMultiTiles;
}
public static Selector<NetState> ClientSelector { get; set; }
public static Selector<IEntity> EntitySelector { get; set; }
public static Selector<Mobile> MobileSelector { get; set; }
public static Selector<Item> ItemSelector { get; set; }
public static Selector<BaseMulti> MultiSelector { get; set; }
public static Selector<StaticTile[]> MultiTileSelector { get; set; }
public static IEnumerable<NetState> SelectClients(Sector s, Rectangle2D bounds)
{
var clients = new List<NetState>(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<IEntity> SelectEntities(Sector s, Rectangle2D bounds)
{
var entities = new List<IEntity>(s.Mobiles.Count + s.Items.Count);
for (int i = s.Mobiles.Count - 1, j = s.Items.Count - 1; i >= 0 || j >= 0; --i, --j)
{
if (j >= 0)
{
Item item = s.Items[j];
if (item is { Deleted: false, Parent: null } && bounds.Contains(item.Location))
{
entities.Add(item);
}
}
if (i >= 0)
{
Mobile mob = s.Mobiles[i];
if (mob is { Deleted: false } && bounds.Contains(mob.Location))
{
entities.Add(mob);
}
}
}
return entities;
}
public static IEnumerable<T> SelectMobiles<T>(Sector s, Rectangle2D bounds) where T : Mobile
{
var entities = new List<T>(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<T> SelectItems<T>(Sector s, Rectangle2D bounds) where T : Item
{
var entities = new List<T>(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<BaseMulti> SelectMultis(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(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 Map.PooledEnumerable<NetState> GetClients(Map map, Rectangle2D bounds) =>
Map.PooledEnumerable<NetState>.Instantiate(map, bounds, ClientSelector ?? SelectClients);
public static Map.PooledEnumerable<IEntity> GetEntities(Map map, Rectangle2D bounds) =>
Map.PooledEnumerable<IEntity>.Instantiate(map, bounds, EntitySelector ?? SelectEntities);
public static Map.PooledEnumerable<Mobile> GetMobiles(Map map, Rectangle2D bounds) =>
GetMobiles<Mobile>(map, bounds);
public static Map.PooledEnumerable<T> GetMobiles<T>(Map map, Rectangle2D bounds) where T : Mobile =>
Map.PooledEnumerable<T>.Instantiate(map, bounds, SelectMobiles<T>);
public static Map.PooledEnumerable<T> GetItems<T>(Map map, Rectangle2D bounds) where T : Item =>
Map.PooledEnumerable<T>.Instantiate(map, bounds, SelectItems<T>);
public static Map.PooledEnumerable<BaseMulti> GetMultis(Map map, Rectangle2D bounds) =>
Map.PooledEnumerable<BaseMulti>.Instantiate(map, bounds, MultiSelector ?? SelectMultis);
public static Map.PooledEnumerable<StaticTile[]> GetMultiTiles(Map map, Rectangle2D bounds) =>
Map.PooledEnumerable<StaticTile[]>.Instantiate(map, bounds, MultiTileSelector ?? SelectMultiTiles);
public static IEnumerable<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 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 sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
{
public const int SectorSize = 16;
@ -501,7 +226,6 @@ public sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
return false;
}
public override string ToString() => Name;
public string ToString(string format, IFormatProvider formatProvider)
@ -598,8 +322,6 @@ public sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
}
}
eable.Free();
Array.Sort(pool, 0, length, ZComparer.Default);
}
@ -1429,8 +1151,6 @@ public sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
}
}
eable.Free();
if (contains)
{
return false;
@ -1510,11 +1230,9 @@ public sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
continue;
}
area.Free();
return false;
}
area.Free();
return true;
}
@ -1598,88 +1316,6 @@ public sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
return loc;
}
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 Free()
{
}
}
public sealed class PooledEnumerable<T> : IPooledEnumerable<T>, IDisposable
{
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()
{
m_IsDisposed = true;
m_Pool.Clear();
m_Pool.TrimExcess();
m_Pool = null;
}
IEnumerator IEnumerable.GetEnumerator() => m_Pool.GetEnumerator();
public IEnumerator<T> GetEnumerator() => m_Pool.GetEnumerator();
public void Free()
{
if (m_IsDisposed)
{
return;
}
m_Pool.Clear();
m_Pool.Capacity = Math.Max(m_Pool.Capacity, 0x100);
lock (((ICollection)_Buffer).SyncRoot)
{
_Buffer.Enqueue(this);
}
}
#pragma warning disable CA1000 // Do not declare static members on generic types
public static PooledEnumerable<T> Instantiate(
Map map, Rectangle2D bounds, PooledEnumeration.Selector<T> selector
)
{
PooledEnumerable<T> e = null;
lock (((ICollection)_Buffer).SyncRoot)
{
if (_Buffer.Count > 0)
{
e = _Buffer.Dequeue();
}
}
var pool = PooledEnumeration.EnumerateSectors(map, bounds).SelectMany(s => selector(s, bounds));
if (e == null)
{
return new PooledEnumerable<T>(pool);
}
e.m_Pool.AddRange(pool);
return e;
}
}
#pragma warning restore CA1000 // Do not declare static members on generic types
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Map Parse(string s) => Parse(s, null);
@ -1775,4 +1411,212 @@ public sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
result = default;
return false;
}
public class RegionRect : IComparable<RegionRect>
{
private Rectangle3D m_Rect;
public RegionRect(Region region, Rectangle3D rect)
{
Region = region;
m_Rect = rect;
}
public Region Region { get; }
public Rectangle3D Rect => m_Rect;
public int CompareTo(RegionRect regRect) => regRect == null ? 1 : Region.CompareTo(regRect.Region);
public bool Contains(Point3D loc) => m_Rect.Contains(loc);
}
public class Sector
{
// TODO: Can we avoid this?
private static readonly List<Mobile> m_DefaultMobileList = new();
private static readonly List<Item> m_DefaultItemList = new();
private static readonly List<NetState> m_DefaultClientList = new();
private static readonly List<BaseMulti> m_DefaultMultiList = new();
private static readonly List<RegionRect> m_DefaultRectList = new();
private bool m_Active;
private List<NetState> m_Clients;
private List<Item> m_Items;
private List<Mobile> m_Mobiles;
private List<BaseMulti> m_Multis;
private List<RegionRect> m_RegionRects;
public Sector(int x, int y, Map owner)
{
X = x;
Y = y;
Owner = owner;
m_Active = false;
}
public List<RegionRect> RegionRects => m_RegionRects ?? m_DefaultRectList;
public List<BaseMulti> Multis => m_Multis ?? m_DefaultMultiList;
public List<Mobile> Mobiles => m_Mobiles ?? m_DefaultMobileList;
public List<Item> Items => m_Items ?? m_DefaultItemList;
public List<NetState> Clients => m_Clients ?? m_DefaultClientList;
public bool Active => m_Active && Owner != Map.Internal;
public Map Owner { get; }
public int X { get; }
public int Y { get; }
public void OnClientChange(NetState oldState, NetState newState)
{
Utility.Replace(ref m_Clients, oldState, newState);
}
public void OnEnter(Item item)
{
Utility.Add(ref m_Items, item);
}
public void OnLeave(Item item)
{
Utility.Remove(ref m_Items, item);
}
public void OnEnter(Mobile mob)
{
Utility.Add(ref m_Mobiles, mob);
if (mob.NetState != null)
{
Utility.Add(ref m_Clients, mob.NetState);
Owner.ActivateSectors(X, Y);
}
}
public void OnLeave(Mobile mob)
{
Utility.Remove(ref m_Mobiles, mob);
if (mob.NetState != null)
{
Utility.Remove(ref m_Clients, mob.NetState);
Owner.DeactivateSectors(X, Y);
}
}
public void OnEnter(Region region, Rectangle3D rect)
{
Utility.Add(ref m_RegionRects, new RegionRect(region, rect));
m_RegionRects.Sort();
UpdateMobileRegions();
}
public void OnLeave(Region region)
{
if (m_RegionRects != null)
{
for (var i = m_RegionRects.Count - 1; i >= 0; i--)
{
var regRect = m_RegionRects[i];
if (regRect.Region == region)
{
m_RegionRects.RemoveAt(i);
break;
}
}
if (m_RegionRects.Count == 0)
{
m_RegionRects = null;
}
}
UpdateMobileRegions();
}
private void UpdateMobileRegions()
{
if (m_Mobiles != null)
{
using var queue = PooledRefQueue<Mobile>.Create(m_Mobiles.Count);
foreach (var mob in m_Mobiles)
{
queue.Enqueue(mob);
}
while (queue.Count > 0)
{
queue.Dequeue().UpdateRegion();
}
}
}
public void OnMultiEnter(BaseMulti multi)
{
Utility.Add(ref m_Multis, multi);
}
public void OnMultiLeave(BaseMulti multi)
{
Utility.Remove(ref m_Multis, multi);
}
public void Activate()
{
if (!Active)
{
if (m_Items != null)
{
foreach (var item in m_Items)
{
item.OnSectorActivate();
}
}
if (m_Mobiles != null)
{
foreach (var mob in m_Mobiles)
{
mob.OnSectorActivate();
}
}
m_Active = true;
}
}
public void Deactivate()
{
if (Active)
{
if (m_Items != null)
{
foreach (var item in m_Items)
{
item.OnSectorDeactivate();
}
}
if (m_Mobiles != null)
{
foreach (var mob in m_Mobiles)
{
mob.OnSectorDeactivate();
}
}
m_Active = false;
}
}
}
}

View file

@ -0,0 +1,390 @@
/*************************************************************************
* 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;
using Server.Network;
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()
{
ClientSelector = SelectClients;
EntitySelector = SelectEntities;
MobileSelector = SelectMobiles<Mobile>;
ItemSelector = SelectItems<Item>;
MultiSelector = SelectMultis;
MultiTileSelector = SelectMultiTiles;
}
public static Selector<NetState> ClientSelector { get; set; }
public static Selector<IEntity> EntitySelector { get; set; }
public static Selector<Mobile> MobileSelector { get; set; }
public static Selector<Item> ItemSelector { get; set; }
public static Selector<BaseMulti> MultiSelector { get; set; }
public static Selector<StaticTile[]> MultiTileSelector { get; set; }
public static IEnumerable<NetState> SelectClients(Map.Sector s, Rectangle2D bounds)
{
var clients = new List<NetState>(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<IEntity> SelectEntities(Map.Sector s, Rectangle2D bounds)
{
var entities = new List<IEntity>(s.Mobiles.Count + s.Items.Count);
for (int i = s.Mobiles.Count - 1, j = s.Items.Count - 1; i >= 0 || j >= 0; --i, --j)
{
if (j >= 0)
{
Item item = s.Items[j];
if (item is { Deleted: false, Parent: null } && bounds.Contains(item.Location))
{
entities.Add(item);
}
}
if (i >= 0)
{
Mobile mob = s.Mobiles[i];
if (mob is { Deleted: false } && bounds.Contains(mob.Location))
{
entities.Add(mob);
}
}
}
return entities;
}
public static IEnumerable<T> SelectMobiles<T>(Map.Sector s, Rectangle2D bounds) where T : Mobile
{
var entities = new List<T>(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<T> SelectItems<T>(Map.Sector s, Rectangle2D bounds) where T : Item
{
var entities = new List<T>(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<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<NetState> GetClients(Map map, Rectangle2D bounds) =>
PooledEnumerable<NetState>.Instantiate(map, bounds, ClientSelector ?? SelectClients);
public static PooledEnumerable<IEntity> GetEntities(Map map, Rectangle2D bounds) =>
PooledEnumerable<IEntity>.Instantiate(map, bounds, EntitySelector ?? SelectEntities);
public static PooledEnumerable<Mobile> GetMobiles(Map map, Rectangle2D bounds) =>
GetMobiles<Mobile>(map, bounds);
public static PooledEnumerable<T> GetMobiles<T>(Map map, Rectangle2D bounds) where T : Mobile =>
PooledEnumerable<T>.Instantiate(map, bounds, SelectMobiles<T>);
public static PooledEnumerable<T> GetItems<T>(Map map, Rectangle2D bounds) where T : Item =>
PooledEnumerable<T>.Instantiate(map, bounds, SelectItems<T>);
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, PooledEnumeration.Selector<T> selector
)
{
PooledEnumerable<T> e = null;
lock (((ICollection)_Buffer).SyncRoot)
{
if (_Buffer.Count > 0)
{
e = _Buffer.Dequeue();
}
}
var pool = PooledEnumeration.EnumerateSectors(map, bounds).SelectMany(s => selector(s, bounds));
if (e == null)
{
return new PooledEnumerable<T>(pool);
}
e.m_Pool.AddRange(pool);
return e;
}
}
}

View file

@ -2985,8 +2985,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
SendOPLPacketTo(state);
}
eable.Free();
}
public ISpawner Spawner { get; set; }
@ -4313,8 +4311,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
}
eable.Free();
const int cacheLength = OutgoingMobilePackets.MobileMovingPacketCacheByteLength;
const int width = OutgoingMobilePackets.MobileMovingPacketLength;
@ -4790,8 +4786,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
}
}
eable.Free();
}
Region.OnDeath(this);
@ -5092,8 +5086,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
ns.Send(buffer);
}
}
eable.Free();
}
var fixLoc = item.Location;
@ -5253,8 +5245,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
ns.Send(buffer);
}
eable.Free();
}
public virtual bool Drop(Item to, Point3D loc)
@ -5585,8 +5575,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
}
eable.Free();
object mutateContext = null;
var mutatedText = text;
SpeechEventArgs mutatedArgs = null;
@ -5983,8 +5971,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
ns.SendDamage(Serial, amount);
}
}
eable.Free();
}
public void SendVisibleDamageSelective(Mobile from, int amount)
@ -6745,8 +6731,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(buffer);
}
eable.Free();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -6783,8 +6767,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(buffer);
}
}
eable.Free();
}
public virtual void SendOPLPacketTo(NetState ns)
@ -6837,8 +6819,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(removeEntity);
}
}
eable.Free();
}
public void ClearScreen()
@ -6867,8 +6847,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
}
}
eable.Free();
}
/// <summary>
@ -6949,8 +6927,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
}
}
eable.Free();
}
public void UpdateRegion()
@ -7086,8 +7062,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
SendOPLPacketTo(state);
}
}
eable.Free();
}
public virtual void OnConnected()
@ -7307,18 +7281,13 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
}
eable.Free();
var ourState = m_NetState;
// Check to see if we are attached to a client
if (ourState != null)
{
var eeable = map.GetObjectsInRange(newLocation, Core.GlobalMaxUpdateRange);
// 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 eeable)
foreach (var o in map.GetObjectsInRange(newLocation, Core.GlobalMaxUpdateRange))
{
if (o is Item item)
{
@ -7381,8 +7350,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
m.SendOPLPacketTo(ourState);
}
}
eeable.Free();
}
else
{
@ -7411,8 +7378,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
SendOPLPacketTo(ns);
}
}
eable.Free();
}
}
@ -7494,8 +7459,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
SendOPLPacketTo(state);
}
}
eable.Free();
}
public bool PlaceInBackpack(Item item) =>
@ -8009,7 +7972,7 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
/// <summary>
/// Overridable. Virtual event invoked when the sector this Mobile is in gets <see cref="Sector.Activate">activated</see>.
/// Overridable. Virtual event invoked when the sector this Mobile is in gets <see cref="Map.Sector.Activate">activated</see>.
/// </summary>
public virtual void OnSectorActivate()
{
@ -8017,7 +7980,7 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
/// <summary>
/// Overridable. Virtual event invoked when the sector this Mobile is in gets
/// <see cref="Sector.Deactivate">deactivated</see>.
/// <see cref="Map.Sector.Deactivate">deactivated</see>.
/// </summary>
public virtual void OnSectorDeactivate()
{
@ -8956,8 +8919,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(buffer);
}
}
eable.Free();
}
public void PublicOverheadMessage(MessageType type, int hue, int number, string args = "", bool noLineOfSight = true)
@ -8987,8 +8948,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(buffer);
}
}
eable.Free();
}
public void PublicOverheadMessage(
@ -9027,8 +8986,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(buffer);
}
}
eable.Free();
}
public void PrivateOverheadMessage(MessageType type, int hue, bool ascii, string text, NetState state)
@ -9075,8 +9032,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(buffer);
}
}
eable.Free();
}
public void NonlocalOverheadMessage(MessageType type, int hue, bool ascii, string text)
@ -9106,8 +9061,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
state.Send(buffer);
}
}
eable.Free();
}
public void SendLocalizedMessage(int number, string args = "", int hue = 0x3B2) =>

View file

@ -210,7 +210,7 @@ public class Region : IComparable<Region>, IValueLinkListNode<Region>
public Rectangle3D[] Area { get; }
public Sector[] Sectors { get; private set; }
public Map.Sector[] Sectors { get; private set; }
public bool Dynamic { get; }
@ -346,7 +346,7 @@ public class Region : IComparable<Region>, IValueLinkListNode<Region>
Map.RegisterRegion(this);
var sectors = new List<Sector>();
var sectors = new List<Map.Sector>();
for (var i = 0; i < Area.Length; i++)
{

View file

@ -1,215 +0,0 @@
using System;
using System.Collections.Generic;
using Server.Collections;
using Server.Items;
using Server.Network;
namespace Server;
public class RegionRect : IComparable<RegionRect>
{
private Rectangle3D m_Rect;
public RegionRect(Region region, Rectangle3D rect)
{
Region = region;
m_Rect = rect;
}
public Region Region { get; }
public Rectangle3D Rect => m_Rect;
public int CompareTo(RegionRect regRect) => regRect == null ? 1 : Region.CompareTo(regRect.Region);
public bool Contains(Point3D loc) => m_Rect.Contains(loc);
}
public class Sector
{
// TODO: Can we avoid this?
private static readonly List<Mobile> m_DefaultMobileList = new();
private static readonly List<Item> m_DefaultItemList = new();
private static readonly List<NetState> m_DefaultClientList = new();
private static readonly List<BaseMulti> m_DefaultMultiList = new();
private static readonly List<RegionRect> m_DefaultRectList = new();
private bool m_Active;
private List<NetState> m_Clients;
private List<Item> m_Items;
private List<Mobile> m_Mobiles;
private List<BaseMulti> m_Multis;
private List<RegionRect> m_RegionRects;
public Sector(int x, int y, Map owner)
{
X = x;
Y = y;
Owner = owner;
m_Active = false;
}
public List<RegionRect> RegionRects => m_RegionRects ?? m_DefaultRectList;
public List<BaseMulti> Multis => m_Multis ?? m_DefaultMultiList;
public List<Mobile> Mobiles => m_Mobiles ?? m_DefaultMobileList;
public List<Item> Items => m_Items ?? m_DefaultItemList;
public List<NetState> Clients => m_Clients ?? m_DefaultClientList;
public bool Active => m_Active && Owner != Map.Internal;
public Map Owner { get; }
public int X { get; }
public int Y { get; }
public void OnClientChange(NetState oldState, NetState newState)
{
Utility.Replace(ref m_Clients, oldState, newState);
}
public void OnEnter(Item item)
{
Utility.Add(ref m_Items, item);
}
public void OnLeave(Item item)
{
Utility.Remove(ref m_Items, item);
}
public void OnEnter(Mobile mob)
{
Utility.Add(ref m_Mobiles, mob);
if (mob.NetState != null)
{
Utility.Add(ref m_Clients, mob.NetState);
Owner.ActivateSectors(X, Y);
}
}
public void OnLeave(Mobile mob)
{
Utility.Remove(ref m_Mobiles, mob);
if (mob.NetState != null)
{
Utility.Remove(ref m_Clients, mob.NetState);
Owner.DeactivateSectors(X, Y);
}
}
public void OnEnter(Region region, Rectangle3D rect)
{
Utility.Add(ref m_RegionRects, new RegionRect(region, rect));
m_RegionRects.Sort();
UpdateMobileRegions();
}
public void OnLeave(Region region)
{
if (m_RegionRects != null)
{
for (var i = m_RegionRects.Count - 1; i >= 0; i--)
{
var regRect = m_RegionRects[i];
if (regRect.Region == region)
{
m_RegionRects.RemoveAt(i);
break;
}
}
if (m_RegionRects.Count == 0)
{
m_RegionRects = null;
}
}
UpdateMobileRegions();
}
private void UpdateMobileRegions()
{
if (m_Mobiles != null)
{
using var queue = PooledRefQueue<Mobile>.Create(m_Mobiles.Count);
foreach (var mob in m_Mobiles)
{
queue.Enqueue(mob);
}
while (queue.Count > 0)
{
queue.Dequeue().UpdateRegion();
}
}
}
public void OnMultiEnter(BaseMulti multi)
{
Utility.Add(ref m_Multis, multi);
}
public void OnMultiLeave(BaseMulti multi)
{
Utility.Remove(ref m_Multis, multi);
}
public void Activate()
{
if (!Active)
{
if (m_Items != null)
{
foreach (var item in m_Items)
{
item.OnSectorActivate();
}
}
if (m_Mobiles != null)
{
foreach (var mob in m_Mobiles)
{
mob.OnSectorActivate();
}
}
m_Active = true;
}
}
public void Deactivate()
{
if (Active)
{
if (m_Items != null)
{
foreach (var item in m_Items)
{
item.OnSectorDeactivate();
}
}
if (m_Mobiles != null)
{
foreach (var mob in m_Mobiles)
{
mob.OnSectorDeactivate();
}
}
m_Active = false;
}
}
}

View file

@ -261,8 +261,6 @@ public class TileMatrix
m_TilesList.AddRange(multiTiles);
}
eable.Free();
if (!any)
{
return tiles[x & 0x7][y & 0x7];

View file

@ -997,6 +997,17 @@ public static class Utility
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Shuffle<T>(this PooledRefList<T> list)
{
var count = list.Count;
for (var i = 0; i < count; i++)
{
var r = RandomMinMax(i, count - 1);
(list[r], list[i]) = (list[i], list[r]);
}
}
/**
* Gets a random sample from the source list.
* Not meant for unbounded lists. Does not shuffle or modify source.