using System; using System.Collections.Generic; using Server.Items; using Server.Network; namespace Server { public class RegionRect : IComparable { 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 m_DefaultMobileList = new(); private static readonly List m_DefaultItemList = new(); private static readonly List m_DefaultClientList = new(); private static readonly List m_DefaultMultiList = new(); private static readonly List m_DefaultRectList = new(); private bool m_Active; private List m_Clients; private List m_Items; private List m_Mobiles; private List m_Multis; private List m_Players; private List m_RegionRects; public Sector(int x, int y, Map owner) { X = x; Y = y; Owner = owner; m_Active = false; } public List RegionRects => m_RegionRects ?? m_DefaultRectList; public List Multis => m_Multis ?? m_DefaultMultiList; public List Mobiles => m_Mobiles ?? m_DefaultMobileList; public List Items => m_Items ?? m_DefaultItemList; public List Clients => m_Clients ?? m_DefaultClientList; public List Players => m_Players ?? m_DefaultMobileList; public bool Active => m_Active && Owner != Map.Internal; public Map Owner { get; } public int X { get; } public int Y { get; } private static void Add(ref List list, T value) { list ??= new List(); list.Add(value); } private void Remove(ref List list, T value) { if (list != null) { list.Remove(value); if (list.Count == 0) { list = null; } } } private void Replace(ref List list, T oldValue, T newValue) { if (oldValue != null && newValue != null) { var index = list?.IndexOf(oldValue) ?? -1; if (index >= 0) { list![index] = newValue; } else { Add(ref list, newValue); } } else if (oldValue != null) { Remove(ref list, oldValue); } else if (newValue != null) { Add(ref list, newValue); } } public void OnClientChange(NetState oldState, NetState newState) { Replace(ref m_Clients, oldState, newState); } public void OnEnter(Item item) { Add(ref m_Items, item); } public void OnLeave(Item item) { Remove(ref m_Items, item); } public void OnEnter(Mobile mob) { Add(ref m_Mobiles, mob); if (mob.NetState != null) { Add(ref m_Clients, mob.NetState); } if (mob.Player) { if (m_Players == null) { Owner.ActivateSectors(X, Y); } Add(ref m_Players, mob); } } public void OnLeave(Mobile mob) { Remove(ref m_Mobiles, mob); if (mob.NetState != null) { Remove(ref m_Clients, mob.NetState); } if (mob.Player && m_Players != null) { Remove(ref m_Players, mob); if (m_Players == null) { Owner.DeactivateSectors(X, Y); } } } public void OnEnter(Region region, Rectangle3D rect) { 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); } } if (m_RegionRects.Count == 0) { m_RegionRects = null; } } UpdateMobileRegions(); } private void UpdateMobileRegions() { if (m_Mobiles != null) { var sandbox = new List(m_Mobiles); foreach (var mob in sandbox) { mob.UpdateRegion(); } } } public void OnMultiEnter(BaseMulti multi) { Add(ref m_Multis, multi); } public void OnMultiLeave(BaseMulti multi) { Remove(ref m_Multis, multi); } public void Activate() { if (!Active && Owner != Map.Internal) { 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; } } } }