fix: Cleans up LINQ calls. (#965)

- [X] Removes several `ToList()` uses with `PooledRefQueue`
- [X] Adds a `PeekRandom` to PooledRefQueue
- [X] Updates EV/BS so they dispel each other in a more efficient manner.
- [X] Fixes Firebomb so it works like a normal firefield.
- [X] Fixes field spells so they aren't unnecessarily using a Point3D ref more than necessary.
- [X] Removes extra allocation in campfire by using reverse loop.
- [X] Removes other LINQ calls that aren't needed.
This commit is contained in:
Kamron Batman 2022-03-20 19:20:54 -07:00 • committed by GitHub
parent daf89686d1
commit 23532db603
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 585 additions and 447 deletions

View file

@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Collections;
using Server.Network;
using Server.Spells;
using Server.Spells.Fourth;
using Server.Targeting;
namespace Server.Items
@ -10,6 +11,7 @@ namespace Server.Items
public class Firebomb : Item
{
private Mobile m_LitBy;
private Point3D _thrownFromLocation;
private int m_Ticks;
private TimerExecutionToken _timerToken;
private List<Mobile> m_Users;
@ -138,24 +140,34 @@ namespace Server.Items
else if (RootParent == null)
{
var eable = Map.GetMobilesInRange(Location, 1);
var toDamage = eable.ToList();
eable.Free();
for (var i = 0; i < toDamage.Count; ++i)
using var targets = PooledRefQueue<Mobile>.Create();
foreach (var m in eable)
{
var victim = toDamage[i];
if (m_LitBy == null || SpellHelper.ValidIndirectTarget(m_LitBy, victim) &&
m_LitBy.CanBeHarmful(victim, false))
if (m_LitBy == null || SpellHelper.ValidIndirectTarget(m_LitBy, m) &&
m_LitBy.CanBeHarmful(m, false))
{
m_LitBy?.DoHarmful(victim);
AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
targets.Enqueue(m);
}
}
eable.Free();
new FirebombField(m_LitBy, toDamage).MoveToWorld(Location, Map);
while (targets.Count > 0)
{
var victim = targets.Dequeue();
m_LitBy?.DoHarmful(victim);
AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
}
var loc = _thrownFromLocation;
var eastToWest = SpellHelper.GetEastToWest(loc, Location);
Effects.PlaySound(loc, Map, 0x20C);
var itemID = eastToWest ? 0x398C : 0x3996;
for (var i = -2; i <= 2; ++i)
{
var targetLoc = new Point3D(eastToWest ? loc.X + i : loc.X, eastToWest ? loc.Y : loc.Y + i, loc.Z);
new FireFieldSpell.FireFieldItem(itemID, targetLoc, m_LitBy, Map, TimeSpan.FromSeconds(9), i);
}
}
_timerToken.Cancel();
@ -178,12 +190,12 @@ namespace Server.Items
}
SpellHelper.GetSurfaceTop(ref p);
var loc = new Point3D(p);
_thrownFromLocation = new Point3D(p);
var map = Map;
from.RevealingAction();
var to = p as IEntity ?? new Entity(Serial.Zero, loc, map);
var to = p as IEntity ?? new Entity(Serial.Zero, _thrownFromLocation, map);
Effects.SendMovingEffect(from, to, ItemID, 7, 0, false, false, Hue);
@ -195,7 +207,7 @@ namespace Server.Items
return;
}
MoveToWorld(loc, map);
MoveToWorld(_thrownFromLocation, map);
}
);
Internalize();
@ -203,9 +215,7 @@ namespace Server.Items
private class ThrowTarget : Target
{
public ThrowTarget(Firebomb bomb)
: base(12, true, TargetFlags.None) =>
Bomb = bomb;
public ThrowTarget(Firebomb bomb) : base(12, true, TargetFlags.None) => Bomb = bomb;
public Firebomb Bomb { get; }
@ -215,93 +225,4 @@ namespace Server.Items
}
}
}
public class FirebombField : Item
{
private readonly List<Mobile> m_Burning;
private readonly DateTime m_Expire;
private readonly Mobile m_LitBy;
private TimerExecutionToken _timerToken;
public FirebombField(Mobile litBy, List<Mobile> toDamage) : base(0x376A)
{
Movable = false;
m_LitBy = litBy;
m_Expire = Core.Now + TimeSpan.FromSeconds(10);
m_Burning = toDamage;
Timer.StartTimer(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), OnFirebombFieldTimerTick, out _timerToken);
}
public FirebombField(Serial serial) : base(serial)
{
}
public override void Serialize(IGenericWriter writer)
{
// Don't serialize these...
}
public override void Deserialize(IGenericReader reader)
{
}
public override bool OnMoveOver(Mobile m)
{
if (ItemID == 0x398C && m_LitBy == null ||
SpellHelper.ValidIndirectTarget(m_LitBy, m) && m_LitBy.CanBeHarmful(m, false))
{
m_LitBy?.DoHarmful(m);
AOS.Damage(m, m_LitBy, 2, 0, 100, 0, 0, 0);
m.PlaySound(0x208);
if (!m_Burning.Contains(m))
{
m_Burning.Add(m);
}
}
return true;
}
private void OnFirebombFieldTimerTick()
{
if (Deleted)
{
_timerToken.Cancel();
return;
}
if (ItemID == 0x376A)
{
ItemID = 0x398C;
return;
}
for (var i = 0; i < m_Burning.Count;)
{
var victim = m_Burning[i];
if (victim.Location == Location && victim.Map == Map &&
(m_LitBy == null || SpellHelper.ValidIndirectTarget(m_LitBy, victim) &&
m_LitBy.CanBeHarmful(victim, false)))
{
m_LitBy?.DoHarmful(victim);
AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
++i;
}
else
{
m_Burning.RemoveAt(i);
}
}
if (Core.Now >= m_Expire)
{
_timerToken.Cancel();
Delete();
}
}
}
}

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Mobiles;
namespace Server.Items
@ -58,20 +57,26 @@ namespace Server.Items
switch (value)
{
case CampfireStatus.Burning:
ItemID = 0xDE3;
Light = LightType.Circle300;
break;
{
ItemID = 0xDE3;
Light = LightType.Circle300;
break;
}
case CampfireStatus.Extinguishing:
ItemID = 0xDE9;
Light = LightType.Circle150;
break;
{
ItemID = 0xDE9;
Light = LightType.Circle150;
break;
}
default:
ItemID = 0xDEA;
Light = LightType.ArchedWindowEast;
ClearEntries();
break;
{
ItemID = 0xDEA;
Light = LightType.ArchedWindowEast;
ClearEntries();
break;
}
}
}
}
@ -111,8 +116,10 @@ namespace Server.Items
return;
}
foreach (var entry in m_Entries.ToList())
for (var i = m_Entries.Count - 1; i >= 0; i--)
{
var entry = m_Entries[i];
if (!entry.Valid || entry.Player.NetState == null)
{
RemoveEntry(entry);
@ -149,10 +156,13 @@ namespace Server.Items
return;
}
foreach (var entry in m_Entries.ToList())
foreach (var entry in m_Entries)
{
RemoveEntry(entry);
m_Table.Remove(entry.Player);
}
m_Entries.Clear();
m_Entries.TrimExcess();
}
public override void OnAfterDelete()

View file

@ -1,5 +1,5 @@
using System;
using System.Linq;
using Server.Collections;
using Server.Network;
using Server.Spells;
using Server.Targeting;
@ -100,27 +100,23 @@ namespace Server.Items
true
);
var eable = from.Map.GetMobilesInRange(new Point3D(loc), 2);
var playerVsPlayer = false;
var targets = eable.Where(
m =>
var eable = from.Map.GetMobilesInRange(loc, 2);
using var targets = PooledRefQueue<Mobile>.Create();
foreach (var m in eable)
{
if (from != m && SpellHelper.ValidIndirectTarget(from, m) && from.CanBeHarmful(m, false) &&
(!Core.AOS || from.InLOS(m)))
{
targets.Enqueue(m);
if (m.Player)
{
if (from == m || !SpellHelper.ValidIndirectTarget(from, m) || !from.CanBeHarmful(m, false)
|| Core.AOS && !from.InLOS(m))
{
return false;
}
if (m.Player)
{
playerVsPlayer = true;
}
return true;
playerVsPlayer = true;
}
)
.ToList();
}
}
eable.Free();
@ -178,9 +174,9 @@ namespace Server.Items
damage /= targets.Count;
}
for (var i = 0; i < targets.Count; ++i)
while (targets.Count > 0)
{
var m = targets[i];
var m = targets.Dequeue();
var toDeal = damage;

View file

@ -1,5 +1,5 @@
using System;
using System.Linq;
using Server.Collections;
using Server.Spells;
namespace Server.Items
@ -36,23 +36,30 @@ namespace Server.Items
attacker.FixedEffect(0x3728, 10, 15);
attacker.PlaySound(0x2A1);
var targets = attacker.GetMobilesInRange(1)
.Where(
m =>
m?.Deleted == false && m != defender && m != attacker &&
SpellHelper.ValidIndirectTarget(attacker, m) &&
m.Map == attacker.Map && m.Alive && attacker.CanSee(m) && attacker.CanBeHarmful(m) &&
attacker.InRange(m, weapon.MaxRange) && attacker.InLOS(m)
)
.ToList();
var eable = attacker.GetMobilesInRange(1);
using var queue = PooledRefQueue<Mobile>.Create();
if (targets.Count <= 0)
foreach (var m in eable)
{
if (m?.Deleted == false && m != defender && m != attacker &&
m.Map == attacker.Map && m.Alive &&
SpellHelper.ValidIndirectTarget(attacker, m) &&
attacker.CanSee(m) && attacker.CanBeHarmful(m) &&
attacker.InRange(m, weapon.MaxRange) && attacker.InLOS(m))
{
queue.Enqueue(m);
}
}
eable.Free();
if (queue.Count <= 0)
{
return;
}
var bushido = attacker.Skills.Bushido.Value;
var damageBonus = 1.0 + Math.Pow(targets.Count * bushido / 60, 2) / 100;
var damageBonus = 1.0 + Math.Pow(queue.Count * bushido / 60, 2) / 100;
if (damageBonus > 2.0)
{
@ -61,10 +68,9 @@ namespace Server.Items
attacker.RevealingAction();
for (var i = 0; i < targets.Count; ++i)
while (queue.Count > 0)
{
var m = targets[i];
var m = queue.Dequeue();
attacker.SendLocalizedMessage(1060161); // The whirling attack strikes a target!
m.SendLocalizedMessage(1060162); // You are struck by the whirling attack and take damage!