fix: Eliminates List allocations in various places. (#2158)

This commit is contained in:
Kamron Batman 2025-11-16 18:33:53 -08:00 committed by GitHub
parent 6f64cddd0b
commit 4836bff5eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 263 additions and 200 deletions

View file

@ -430,8 +430,8 @@ public partial class Container : Item
public virtual bool TryDropItems(Mobile from, bool sendFullMessage, params ReadOnlySpan<Item> droppedItems) public virtual bool TryDropItems(Mobile from, bool sendFullMessage, params ReadOnlySpan<Item> droppedItems)
{ {
var dropItems = new List<Item>(); using var dropItems = PooledRefQueue<Item>.Create();
var stackItems = new List<ItemStackEntry>(); using var stackItems = PooledRefQueue<ItemStackEntry>.Create();
var extraItems = 0; var extraItems = 0;
var extraWeight = 0; var extraWeight = 0;
@ -451,7 +451,7 @@ public partial class Container : Item
if (item is not Container && CheckHold(from, dropped, false, false, 0, extraWeight) && if (item is not Container && CheckHold(from, dropped, false, false, 0, extraWeight) &&
item.CanStackWith(dropped)) 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)) - 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 item.PileWeight; // extra weight delta, do not need TotalWeight as we do not have hybrid stackable container types
stacked = true; stacked = true;
@ -461,7 +461,7 @@ public partial class Container : Item
if (!stacked && CheckHold(from, dropped, false, true, extraItems, extraWeight)) if (!stacked && CheckHold(from, dropped, false, true, extraItems, extraWeight))
{ {
dropItems.Add(dropped); dropItems.Enqueue(dropped);
extraItems++; extraItems++;
extraWeight += dropped.TotalWeight + dropped.PileWeight; extraWeight += dropped.TotalWeight + dropped.PileWeight;
} }
@ -469,14 +469,15 @@ public partial class Container : Item
if (dropItems.Count + stackItems.Count == droppedItems.Length) // All good 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; return true;

View file

@ -547,10 +547,29 @@ public class Region : IComparable<Region>, IValueLinkListNode<Region>
public virtual bool AcceptsSpawnsFrom(Region region) => public virtual bool AcceptsSpawnsFrom(Region region) =>
AllowSpawn() && (region == this || Parent?.AcceptsSpawnsFrom(region) == true); AllowSpawn() && (region == this || Parent?.AcceptsSpawnsFrom(region) == true);
public PooledRefList<Mobile> GetPlayersPooled()
{
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() public List<Mobile> GetPlayers()
{ {
var list = new List<Mobile>(); List<Mobile> list = [];
for (var i = 0; i < Sectors?.Length; i++) for (var i = 0; i < Sectors?.Length; i++)
{ {
var sector = Sectors[i]; var sector = Sectors[i];
@ -609,6 +628,25 @@ public class Region : IComparable<Region>, IValueLinkListNode<Region>
return list; 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() public int GetMobileCount()
{ {
var count = 0; var count = 0;
@ -649,6 +687,26 @@ public class Region : IComparable<Region>, IValueLinkListNode<Region>
return list; 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() public int GetItemCount()
{ {
var count = 0; var count = 0;

View file

@ -16,7 +16,6 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using Server.Buffers; using Server.Buffers;
using Server.Text; using Server.Text;

View file

@ -850,40 +850,6 @@ public partial class Account : IAccount, IComparable<Account>
return true; 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> /// <summary>
/// Deserializes a list of IPAddress values from an xml element. /// Deserializes a list of IPAddress values from an xml element.
/// </summary> /// </summary>

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Server.Collections;
using Server.Gumps; using Server.Gumps;
using Server.Items; using Server.Items;
using Server.Multis; using Server.Multis;
@ -112,7 +113,7 @@ namespace Server.Commands.Generic
if (okay) if (okay)
{ {
var foundations = new List<HouseFoundation>(); using var foundations = PooledRefQueue<HouseFoundation>.Create();
flushToLog = list.Count > 20; flushToLog = list.Count > 20;
for (var i = 0; i < list.Count; ++i) for (var i = 0; i < list.Count; ++i)
@ -127,7 +128,7 @@ namespace Server.Commands.Generic
if (!foundations.Contains(house)) if (!foundations.Contains(house))
{ {
foundations.Add(house); foundations.Enqueue(house);
} }
break; break;
@ -146,9 +147,9 @@ namespace Server.Commands.Generic
} }
} }
foreach (var house in foundations) while (foundations.Count > 0)
{ {
house.Delta(ItemDelta.Update); foundations.Dequeue().Delta(ItemDelta.Update);
} }
} }
else else

View file

@ -33,8 +33,10 @@ namespace Server.Commands.Generic
if (mobiles) 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)) if (BaseCommand.IsAccessible(from, mob) && ext.IsValid(mob))
{ {
list.Add(mob); list.Add(mob);
@ -44,7 +46,8 @@ namespace Server.Commands.Generic
if (items) 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)) if (BaseCommand.IsAccessible(from, item) && ext.IsValid(item))
{ {

View file

@ -1364,6 +1364,8 @@ public class ChampionSpawnRegion : BaseRegion
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 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) public override void OnEnter(Mobile m)
{ {
if (!m.Player || m.AccessLevel != AccessLevel.Player || Spawn.Active) if (!m.Player || m.AccessLevel != AccessLevel.Player || Spawn.Active)
@ -1371,8 +1373,6 @@ public class ChampionSpawnRegion : BaseRegion
return; return;
} }
Region parent = Parent ?? this;
if (Spawn.ReadyToActivate) if (Spawn.ReadyToActivate)
{ {
Spawn.Start(); Spawn.Start();
@ -1384,27 +1384,29 @@ public class ChampionSpawnRegion : BaseRegion
return; return;
} }
List<Mobile> players = parent.GetPlayers(); using var players = (Parent ?? this).GetPlayersPooled();
List<IPAddress> addresses = new List<IPAddress>();
for (var i = 0; i < players.Count; i++) for (var i = 0; i < players.Count; i++)
{ {
if (players[i].AccessLevel == AccessLevel.Player && players[i].NetState != null && var player = players[i];
!addresses.Contains(players[i].NetState.Address) && !((PlayerMobile)players[i]).Young) 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.ActivatedByProximity = true;
Spawn.BeginRestart(TimeSpan.FromMinutes(5.0)); Spawn.BeginRestart(TimeSpan.FromMinutes(5.0));
} }
_addresses.Clear();
} }
public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation) public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)

View file

@ -14,7 +14,7 @@
*************************************************************************/ *************************************************************************/
using System; using System;
using System.Collections.Generic; using Server.Collections;
using Server.Logging; using Server.Logging;
namespace Server.Engines.CannedEvil; namespace Server.Engines.CannedEvil;
@ -67,18 +67,18 @@ public static class ChampionGenerator
*/ */
//We assume that all champion spawns are generated here. //We assume that all champion spawns are generated here.
List<ChampionSpawn> spawns = []; using var spawns = PooledRefQueue<IEntity>.Create();
foreach (Item item in World.Items.Values) foreach (Item item in World.Items.Values)
{ {
if (item is ChampionSpawn spawn) if (item is ChampionSpawn spawn)
{ {
spawns.Add(spawn); spawns.Enqueue(spawn);
} }
} }
for (int i = spawns.Count - 1; i >= 0; i--) while (spawns.Count > 0)
{ {
spawns[i].Delete(); spawns.Dequeue().Delete();
} }
Process(DungeonLocations); Process(DungeonLocations);

View file

@ -1,4 +1,4 @@
using System.Collections.Generic; using Server.Collections;
using Server.Items; using Server.Items;
using Server.Mobiles; using Server.Mobiles;
@ -272,18 +272,23 @@ namespace Server.Engines.Doom
FacialHairHue = 0x482 FacialHairHue = 0x482
}; };
var items = new List<Item>(dealer.Items); using var toDelete = PooledRefQueue<Item>.Create();
for (var i = 0; i < items.Count; ++i) for (var i = 0; i < dealer.Items.Count; ++i)
{ {
var item = items[i]; var item = dealer.Items[i];
if (item.Layer is not Layer.ShopBuy and not Layer.ShopResale and not Layer.ShopSell) if (item.Layer is not Layer.ShopBuy and not Layer.ShopResale and not Layer.ShopSell)
{ {
item.Delete(); toDelete.Enqueue(item);
} }
} }
while (toDelete.Count > 0)
{
toDelete.Dequeue().Delete();
}
dealer.AddItem(new FloppyHat(1)); dealer.AddItem(new FloppyHat(1));
dealer.AddItem(new Robe(1)); dealer.AddItem(new Robe(1));
dealer.AddItem(new LanternOfSouls()); dealer.AddItem(new LanternOfSouls());

