Skip to content

fix: Eliminates List allocations in various places. #2158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
17 changes: 9 additions & 8 deletions Projects/Server/Items/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,8 @@ public virtual bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage,

public virtual bool TryDropItems(Mobile from, bool sendFullMessage, params ReadOnlySpan<Item> droppedItems)
{
var dropItems = new List<Item>();
var stackItems = new List<ItemStackEntry>();
using var dropItems = PooledRefQueue<Item>.Create();
using var stackItems = PooledRefQueue<ItemStackEntry>.Create();

var extraItems = 0;
var extraWeight = 0;
Expand All @@ -446,7 +446,7 @@ public virtual bool TryDropItems(Mobile from, bool sendFullMessage, params ReadO
if (item is not Container && CheckHold(from, dropped, false, false, 0, extraWeight) &&
item.CanStackWith(dropped))
{
stackItems.Add(new ItemStackEntry(item, dropped));
stackItems.Enqueue(new ItemStackEntry(item, dropped));
extraWeight += (int)Math.Ceiling(item.Weight * (item.Amount + dropped.Amount)) -
item.PileWeight; // extra weight delta, do not need TotalWeight as we do not have hybrid stackable container types
stacked = true;
Expand All @@ -456,22 +456,23 @@ public virtual bool TryDropItems(Mobile from, bool sendFullMessage, params ReadO

if (!stacked && CheckHold(from, dropped, false, true, extraItems, extraWeight))
{
dropItems.Add(dropped);
dropItems.Enqueue(dropped);
extraItems++;
extraWeight += dropped.TotalWeight + dropped.PileWeight;
}
}

if (dropItems.Count + stackItems.Count == droppedItems.Length) // All good
{
for (var i = 0; i < dropItems.Count; i++)
while (dropItems.Count > 0)
{
DropItem(dropItems[i]);
DropItem(dropItems.Dequeue());
}

for (var i = 0; i < stackItems.Count; i++)
while (stackItems.Count > 0)
{
stackItems[i].m_StackItem.StackWith(from, stackItems[i].m_DropItem, false);
var stackItem = stackItems.Dequeue();
stackItem.m_StackItem.StackWith(from, stackItem.m_DropItem, false);
}

return true;
Expand Down
62 changes: 60 additions & 2 deletions Projects/Server/Regions/Region.cs
Original file line number Diff line number Diff line change
Expand Up @@ -547,10 +547,29 @@ public Region GetRegion(string regionName, bool caseSensitive = true)
public virtual bool AcceptsSpawnsFrom(Region region) =>
AllowSpawn() && (region == this || Parent?.AcceptsSpawnsFrom(region) == true);

public List<Mobile> GetPlayers()
public PooledRefList<Mobile> GetPlayersPooled()
{
var list = new List<Mobile>();
var list = PooledRefList<Mobile>.Create();
for (var i = 0; i < Sectors?.Length; i++)
{
var sector = Sectors[i];

foreach (var ns in sector.Clients)
{
var player = ns.Mobile;
if (player?.Deleted == false && player.Region.IsPartOf(this))
{
list.Add(ns.Mobile);
}
}
}

return list;
}

public List<Mobile> GetPlayers()
{
List<Mobile> list = [];
for (var i = 0; i < Sectors?.Length; i++)
{
var sector = Sectors[i];
Expand Down Expand Up @@ -609,6 +628,25 @@ public List<Mobile> GetMobiles()
return list;
}

public PooledRefList<Mobile> GetMobilesPooled()
{
var list = PooledRefList<Mobile>.Create();
for (var i = 0; i < Sectors?.Length; i++)
{
var sector = Sectors[i];

foreach (var mobile in sector.Mobiles)
{
if (mobile.Region.IsPartOf(this))
{
list.Add(mobile);
}
}
}

return list;
}

public int GetMobileCount()
{
var count = 0;
Expand Down Expand Up @@ -649,6 +687,26 @@ public List<Item> GetItems()
return list;
}

public PooledRefList<Item> GetItemsPooled()
{
var list = PooledRefList<Item>.Create();

for (var i = 0; i < Sectors?.Length; i++)
{
var sector = Sectors[i];

foreach (var item in sector.Items)
{
if (Find(item.Location, item.Map).IsPartOf(this))
{
list.Add(item);
}
}
}

return list;
}

public int GetItemCount()
{
var count = 0;
Expand Down
34 changes: 0 additions & 34 deletions Projects/UOContent/Accounting/Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -849,40 +849,6 @@ private bool UpgradePassword(string password, PasswordProtectionAlgorithm algori
return true;
}

/// <summary>
/// Deserializes a list of string values from an xml element. Null values are not added to the list.
/// </summary>
/// <param name="node">The XmlElement from which to deserialize.</param>
/// <returns>String list. Value will never be null.</returns>
private static string[] LoadAccessCheck(XmlElement node)
{
string[] stringList;
var accessCheck = node["accessCheck"];

if (accessCheck != null)
{
var list = new List<string>();

foreach (XmlElement ip in accessCheck.GetElementsByTagName("ip"))
{
var text = Utility.GetText(ip, null);

if (text != null)
{
list.Add(text);
}
}

stringList = list.ToArray();
}
else
{
stringList = [];
}

return stringList;
}

/// <summary>
/// Deserializes a list of IPAddress values from an xml element.
/// </summary>
Expand Down
9 changes: 5 additions & 4 deletions Projects/UOContent/Commands/Generic/Commands/DesignInsert.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Server.Collections;
using Server.Gumps;
using Server.Items;
using Server.Multis;
Expand Down Expand Up @@ -112,7 +113,7 @@ private void OnConfirmCallback(Mobile from, bool okay, List<object> list, bool s

if (okay)
{
var foundations = new List<HouseFoundation>();
using var foundations = PooledRefQueue<HouseFoundation>.Create();
flushToLog = list.Count > 20;

for (var i = 0; i < list.Count; ++i)
Expand All @@ -127,7 +128,7 @@ private void OnConfirmCallback(Mobile from, bool okay, List<object> list, bool s

if (!foundations.Contains(house))
{
foundations.Add(house);
foundations.Enqueue(house);
}

break;
Expand All @@ -146,9 +147,9 @@ private void OnConfirmCallback(Mobile from, bool okay, List<object> list, bool s
}
}

foreach (var house in foundations)
while (foundations.Count > 0)
{
house.Delta(ItemDelta.Update);
foundations.Dequeue().Delta(ItemDelta.Update);
}
}
else
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Server.Collections;

Check warning on line 3 in Projects/UOContent/Commands/Generic/Implementors/RegionCommandImplementor.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Redundant using directive

Using directive is not required by the code and can be safely removed

namespace Server.Commands.Generic
{
Expand Down Expand Up @@ -33,8 +34,10 @@

if (mobiles)
{
foreach (var mob in reg.GetMobiles())
using var mobileList = reg.GetMobilesPooled();
for (var i = 0; i < mobileList.Count; i++)
{
var mob = mobileList[i];
if (BaseCommand.IsAccessible(from, mob) && ext.IsValid(mob))
{
list.Add(mob);
Expand All @@ -44,7 +47,8 @@

if (items)
{
foreach (var item in reg.GetItems())
using var itemList = reg.GetItemsPooled();
foreach (var item in itemList)
{
if (BaseCommand.IsAccessible(from, item) && ext.IsValid(item))
{
Expand Down
47 changes: 25 additions & 22 deletions Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

using System;
using System.Collections.Generic;
using Server.Collections;
using Server.Misc;

namespace Server.Engines.CannedEvil
Expand All @@ -38,58 +39,60 @@ public static void Initialize()
public static void AddSpawn(DungeonChampionSpawn spawn)
{
_dungeonSpawns.Add(spawn);
Instance?.OnSlice(_dungeonSpawns, false);
OnSlice(_dungeonSpawns, false);
}

public static void AddSpawn(LLChampionSpawn spawn)
{
_lostLandsSpawns.Add(spawn);
Instance?.OnSlice(_lostLandsSpawns, false);
OnSlice(_lostLandsSpawns, false);
}

public static void RemoveSpawn(DungeonChampionSpawn spawn)
{
_dungeonSpawns.Remove(spawn);
Instance?.OnSlice(_dungeonSpawns, false);
OnSlice(_dungeonSpawns, false);
}

public static void RemoveSpawn(LLChampionSpawn spawn)
{
_lostLandsSpawns.Remove(spawn);
Instance?.OnSlice(_lostLandsSpawns, false);
OnSlice(_lostLandsSpawns, false);
}

public CannedEvilTimer() : base(TimeSpan.Zero, TimeSpan.FromMinutes(1.0))
{
_sliceTime = Core.Now;
}

public void OnSlice<T>(ICollection<T> list, bool rotate = true) where T : ChampionSpawn
public static void OnSlice<T>(ICollection<T> list, bool rotate = true) where T : ChampionSpawn
{
if (list.Count > 0)
if (list.Count <= 0)
{
List<T> valid = new List<T>();
return;
}

using var valid = PooledRefQueue<IEntity>.Create();

foreach (T spawn in list)
foreach (T spawn in list)
{
if (spawn.AlwaysActive && !spawn.Active)
{
if (spawn.AlwaysActive && !spawn.Active)
{
spawn.ReadyToActivate = true;
}
else if (rotate && (!spawn.Active || spawn.Kills == 0 && spawn.Level == 0))
{
spawn.Active = false;
spawn.ReadyToActivate = false;

valid.Add(spawn);
}
spawn.ReadyToActivate = true;
}

if (valid.Count > 0)
else if (rotate && (!spawn.Active || spawn.Kills == 0 && spawn.Level == 0))
{
valid[Utility.Random(valid.Count)].ReadyToActivate = true;
spawn.Active = false;
spawn.ReadyToActivate = false;

valid.Enqueue(spawn);
}
}

if (valid.Count > 0 && valid.PeekRandom() is T t)
{
t.ReadyToActivate = true;
}
}

protected override void OnTick()
Expand Down
23 changes: 13 additions & 10 deletions Projects/UOContent/Engines/CannedEvil/ChampionSpawn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ModernUO.Serialization;
using Server.Collections;

Check warning on line 21 in Projects/UOContent/Engines/CannedEvil/ChampionSpawn.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Redundant using directive

Using directive is not required by the code and can be safely removed
using Server.Engines.Virtues;
using Server.Gumps;
using Server.Items;
Expand Down Expand Up @@ -1364,15 +1365,15 @@
global = Math.Max(global, 1 + Spawn.Level); //This is a guesstimate. TODO: Verify & get exact values // OSI testing: at 2 red skulls, light = 0x3 ; 1 red = 0x3.; 3 = 8; 9 = 0xD 8 = 0xD 12 = 0x12 10 = 0xD
}

private static readonly HashSet<IPAddress> _addresses = [];

public override void OnEnter(Mobile m)
{
if (!m.Player || m.AccessLevel != AccessLevel.Player || Spawn.Active)
{
return;
}

Region parent = Parent ?? this;

if (Spawn.ReadyToActivate)
{
Spawn.Start();
Expand All @@ -1384,27 +1385,29 @@
return;
}

List<Mobile> players = parent.GetPlayers();
List<IPAddress> addresses = new List<IPAddress>();
using var players = (Parent ?? this).GetPlayersPooled();

for (var i = 0; i < players.Count; i++)
{
if (players[i].AccessLevel == AccessLevel.Player && players[i].NetState != null &&
!addresses.Contains(players[i].NetState.Address) && !((PlayerMobile)players[i]).Young)
var player = players[i];
if (player.AccessLevel == AccessLevel.Player && player.NetState != null && !((PlayerMobile)player).Young)
{
addresses.Add(players[i].NetState.Address);
_addresses.Add(player.NetState.Address);
}
}

if (addresses.Count >= 15)
if (_addresses.Count >= 15)
{
foreach (Mobile player in players)
for (var i = 0; i < players.Count; i++)
{
player.SendMessage(0x20, Spawn.BroadcastMessage);
players[i].SendMessage(0x20, Spawn.BroadcastMessage);
}

Spawn.ActivatedByProximity = true;
Spawn.BeginRestart(TimeSpan.FromMinutes(5.0));
}

_addresses.Clear();
}

public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
Expand Down
Loading
Loading