diff --git a/Projects/UOContent/Gumps/WhoGump.cs b/Projects/UOContent/Gumps/WhoGump.cs index 3852414eb..01c6d9859 100644 --- a/Projects/UOContent/Gumps/WhoGump.cs +++ b/Projects/UOContent/Gumps/WhoGump.cs @@ -1,301 +1,291 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Server.Mobiles; using Server.Network; using static Server.Gumps.PropsConfig; -namespace Server.Gumps +namespace Server.Gumps; +public class WhoGump : DynamicGump { - public class WhoGump : Gump + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + private static readonly int EntryWidth = 180; + private static readonly int EntryCount = 15; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + + private readonly List _mobiles; + private readonly int _page; + + public WhoGump(Mobile owner, string filter) : this(BuildList(owner, filter)) { - private static readonly int PrevLabelOffsetX = PrevWidth + 1; - private static readonly int PrevLabelOffsetY = 0; + } - private static readonly int NextLabelOffsetX = -29; - private static readonly int NextLabelOffsetY = 0; + public WhoGump(List list, int page = 0) : base(GumpOffsetX, GumpOffsetY) + { + _mobiles = list; + _page = page; - private static readonly int EntryWidth = 180; - private static readonly int EntryCount = 15; + // Initialize(page); + } - private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + public static void Configure() + { + CommandSystem.Register("WhoList", AccessLevel.Counselor, WhoList_OnCommand); + } - private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + [Usage("WhoList [filter]")] + [Aliases("Who")] + [Description("Lists all connected clients. Optionally filters results by name.")] + private static void WhoList_OnCommand(CommandEventArgs e) + { + e.Mobile.SendGump(new WhoGump(e.Mobile, e.ArgString)); + } - private readonly List m_Mobiles; + public static List BuildList(Mobile owner, string rawFilter) + { + var filter = rawFilter.AsSpan().Trim(); - private Mobile m_Owner; - private int m_Page; + var list = new List(); - public WhoGump(Mobile owner, string filter) : this(owner, BuildList(owner, filter)) + foreach (var ns in NetState.Instances) { - } + var m = ns.Mobile; - public WhoGump(Mobile owner, List list, int page = 0) : base(GumpOffsetX, GumpOffsetY) - { - owner.CloseGump(); - - m_Owner = owner; - m_Mobiles = list; - - Initialize(page); - } - - public static void Configure() - { - CommandSystem.Register("WhoList", AccessLevel.Counselor, WhoList_OnCommand); - } - - [Usage("WhoList [filter]")] - [Aliases("Who")] - [Description("Lists all connected clients. Optionally filters results by name.")] - private static void WhoList_OnCommand(CommandEventArgs e) - { - e.Mobile.SendGump(new WhoGump(e.Mobile, e.ArgString)); - } - - public static List BuildList(Mobile owner, string rawFilter) - { - var filter = rawFilter.Trim().ToLower().DefaultIfNullOrEmpty(null); - - var list = new List(); - - foreach (var ns in NetState.Instances) + if (m == null || m != owner && m.Hidden && owner.AccessLevel < m.AccessLevel && + (m is not PlayerMobile mobile || !mobile.VisibilityList.Contains(owner))) { - var m = ns.Mobile; - - if (m != null && (m == owner || !m.Hidden || owner.AccessLevel >= m.AccessLevel || - m is PlayerMobile mobile && mobile.VisibilityList.Contains(owner))) - { - if (filter != null && !m.Name.InsensitiveContains(filter)) - { - continue; - } - - list.Add(m); - } + continue; } - list.Sort(InternalComparer.Instance); + if (filter.Length > 0 && !m.Name.AsSpan().InsensitiveContains(filter)) + { + continue; + } - return list; + list.Add(m); } - public void Initialize(int page) + list.Sort(InternalComparer.Instance); + + return list; + } + + protected override void BuildLayout(ref DynamicGumpBuilder builder) + { + var count = Math.Clamp(_mobiles.Count - _page * EntryCount, 0, EntryCount); + + var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); + + builder.AddPage(); + + builder.AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); + builder.AddImageTiled( + BorderSize, + BorderSize, + TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), + totalHeight, + OffsetGumpID + ); + + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize; + + var emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4 - (OldStyle ? SetWidth + OffsetSize : 0); + + if (!OldStyle) { - m_Page = page; - - var count = Math.Clamp(m_Mobiles.Count - page * EntryCount, 0, EntryCount); - - var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); - - AddPage(0); - - AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); - AddImageTiled( - BorderSize, - BorderSize, - TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), - totalHeight, - OffsetGumpID + builder.AddImageTiled( + x - (OldStyle ? OffsetSize : 0), + y, + emptyWidth + (OldStyle ? OffsetSize * 2 : 0), + EntryHeight, + EntryGumpID ); + } - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; + builder.AddLabel( + x + TextOffsetX, + y, + TextHue, + $"Page {_page + 1} of {(_mobiles.Count + EntryCount - 1) / EntryCount} ({_mobiles.Count})" + ); - var emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4 - (OldStyle ? SetWidth + OffsetSize : 0); + x += emptyWidth + OffsetSize; - if (!OldStyle) + if (OldStyle) + { + builder.AddImageTiled(x, y, TotalWidth - OffsetSize * 3 - SetWidth, EntryHeight, HeaderGumpID); + } + else + { + builder.AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); + } + + if (_page > 0) + { + builder.AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1); + + if (PrevLabel) { - AddImageTiled( - x - (OldStyle ? OffsetSize : 0), - y, - emptyWidth + (OldStyle ? OffsetSize * 2 : 0), - EntryHeight, - EntryGumpID - ); + builder.AddLabel(x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous"); } + } - AddLabel( + x += PrevWidth + OffsetSize; + + if (!OldStyle) + { + builder.AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); + } + + if ((_page + 1) * EntryCount < _mobiles.Count) + { + builder.AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1); + + if (NextLabel) + { + builder.AddLabel(x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next"); + } + } + + for (int i = 0, index = _page * EntryCount; i < EntryCount && index < _mobiles.Count; ++i, ++index) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + var m = _mobiles[index]; + + builder.AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + builder.AddLabelCropped( x + TextOffsetX, y, - TextHue, - $"Page {page + 1} of {(m_Mobiles.Count + EntryCount - 1) / EntryCount} ({m_Mobiles.Count})" + EntryWidth - TextOffsetX, + EntryHeight, + GetHueFor(m), + m.Deleted ? "(deleted)" : m.Name ); - x += emptyWidth + OffsetSize; + x += EntryWidth + OffsetSize; - if (OldStyle) + if (SetGumpID != 0) { - AddImageTiled(x, y, TotalWidth - OffsetSize * 3 - SetWidth, EntryHeight, HeaderGumpID); - } - else - { - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); + builder.AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); } - if (page > 0) + if (m.NetState != null && !m.Deleted) { - AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1); - - if (PrevLabel) - { - AddLabel(x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous"); - } - } - - x += PrevWidth + OffsetSize; - - if (!OldStyle) - { - AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); - } - - if ((page + 1) * EntryCount < m_Mobiles.Count) - { - AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1); - - if (NextLabel) - { - AddLabel(x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next"); - } - } - - for (int i = 0, index = page * EntryCount; i < EntryCount && index < m_Mobiles.Count; ++i, ++index) - { - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - var m = m_Mobiles[index]; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped( - x + TextOffsetX, - y, - EntryWidth - TextOffsetX, - EntryHeight, - GetHueFor(m), - m.Deleted ? "(deleted)" : m.Name - ); - - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - if (m.NetState != null && !m.Deleted) - { - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3); - } - } - } - - private static int GetHueFor(Mobile m) - { - switch (m.AccessLevel) - { - case AccessLevel.Owner: - case AccessLevel.Developer: - case AccessLevel.Administrator: return 0x516; - case AccessLevel.Seer: return 0x144; - case AccessLevel.GameMaster: return 0x21; - case AccessLevel.Counselor: return 0x2; - default: - { - return m.Kills >= 5 ? 0x21 : - m.Criminal ? 0x3B1 : 0x58; - } - } - } - - public override void OnResponse(NetState state, in RelayInfo info) - { - var from = state.Mobile; - - switch (info.ButtonID) - { - case 0: // Closed - { - return; - } - case 1: // Previous - { - if (m_Page > 0) - { - from.SendGump(new WhoGump(from, m_Mobiles, m_Page - 1)); - } - - break; - } - case 2: // Next - { - if ((m_Page + 1) * EntryCount < m_Mobiles.Count) - { - from.SendGump(new WhoGump(from, m_Mobiles, m_Page + 1)); - } - - break; - } - default: - { - var index = m_Page * EntryCount + (info.ButtonID - 3); - - if (index >= 0 && index < m_Mobiles.Count) - { - var m = m_Mobiles[index]; - - if (m.Deleted) - { - from.SendMessage("That player has deleted their character."); - from.SendGump(new WhoGump(from, m_Mobiles, m_Page)); - } - else if (m.NetState == null) - { - from.SendMessage("That player is no longer online."); - from.SendGump(new WhoGump(from, m_Mobiles, m_Page)); - } - else if (m == from || !m.Hidden || from.AccessLevel >= m.AccessLevel || - m is PlayerMobile mobile && mobile.VisibilityList.Contains(from)) - { - from.SendGump(new ClientGump(from, m.NetState)); - } - else - { - from.SendMessage("You cannot see them."); - from.SendGump(new WhoGump(from, m_Mobiles, m_Page)); - } - } - - break; - } - } - } - - private class InternalComparer : IComparer - { - public static readonly IComparer Instance = new InternalComparer(); - - public int Compare(Mobile x, Mobile y) - { - if (x == null) - { - throw new ArgumentNullException(nameof(x)); - } - - if (y == null) - { - throw new ArgumentNullException(nameof(y)); - } - - if (x.AccessLevel > y.AccessLevel) - { - return -1; - } - - return x.AccessLevel < y.AccessLevel ? 1 : x.Name.InsensitiveCompare(y.Name); + builder.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3); } } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetHueFor(Mobile m) => + m.AccessLevel switch + { + >= AccessLevel.Administrator => 0x516, + AccessLevel.Seer => 0x144, + AccessLevel.GameMaster => 0x21, + AccessLevel.Counselor => 0x2, + _ when m.Kills >= 5 => 0x21, + _ when m.Criminal => 0x3B1, + _ => 0x58 + }; + + public override void OnResponse(NetState state, in RelayInfo info) + { + var from = state.Mobile; + + switch (info.ButtonID) + { + case 0: // Closed + { + return; + } + case 1: // Previous + { + if (_page > 0) + { + from.SendGump(new WhoGump(_mobiles, _page - 1)); + } + + break; + } + case 2: // Next + { + if ((_page + 1) * EntryCount < _mobiles.Count) + { + from.SendGump(new WhoGump(_mobiles, _page + 1)); + } + + break; + } + default: + { + var index = _page * EntryCount + (info.ButtonID - 3); + + if (index >= 0 && index < _mobiles.Count) + { + var m = _mobiles[index]; + + if (m.Deleted) + { + from.SendMessage("That player has deleted their character."); + from.SendGump(new WhoGump(_mobiles, _page)); + } + else if (m.NetState == null) + { + from.SendMessage("That player is no longer online."); + from.SendGump(new WhoGump(_mobiles, _page)); + } + else if (m == from || !m.Hidden || from.AccessLevel >= m.AccessLevel || + m is PlayerMobile mobile && mobile.VisibilityList.Contains(from)) + { + from.SendGump(new ClientGump(from, m.NetState)); + } + else + { + from.SendMessage("You cannot see them."); + from.SendGump(new WhoGump(_mobiles, _page)); + } + } + + break; + } + } + } + + private class InternalComparer : IComparer + { + public static readonly IComparer Instance = new InternalComparer(); + + public int Compare(Mobile x, Mobile y) + { + if (x == null) + { + throw new ArgumentNullException(nameof(x)); + } + + if (y == null) + { + throw new ArgumentNullException(nameof(y)); + } + + if (x.AccessLevel > y.AccessLevel) + { + return -1; + } + + return x.AccessLevel < y.AccessLevel ? 1 : x.Name.InsensitiveCompare(y.Name); + } + } }