View file

@ -667,12 +667,13 @@ public partial class LeverPuzzleController : Item
protected override void OnTick() protected override void OnTick()
{ {
ticks++; ticks++;
var mobiles = m_Controller._lampRoom.GetMobiles(); using var mobiles = m_Controller._lampRoom.GetMobilesPooled();
if (ticks >= 71 || m_Controller._lampRoom.GetPlayerCount() == 0) if (ticks >= 71 || m_Controller._lampRoom.GetPlayerCount() == 0)
{ {
foreach (var mobile in mobiles) for (var i = 0; i < mobiles.Count; i++)
{ {
var mobile = mobiles[i];
if (mobile?.Deleted == false && !mobile.IsDeadBondedPet) if (mobile?.Deleted == false && !mobile.IsDeadBondedPet)
{ {
mobile.Kill(); mobile.Kill();
@ -689,33 +690,36 @@ public partial class LeverPuzzleController : Item
level++; level++;
} }
foreach (var mobile in mobiles) for (var i = 0; i < mobiles.Count; i++)
{ {
if (IsValidDamagable(mobile)) var mobile = mobiles[i];
if (!IsValidDamagable(mobile))
{ {
if (ticks % 2 == 0 && level == 5) continue;
}
if (ticks % 2 == 0 && level == 5)
{
if (mobile.Player)
{ {
if (mobile.Player) mobile.Say(1062092);
if (AniSafe(mobile))
{ {
mobile.Say(1062092); mobile.Animate(32, 5, 1, true, false, 0);
if (AniSafe(mobile))
{
mobile.Animate(32, 5, 1, true, false, 0);
}
} }
DoDamage(mobile, 15, 20, true);
} }
if (Utility.Random((int)(level & ~0xfffffffc), 3) == 3) DoDamage(mobile, 15, 20, true);
{ }
mobile.ApplyPoison(mobile, PA2[level]);
}
if (ticks % 12 == 0 && level > 0 && mobile.Player) if (Utility.Random((int)(level & ~0xfffffffc), 3) == 3)
{ {
mobile.SendLocalizedMessage(PA[level][0], null, PA[level][1]); mobile.ApplyPoison(mobile, PA2[level]);
} }
if (ticks % 12 == 0 && level > 0 && mobile.Player)
{
mobile.SendLocalizedMessage(PA[level][0], null, PA[level][1]);
} }
} }

View file

@ -1,5 +1,5 @@
using System; using System;
using System.Collections.Generic; using Server.Collections;
using Server.Factions.AI; using Server.Factions.AI;
using Server.Items; using Server.Items;
using Server.Mobiles; using Server.Mobiles;
@ -692,41 +692,42 @@ namespace Server.Factions
var dexMod = GetStatMod(m_Guard, StatType.Dex); var dexMod = GetStatMod(m_Guard, StatType.Dex);
var intMod = GetStatMod(m_Guard, StatType.Int); var intMod = GetStatMod(m_Guard, StatType.Int);
var types = new List<Type>(); using var spellTypes = PooledRefQueue<Type>.Create();
if (strMod <= 0) if (strMod <= 0)
{ {
types.Add(typeof(StrengthSpell)); spellTypes.Enqueue(typeof(StrengthSpell));
} }
if (dexMod <= 0 && IsAllowed(GuardAI.Melee)) if (dexMod <= 0 && IsAllowed(GuardAI.Melee))
{ {
types.Add(typeof(AgilitySpell)); spellTypes.Enqueue(typeof(AgilitySpell));
} }
if (intMod <= 0 && IsAllowed(GuardAI.Magic)) if (intMod <= 0 && IsAllowed(GuardAI.Magic))
{ {
types.Add(typeof(CunningSpell)); spellTypes.Enqueue(typeof(CunningSpell));
} }
if (IsAllowed(GuardAI.Bless)) if (IsAllowed(GuardAI.Bless))
{ {
if (types.Count > 1) if (spellTypes.Count > 1)
{ {
spell = new BlessSpell(m_Guard); spell = new BlessSpell(m_Guard);
} }
else if (types.Count == 1) else if (spellTypes.Count == 1)
{ {
spell = types[0].CreateInstance<Spell>(m_Guard, null); spell = spellTypes.Dequeue().CreateInstance<Spell>(m_Guard, null);
} }
} }
else if (types.Count > 0) else if (spellTypes.Count > 0)
{ {
if (types[0] == typeof(StrengthSpell)) var spellType = spellTypes.Dequeue();
if (spellType == typeof(StrengthSpell))
{ {
UseItemByType(typeof(BaseStrengthPotion)); UseItemByType(typeof(BaseStrengthPotion));
} }
else if (types[0] == typeof(AgilitySpell)) else if (spellType == typeof(AgilitySpell))
{ {
UseItemByType(typeof(BaseAgilityPotion)); UseItemByType(typeof(BaseAgilityPotion));
} }
@ -746,30 +747,30 @@ namespace Server.Factions
var dexMod = GetStatMod(combatant, StatType.Dex); var dexMod = GetStatMod(combatant, StatType.Dex);
var intMod = GetStatMod(combatant, StatType.Int); var intMod = GetStatMod(combatant, StatType.Int);
var types = new List<Type>(); using var spellTypes = PooledRefQueue<Type>.Create();
if (strMod >= 0) if (strMod >= 0)
{ {
types.Add(typeof(WeakenSpell)); spellTypes.Enqueue(typeof(WeakenSpell));
} }
if (dexMod >= 0 && IsAllowed(GuardAI.Melee)) if (dexMod >= 0 && IsAllowed(GuardAI.Melee))
{ {
types.Add(typeof(ClumsySpell)); spellTypes.Enqueue(typeof(ClumsySpell));
} }
if (intMod >= 0 && IsAllowed(GuardAI.Magic)) if (intMod >= 0 && IsAllowed(GuardAI.Magic))
{ {
types.Add(typeof(FeeblemindSpell)); spellTypes.Enqueue(typeof(FeeblemindSpell));
} }
if (types.Count > 1) if (spellTypes.Count > 1)
{ {
spell = new CurseSpell(m_Guard); spell = new CurseSpell(m_Guard);
} }
else if (types.Count == 1) else if (spellTypes.Count == 1)
{ {
spell = types[0].CreateInstance<Spell>(m_Guard, null); spell = spellTypes.Dequeue().CreateInstance<Spell>(m_Guard, null);
} }
} }
} }

View file

@ -118,8 +118,7 @@ public abstract partial class DoneQuestCollector : BaseCreature, IRaceChanger
} }
else else
{ {
var conversation = new List<TextDefinition>(); List<TextDefinition> conversation = [..Incomplete];
conversation.AddRange(Incomplete);
var context = MLQuestSystem.GetContext(pm); var context = MLQuestSystem.GetContext(pm);

View file

@ -1,5 +1,5 @@
using System; using System;
using System.Collections.Generic; using Server.Collections;
using Server.Gumps; using Server.Gumps;
using Server.Items; using Server.Items;
using Server.Logging; using Server.Logging;
@ -46,7 +46,7 @@ namespace Server.Engines.MLQuests.Objectives
return; return;
} }
var delivery = new List<Item>(); using var delivery = PooledRefQueue<Item>.Create();
for (var i = 0; i < Amount; ++i) for (var i = 0; i < Amount; ++i)
{ {
@ -54,7 +54,7 @@ namespace Server.Engines.MLQuests.Objectives
if (item != null) if (item != null)
{ {
delivery.Add(item); delivery.Enqueue(item);
if (item.Stackable && Amount > 1) if (item.Stackable && Amount > 1)
{ {
@ -64,9 +64,9 @@ namespace Server.Engines.MLQuests.Objectives
} }
} }
foreach (var item in delivery) while (delivery.Count > 0)
{ {
pack.DropItem(item); // Confirmed: on OSI items are added even if your pack is full pack.DropItem(delivery.Dequeue()); // Confirmed: on OSI items are added even if your pack is full
} }
} }

View file

@ -870,7 +870,7 @@ namespace Server.Gumps
} }
var items = house.GetItems(); var items = house.GetItems();
var mobiles = house.GetMobiles(); using var mobiles = house.GetMobilesPooled();
newHouse.MoveToWorld( newHouse.MoveToWorld(
new Point3D( new Point3D(
@ -1216,7 +1216,7 @@ namespace Server.Gumps
); );
var r = m_House.Region; var r = m_House.Region;
var list = r.GetMobiles(); using var list = r.GetMobilesPooled();
for (var i = 0; i < list.Count; ++i) for (var i = 0; i < list.Count; ++i)
{ {
@ -1258,7 +1258,7 @@ namespace Server.Gumps
} }
var r = m_House.Region; var r = m_House.Region;
var list = r.GetMobiles(); using var list = r.GetMobilesPooled();
for (var i = 0; i < list.Count; ++i) for (var i = 0; i < list.Count; ++i)
{ {

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using ModernUO.Serialization; using ModernUO.Serialization;
using Server.Collections; using Server.Collections;
using Server.ContextMenus; using Server.ContextMenus;
@ -141,11 +140,14 @@ namespace Server.Items
{ {
get get
{ {
var lines = new List<string>(); using var lines = PooledRefQueue<string>.Create(256);
for (var i = 0; i < Pages.Length; i++)
foreach (var bpi in Pages)
{ {
lines.AddRange(bpi.Lines); var bpi = Pages[i];
for (var j = 0; j < bpi.Lines.Length; j++)
{
lines.Enqueue(bpi.Lines[j]);
}
} }
return lines.ToArray(); return lines.ToArray();

View file

@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic;
using ModernUO.Serialization; using ModernUO.Serialization;
using Server.Collections;
using Server.Targeting; using Server.Targeting;
namespace Server.Items namespace Server.Items
@ -22,7 +22,7 @@ namespace Server.Items
PostedHue = Poster.Hue; PostedHue = Poster.Hue;
Lines = lines; Lines = lines;
var list = new List<BulletinEquip>(); using var list = PooledRefQueue<BulletinEquip>.Create(poster.Items.Count);
for (var i = 0; i < poster.Items.Count; ++i) for (var i = 0; i < poster.Items.Count; ++i)
{ {
@ -30,7 +30,7 @@ namespace Server.Items
if (item.Layer >= Layer.OneHanded && item.Layer <= Layer.Mount) if (item.Layer >= Layer.OneHanded && item.Layer <= Layer.Mount)
{ {
list.Add(new BulletinEquip(item.ItemID, item.Hue)); list.Enqueue(new BulletinEquip(item.ItemID, item.Hue));
} }
} }

View file

@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic;
using ModernUO.Serialization; using ModernUO.Serialization;
using Server.Collections;
using Server.Multis; using Server.Multis;
namespace Server.Items; namespace Server.Items;
@ -102,15 +102,15 @@ public partial class StrongBox : BaseContainer, IChoppable
public Container ConvertToStandardContainer() public Container ConvertToStandardContainer()
{ {
var metalBox = new MetalBox(); var metalBox = new MetalBox();
var subItems = new List<Item>(Items); using var subItems = PooledRefList<Item>.Create(Items.Count);
subItems.AddRange(Items);
foreach (var subItem in subItems) for (var i = 0; i < subItems.Count; i++)
{ {
metalBox.AddItem(subItem); metalBox.AddItem(subItems[i]);
} }
Delete(); Delete();
return metalBox; return metalBox;
} }
} }

View file

@ -824,25 +824,28 @@ public partial class Corpse : Container, ICarvable
} }
var pack = from.Backpack; var pack = from.Backpack;
using var items = PooledRefList<Item>.Create(128);
if (RestoreEquip != null && pack != null) if (RestoreEquip != null && pack != null)
{ {
var packItems = new List<Item>(pack.Items); // Only items in the top-level pack are re-equipped items.AddRange(pack.Items);
for (var i = 0; i < packItems.Count; i++) // Only items in the top-level pack are re-equipped
for (var i = 0; i < items.Count; i++)
{ {
var packItem = packItems[i]; var packItem = items[i];
if (RestoreEquip.Contains(packItem) && packItem.Movable) if (RestoreEquip.Contains(packItem) && packItem.Movable)
{ {
from.EquipItem(packItem); from.EquipItem(packItem);
} }
} }
items.Clear();
} }
var items = new List<Item>(Items);
var didntFit = false; var didntFit = false;
items.AddRange(Items);
for (var i = 0; !didntFit && i < items.Count; ++i) for (var i = 0; !didntFit && i < items.Count; ++i)
{ {

View file

@ -1,4 +1,3 @@
using System;
using ModernUO.Serialization; using ModernUO.Serialization;
namespace Server.Items; namespace Server.Items;

View file

@ -986,67 +986,71 @@ namespace Server.Mobiles
from.TargetLocked = false; from.TargetLocked = false;
} }
public static void EquipMacro(Mobile m, List<Serial> list) public static void EquipMacro(Mobile m, ref PooledRefList<Serial> list)
{ {
if (m is PlayerMobile { Alive: true } pm && pm.Backpack != null) if (m is not PlayerMobile { Alive: true } pm || pm.Backpack == null)
{ {
var pack = pm.Backpack; return;
}
foreach (var serial in list) var pack = pm.Backpack;
foreach (var serial in list)
{
Item item = null;
foreach (var i in pack.Items)
{ {
Item item = null; if (i.Serial == serial)
foreach (var i in pack.Items)
{ {
if (i.Serial == serial) item = i;
{ break;
item = i;
break;
}
} }
}
if (item == null) if (item == null)
{
continue;
}
var toMove = pm.FindItemOnLayer(item.Layer);
if (toMove != null)
{
// pack.DropItem(toMove);
toMove.Internalize();
if (!pm.EquipItem(item))
{ {
continue; pm.EquipItem(toMove);
}
var toMove = pm.FindItemOnLayer(item.Layer);
if (toMove != null)
{
// pack.DropItem(toMove);
toMove.Internalize();
if (!pm.EquipItem(item))
{
pm.EquipItem(toMove);
}
else
{
pack.DropItem(toMove);
}
} }
else else
{ {
pm.EquipItem(item); pack.DropItem(toMove);
} }
} }
else
{
pm.EquipItem(item);
}
} }
} }
public static void UnequipMacro(Mobile m, List<Layer> layers) public static void UnequipMacro(Mobile m, ref PooledRefList<Layer> layers)
{ {
if (m is PlayerMobile { Alive: true } pm && pm.Backpack != null) if (m is not PlayerMobile { Alive: true } pm || pm.Backpack == null)
{ {
var pack = pm.Backpack; return;
var eq = m.Items; }
for (var i = eq.Count - 1; i >= 0; i--) var pack = pm.Backpack;
var eq = m.Items;
for (var i = eq.Count - 1; i >= 0; i--)
{
var item = eq[i];
if (layers.Contains(item.Layer))
{ {
var item = eq[i]; pack.TryDropItem(pm, item, false);
if (layers.Contains(item.Layer))
{
pack.TryDropItem(pm, item, false);
}
} }
} }
} }
@ -1547,13 +1551,17 @@ namespace Server.Mobiles
// Eject all from house // Eject all from house
from.RevealingAction(); from.RevealingAction();
foreach (var item in context.Foundation.GetItems()) var list = context.Foundation.GetItems();
for (var i = 0; i < list.Count; i++)
{ {
var item = list[i];
item.Location = context.Foundation.BanLocation; item.Location = context.Foundation.BanLocation;
} }
foreach (var mobile in context.Foundation.GetMobiles()) using var mobiles = context.Foundation.GetMobilesPooled();
for (var i = 0; i < mobiles.Count; i++)
{ {
var mobile = mobiles[i];
mobile.Location = context.Foundation.BanLocation; mobile.Location = context.Foundation.BanLocation;
} }

View file

@ -1235,24 +1235,24 @@ namespace Server.Multis
return list; return list;
} }
public List<Mobile> GetMobiles() public PooledRefList<Mobile> GetMobilesPooled()
{ {
if (Map == null || Map == Map.Internal) if (Map == null || Map == Map.Internal)
{ {
return new List<Mobile>(); return PooledRefList<Mobile>.Create(0);
} }
var list = new List<Mobile>(); var mobileList = Region.GetMobilesPooled();
for (var i = mobileList.Count - 1; i >= 0; i--)
foreach (var mobile in Region.GetMobiles())
{ {
if (IsInside(mobile)) var mobile = mobileList[i];
if (!IsInside(mobile))
{ {
list.Add(mobile); mobileList.Remove(mobile);
} }
} }
return list; return mobileList;
} }
public virtual bool CheckAosLockdowns(int need) => GetAosCurLockdowns() + need <= GetAosMaxLockdowns(); public virtual bool CheckAosLockdowns(int need) => GetAosCurLockdowns() + need <= GetAosMaxLockdowns();

View file

@ -901,8 +901,10 @@ namespace Server.Multis
item.Location = BanLocation; item.Location = BanLocation;
} }
foreach (var mobile in GetMobiles()) using var mobiles = GetMobilesPooled();
for (var i = 0; i < mobiles.Count; i++)
{ {
var mobile = mobiles[i];
if (mobile != m) if (mobile != m)
{ {
mobile.Location = BanLocation; mobile.Location = BanLocation;
@ -1294,13 +1296,18 @@ namespace Server.Multis
// Eject all from house // Eject all from house
from.RevealingAction(); from.RevealingAction();
foreach (var item in GetItems()) var items = GetItems();
for (var i = 0; i < items.Count; i++)
{ {
var item = items[i];
item.Location = BanLocation; item.Location = BanLocation;
} }
foreach (var mobile in GetMobiles()) using var mobiles = GetMobilesPooled();
var list = GetMobilesPooled();
for (var i = 0; i < list.Count; i++)
{ {
var mobile = list[i];
mobile.Location = BanLocation; mobile.Location = BanLocation;
} }
@ -1760,13 +1767,17 @@ namespace Server.Multis
// Eject all from house // Eject all from house
from.RevealingAction(); from.RevealingAction();
foreach (var item in context.Foundation.GetItems()) var list = context.Foundation.GetItems();
for (var i = 0; i < list.Count; i++)
{ {
var item = list[i];
item.Location = context.Foundation.BanLocation; item.Location = context.Foundation.BanLocation;
} }
foreach (var mobile in context.Foundation.GetMobiles()) using var mobiles = context.Foundation.GetMobilesPooled();
for (var i = 0; i < mobiles.Count; i++)
{ {
var mobile = mobiles[i];
mobile.Location = context.Foundation.BanLocation; mobile.Location = context.Foundation.BanLocation;
} }

View file

@ -14,8 +14,8 @@
*************************************************************************/ *************************************************************************/
using System.Buffers; using System.Buffers;
using System.Collections.Generic;
using System.IO; using System.IO;
using Server.Collections;
using Server.Items; using Server.Items;
using Server.Mobiles; using Server.Mobiles;
@ -112,24 +112,25 @@ public static class IncomingItemPackets
public static void EquipMacro(NetState state, SpanReader reader) public static void EquipMacro(NetState state, SpanReader reader)
{ {
int count = reader.ReadByte(); int count = reader.ReadByte();
var serialList = new List<Serial>(count); var serialList = PooledRefList<Serial>.Create(count);
for (var i = 0; i < count; ++i) for (var i = 0; i < count; ++i)
{ {
serialList.Add((Serial)reader.ReadUInt32()); serialList.Add((Serial)reader.ReadUInt32());
} }
PlayerMobile.EquipMacro(state.Mobile, serialList); PlayerMobile.EquipMacro(state.Mobile, ref serialList);
serialList.Dispose();
} }
public static void UnequipMacro(NetState state, SpanReader reader) public static void UnequipMacro(NetState state, SpanReader reader)
{ {
int count = reader.ReadByte(); int count = reader.ReadByte();
var layers = new List<Layer>(count); var layers = PooledRefList<Layer>.Create(count);
for (var i = 0; i < count; ++i) for (var i = 0; i < count; ++i)
{ {
layers.Add((Layer)reader.ReadUInt16()); layers.Add((Layer)reader.ReadUInt16());
} }
PlayerMobile.UnequipMacro(state.Mobile, layers); PlayerMobile.UnequipMacro(state.Mobile, ref layers);
} }
} }