fix: Fixes GetAllSharedAccounts and other list conversions in AdminGump (#1422)
--------- Co-authored-by: Kamron Batman <3953314+kamronbatman@users.noreply.github.com>
This commit is contained in:
parent
27e00cc73f
commit
3825b16132
2 changed files with 100 additions and 110 deletions
|
|
@ -806,6 +806,27 @@ public static class Utility
|
||||||
return outputList;
|
return outputList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToArray returns an array containing the contents of the List.
|
||||||
|
// This requires copying the List, which is an O(n) operation.
|
||||||
|
public static List<R> ToList<T, R>(this PooledRefList<T> poolList) where T : R
|
||||||
|
{
|
||||||
|
var size = poolList._size;
|
||||||
|
var items = poolList._items;
|
||||||
|
|
||||||
|
var list = new List<R>(size);
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < items.Length; i++)
|
||||||
|
{
|
||||||
|
list.Add(items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool ToBoolean(string value) =>
|
public static bool ToBoolean(string value) =>
|
||||||
bool.TryParse(value, out var b)
|
bool.TryParse(value, out var b)
|
||||||
? b
|
? b
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Server.Accounting;
|
using Server.Accounting;
|
||||||
using Server.Buffers;
|
using Server.Buffers;
|
||||||
|
using Server.Collections;
|
||||||
using Server.Commands;
|
using Server.Commands;
|
||||||
using Server.Misc;
|
using Server.Misc;
|
||||||
using Server.Multis;
|
using Server.Multis;
|
||||||
|
|
@ -597,18 +599,7 @@ namespace Server.Gumps
|
||||||
}
|
}
|
||||||
case AdminGumpPage.Accounts_Shared:
|
case AdminGumpPage.Accounts_Shared:
|
||||||
{
|
{
|
||||||
List<KeyValuePair<IPAddress, List<Account>>> sharedAccounts;
|
m_List ??= GetAllSharedAccounts();
|
||||||
|
|
||||||
if (m_List == null)
|
|
||||||
{
|
|
||||||
sharedAccounts = GetAllSharedAccounts();
|
|
||||||
// TODO: Find a better way, don't use KVPs?
|
|
||||||
m_List = sharedAccounts.ConvertAll(kvp => (object)kvp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sharedAccounts = m_List.SafeConvertList<object, KeyValuePair<IPAddress, List<Account>>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
AddLabelCropped(12, 120, 60, 20, LabelHue, "Count");
|
AddLabelCropped(12, 120, 60, 20, LabelHue, "Count");
|
||||||
AddLabelCropped(72, 120, 120, 20, LabelHue, "Address");
|
AddLabelCropped(72, 120, 120, 20, LabelHue, "Address");
|
||||||
|
|
@ -623,7 +614,7 @@ namespace Server.Gumps
|
||||||
AddImage(375, 122, 0x25EA);
|
AddImage(375, 122, 0x25EA);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((listPage + 1) * 12 < sharedAccounts.Count)
|
if ((listPage + 1) * 12 < m_List.Count)
|
||||||
{
|
{
|
||||||
AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
||||||
}
|
}
|
||||||
|
|
@ -632,21 +623,16 @@ namespace Server.Gumps
|
||||||
AddImage(392, 122, 0x25E6);
|
AddImage(392, 122, 0x25E6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedAccounts.Count == 0)
|
if (m_List.Count == 0)
|
||||||
{
|
{
|
||||||
AddLabel(12, 140, LabelHue, "There are no accounts to display.");
|
AddLabel(12, 140, LabelHue, "There are no accounts to display.");
|
||||||
}
|
}
|
||||||
|
|
||||||
using var sb = ValueStringBuilder.Create();
|
using var sb = ValueStringBuilder.Create();
|
||||||
|
|
||||||
for (int i = 0, index = listPage * 12;
|
for (int i = 0, index = listPage * 12; i < 12 && index >= 0 && index < m_List.Count; ++i, ++index)
|
||||||
i < 12 && index >= 0 && index < sharedAccounts.Count;
|
|
||||||
++i, ++index)
|
|
||||||
{
|
{
|
||||||
var kvp = sharedAccounts[index];
|
var (ipAddr, accts) = (KeyValuePair<IPAddress, List<Account>>)m_List[index];
|
||||||
|
|
||||||
var ipAddr = kvp.Key;
|
|
||||||
var accts = kvp.Value;
|
|
||||||
|
|
||||||
var offset = 140 + i * 20;
|
var offset = 140 + i * 20;
|
||||||
|
|
||||||
|
|
@ -977,17 +963,7 @@ namespace Server.Gumps
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IPAddress> ipAddresses;
|
m_List ??= a.LoginIPs.ToList<object>();
|
||||||
|
|
||||||
if (m_List == null)
|
|
||||||
{
|
|
||||||
ipAddresses = a.LoginIPs.ToList();
|
|
||||||
m_List = ipAddresses.ToList<object>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ipAddresses = m_List.SafeConvertList<object, IPAddress>();
|
|
||||||
}
|
|
||||||
|
|
||||||
AddHtml(10, 195, 400, 20, Color(Center("Client Addresses"), LabelColor32));
|
AddHtml(10, 195, 400, 20, Color(Center("Client Addresses"), LabelColor32));
|
||||||
|
|
||||||
|
|
@ -1018,7 +994,7 @@ namespace Server.Gumps
|
||||||
AddImage(184, 223, 0x25EA);
|
AddImage(184, 223, 0x25EA);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((listPage + 1) * 6 < ipAddresses.Count)
|
if ((listPage + 1) * 6 < m_List.Count)
|
||||||
{
|
{
|
||||||
AddButton(201, 223, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
AddButton(201, 223, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
||||||
}
|
}
|
||||||
|
|
@ -1027,14 +1003,14 @@ namespace Server.Gumps
|
||||||
AddImage(201, 223, 0x25E6);
|
AddImage(201, 223, 0x25E6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipAddresses.Count == 0)
|
if (m_List.Count == 0)
|
||||||
{
|
{
|
||||||
AddHtml(18, 243, 200, 60, Color("This account has not yet been accessed.", LabelColor32));
|
AddHtml(18, 243, 200, 60, Color("This account has not yet been accessed.", LabelColor32));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, index = listPage * 6; i < 6 && index >= 0 && index < ipAddresses.Count; ++i, ++index)
|
for (int i = 0, index = listPage * 6; i < 6 && index >= 0 && index < m_List.Count; ++i, ++index)
|
||||||
{
|
{
|
||||||
AddHtml(18, 243 + i * 22, 114, 20, Color(ipAddresses[index].ToString(), LabelColor32));
|
AddHtml(18, 243 + i * 22, 114, 20, Color(m_List[index].ToString(), LabelColor32));
|
||||||
AddButton(130, 242 + i * 22, 0xFA2, 0xFA4, GetButtonID(8, index));
|
AddButton(130, 242 + i * 22, 0xFA2, 0xFA4, GetButtonID(8, index));
|
||||||
AddButton(160, 242 + i * 22, 0xFA8, 0xFAA, GetButtonID(9, index));
|
AddButton(160, 242 + i * 22, 0xFA8, 0xFAA, GetButtonID(9, index));
|
||||||
AddButton(190, 242 + i * 22, 0xFB1, 0xFB3, GetButtonID(10, index));
|
AddButton(190, 242 + i * 22, 0xFB1, 0xFB3, GetButtonID(10, index));
|
||||||
|
|
@ -1049,17 +1025,7 @@ namespace Server.Gumps
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> ipRestrictions;
|
m_List ??= a.IpRestrictions.ToList<object>();
|
||||||
|
|
||||||
if (m_List == null)
|
|
||||||
{
|
|
||||||
ipRestrictions = a.IpRestrictions.ToList();
|
|
||||||
m_List = ipRestrictions.ToList<object>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ipRestrictions = m_List.SafeConvertList<object, string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
AddHtml(10, 195, 400, 20, Color(Center("Address Restrictions"), LabelColor32));
|
AddHtml(10, 195, 400, 20, Color(Center("Address Restrictions"), LabelColor32));
|
||||||
|
|
||||||
|
|
@ -1092,7 +1058,7 @@ namespace Server.Gumps
|
||||||
AddImage(184, 223, 0x25EA);
|
AddImage(184, 223, 0x25EA);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((listPage + 1) * 6 < ipRestrictions.Count)
|
if ((listPage + 1) * 6 < m_List.Count)
|
||||||
{
|
{
|
||||||
AddButton(201, 223, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
AddButton(201, 223, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
||||||
}
|
}
|
||||||
|
|
@ -1101,16 +1067,14 @@ namespace Server.Gumps
|
||||||
AddImage(201, 223, 0x25E6);
|
AddImage(201, 223, 0x25E6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipRestrictions.Count == 0)
|
if (m_List.Count == 0)
|
||||||
{
|
{
|
||||||
AddHtml(18, 243, 200, 60, Color("There are no addresses in this list.", LabelColor32));
|
AddHtml(18, 243, 200, 60, Color("There are no addresses in this list.", LabelColor32));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, index = listPage * 6;
|
for (int i = 0, index = listPage * 6; i < 6 && index >= 0 && index < m_List.Count; ++i, ++index)
|
||||||
i < 6 && index >= 0 && index < ipRestrictions.Count;
|
|
||||||
++i, ++index)
|
|
||||||
{
|
{
|
||||||
AddHtml(18, 243 + i * 22, 114, 20, Color(ipRestrictions[index], LabelColor32));
|
AddHtml(18, 243 + i * 22, 114, 20, Color((string)m_List[index], LabelColor32));
|
||||||
AddButton(190, 242 + i * 22, 0xFB1, 0xFB3, GetButtonID(8, index));
|
AddButton(190, 242 + i * 22, 0xFB1, 0xFB3, GetButtonID(8, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1246,17 +1210,7 @@ namespace Server.Gumps
|
||||||
{
|
{
|
||||||
AddFirewallHeader();
|
AddFirewallHeader();
|
||||||
|
|
||||||
HashSet<Firewall.IFirewallEntry> firewallEntries;
|
m_List ??= Firewall.Set.ToList<object>();
|
||||||
|
|
||||||
if (m_List == null)
|
|
||||||
{
|
|
||||||
firewallEntries = Firewall.Set;
|
|
||||||
m_List = firewallEntries.ToList<object>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
firewallEntries = m_List.SafeConvertSet<object, Firewall.IFirewallEntry>();
|
|
||||||
}
|
|
||||||
|
|
||||||
AddLabelCropped(12, 120, 358, 20, LabelHue, "IP Address");
|
AddLabelCropped(12, 120, 358, 20, LabelHue, "IP Address");
|
||||||
|
|
||||||
|
|
@ -1269,7 +1223,7 @@ namespace Server.Gumps
|
||||||
AddImage(375, 122, 0x25EA);
|
AddImage(375, 122, 0x25EA);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((listPage + 1) * 12 < firewallEntries.Count)
|
if ((listPage + 1) * 12 < m_List.Count)
|
||||||
{
|
{
|
||||||
AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
||||||
}
|
}
|
||||||
|
|
@ -1278,7 +1232,7 @@ namespace Server.Gumps
|
||||||
AddImage(392, 122, 0x25E6);
|
AddImage(392, 122, 0x25E6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firewallEntries.Count == 0)
|
if (m_List.Count == 0)
|
||||||
{
|
{
|
||||||
AddLabel(12, 140, LabelHue, "The firewall list is empty.");
|
AddLabel(12, 140, LabelHue, "The firewall list is empty.");
|
||||||
}
|
}
|
||||||
|
|
@ -1286,7 +1240,7 @@ namespace Server.Gumps
|
||||||
{
|
{
|
||||||
var i = 0;
|
var i = 0;
|
||||||
var index = listPage * 12;
|
var index = listPage * 12;
|
||||||
foreach (var firewallEntry in firewallEntries)
|
foreach (var firewallEntry in m_List)
|
||||||
{
|
{
|
||||||
if (i >= 12)
|
if (i >= 12)
|
||||||
{
|
{
|
||||||
|
|
@ -1317,11 +1271,9 @@ namespace Server.Gumps
|
||||||
|
|
||||||
AddHtml(10, 175, 400, 20, Color(Center("Potentially Affected Accounts"), LabelColor32));
|
AddHtml(10, 175, 400, 20, Color(Center("Potentially Affected Accounts"), LabelColor32));
|
||||||
|
|
||||||
List<Account> blockedAccts;
|
|
||||||
|
|
||||||
if (m_List == null)
|
if (m_List == null)
|
||||||
{
|
{
|
||||||
blockedAccts = new List<Account>();
|
using var blockedEntriesList = PooledRefList<Account>.Create();
|
||||||
|
|
||||||
foreach (var ia in Accounts.GetAccounts())
|
foreach (var ia in Accounts.GetAccounts())
|
||||||
{
|
{
|
||||||
|
|
@ -1333,18 +1285,15 @@ namespace Server.Gumps
|
||||||
{
|
{
|
||||||
if (firewallEntry.IsBlocked(loginList[i]))
|
if (firewallEntry.IsBlocked(loginList[i]))
|
||||||
{
|
{
|
||||||
blockedAccts.Add(acct);
|
blockedEntriesList.Add(acct);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockedAccts.Sort(AccountComparer.Instance);
|
blockedEntriesList.Sort(AccountComparer.Instance);
|
||||||
m_List = blockedAccts.ToList<object>();
|
|
||||||
}
|
m_List = blockedEntriesList.ToList<Account, object>();
|
||||||
else
|
|
||||||
{
|
|
||||||
blockedAccts = m_List.SafeConvertList<object, Account>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listPage > 0)
|
if (listPage > 0)
|
||||||
|
|
@ -1356,7 +1305,7 @@ namespace Server.Gumps
|
||||||
AddImage(375, 177, 0x25EA);
|
AddImage(375, 177, 0x25EA);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((listPage + 1) * 12 < blockedAccts.Count)
|
if ((listPage + 1) * 12 < m_List.Count)
|
||||||
{
|
{
|
||||||
AddButton(392, 177, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
AddButton(392, 177, 0x15E1, 0x15E5, GetButtonID(1, 1));
|
||||||
}
|
}
|
||||||
|
|
@ -1365,16 +1314,16 @@ namespace Server.Gumps
|
||||||
AddImage(392, 177, 0x25E6);
|
AddImage(392, 177, 0x25E6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockedAccts.Count == 0)
|
if (m_List.Count == 0)
|
||||||
{
|
{
|
||||||
AddLabelCropped(12, 200, 398, 20, LabelHue, "No accounts found.");
|
AddLabelCropped(12, 200, 398, 20, LabelHue, "No accounts found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, index = listPage * 9;
|
for (int i = 0, index = listPage * 9;
|
||||||
i < 9 && index >= 0 && index < blockedAccts.Count;
|
i < 9 && index >= 0 && index < m_List.Count;
|
||||||
++i, ++index)
|
++i, ++index)
|
||||||
{
|
{
|
||||||
var a = blockedAccts[index];
|
var a = (Account)m_List[index];
|
||||||
|
|
||||||
var offset = 200 + i * 20;
|
var offset = 200 + i * 20;
|
||||||
|
|
||||||
|
|
@ -1569,7 +1518,7 @@ namespace Server.Gumps
|
||||||
AddButtonLabeled(200, 80, GetButtonID(6, 2), "Add (Target)");
|
AddButtonLabeled(200, 80, GetButtonID(6, 2), "Add (Target)");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<KeyValuePair<IPAddress, List<Account>>> GetAllSharedAccounts()
|
private static List<object> GetAllSharedAccounts()
|
||||||
{
|
{
|
||||||
var table = new Dictionary<IPAddress, List<Account>>();
|
var table = new Dictionary<IPAddress, List<Account>>();
|
||||||
|
|
||||||
|
|
@ -1579,30 +1528,40 @@ namespace Server.Gumps
|
||||||
|
|
||||||
for (var i = 0; i < theirAddresses.Length; ++i)
|
for (var i = 0; i < theirAddresses.Length; ++i)
|
||||||
{
|
{
|
||||||
table.TryAdd(theirAddresses[i], new List<Account> { acct });
|
var theirAddress = theirAddresses[i];
|
||||||
|
|
||||||
|
// This path is heavy for larger shards, so use optimized code
|
||||||
|
ref var accts = ref CollectionsMarshal.GetValueRefOrAddDefault(table, theirAddress, out var acctExists);
|
||||||
|
|
||||||
|
// If we don't have a list, create one
|
||||||
|
if (!acctExists)
|
||||||
|
{
|
||||||
|
accts = new List<Account>();
|
||||||
|
}
|
||||||
|
|
||||||
|
accts.Add(acct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tableEntries = table.ToList();
|
var list = new List<object>();
|
||||||
|
|
||||||
for (var i = 0; i < tableEntries.Count; ++i)
|
// Lets find all the entries that have only one account
|
||||||
|
foreach (var kvp in table)
|
||||||
{
|
{
|
||||||
var kvp = tableEntries[i];
|
if (kvp.Value.Count > 1)
|
||||||
var list = kvp.Value;
|
{
|
||||||
|
// Sort the accounts alphabetically
|
||||||
|
kvp.Value.Sort(AccountComparer.Instance);
|
||||||
|
|
||||||
if (kvp.Value.Count == 1)
|
// Can't avoid boxing because `m_List` in AdminGump is expecting List<object>
|
||||||
{
|
list.Add(kvp);
|
||||||
list.RemoveAt(i--);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list.Sort(AccountComparer.Instance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tableEntries.Sort(SharedAccountComparer.Instance);
|
// Sort by highest accounts per IP first
|
||||||
|
list.Sort(SharedAccountDescendingComparer.Instance);
|
||||||
|
|
||||||
return tableEntries;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Account> GetSharedAccounts(IPAddress ipAddress)
|
private static List<Account> GetSharedAccounts(IPAddress ipAddress)
|
||||||
|
|
@ -1946,24 +1905,22 @@ namespace Server.Gumps
|
||||||
|
|
||||||
if (m_PageType == AdminGumpPage.Accounts)
|
if (m_PageType == AdminGumpPage.Accounts)
|
||||||
{
|
{
|
||||||
var list = m_List.SafeConvertList<object, Account>();
|
if (m_State is List<Account> rads)
|
||||||
|
|
||||||
if (list != null && m_State is List<Account> rads)
|
|
||||||
{
|
{
|
||||||
for (int i = 0, v = m_ListPage * 12; i < 12 && v < list.Count; ++i, ++v)
|
for (int i = 0, v = m_ListPage * 12; i < 12 && v < m_List.Count; ++i, ++v)
|
||||||
{
|
{
|
||||||
var obj = list[v];
|
var acct = (Account)m_List[v];
|
||||||
|
|
||||||
if (info.IsSwitched(v))
|
if (info.IsSwitched(v))
|
||||||
{
|
{
|
||||||
if (!rads.Contains(obj))
|
if (!rads.Contains(acct))
|
||||||
{
|
{
|
||||||
rads.Add(obj);
|
rads.Add(acct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rads.Contains(obj))
|
else if (rads.Contains(acct))
|
||||||
{
|
{
|
||||||
rads.Remove(obj);
|
rads.Remove(acct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4166,12 +4123,24 @@ namespace Server.Gumps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SharedAccountComparer : IComparer<KeyValuePair<IPAddress, List<Account>>>
|
private class SharedAccountDescendingComparer : IComparer<object>
|
||||||
{
|
{
|
||||||
public static readonly IComparer<KeyValuePair<IPAddress, List<Account>>> Instance = new SharedAccountComparer();
|
public static readonly IComparer<object> Instance = new SharedAccountDescendingComparer();
|
||||||
|
|
||||||
public int Compare(KeyValuePair<IPAddress, List<Account>> x, KeyValuePair<IPAddress, List<Account>> y) =>
|
public int Compare(object x, object y)
|
||||||
x.Value.Count - y.Value.Count;
|
{
|
||||||
|
if (x is not KeyValuePair<IPAddress, List<Account>> a)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y is not KeyValuePair<IPAddress, List<Account>> b)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Value.Count - b.Value.Count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AddCommentPrompt : Prompt
|
private class AddCommentPrompt : Prompt
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue