fix: Fixes stabled, abilities targeting self, and unsummon memory leak (#1418)
## **MAJOR CHANGE** * `Stabled` has been moved to `PlayerMobile`. * New methods added, `PlayerMobile.AddStabled` and `PlayerMobile.RemoveStabled`. * Added `PlayerMobile.AddFollower` and `PlayerMobile.RemoveFollower`. * `Stabled`, `AutoStabled`, and `AllFollowers` are now `HashSet` and **_CAN BE NULL_**. ### Summary * Fixes monster abilities causing harm to the monster through reflect * Adds `CanTriggerAgainstSelf` to override this for healing or some other self-affecting ability * Fixes a major memory leak where `UnsummonTimer` from animated dead spell lasts up-to 24hrs and therefore holds onto references of dead/deleted mobs. * Fixes another minor leak where a mob is not unregistered from the animated dead spell list until the next spell cast.
This commit is contained in:
parent
d99e72db8f
commit
3b97e8d39c
13 changed files with 391 additions and 280 deletions
18
Projects/Server/Mobiles/Mobile.Migrations.cs
Normal file
18
Projects/Server/Mobiles/Mobile.Migrations.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Server;
|
||||
|
||||
public partial class Mobile
|
||||
{
|
||||
// Migrating Stabled property to PlayerMobile
|
||||
public static Dictionary<Mobile, HashSet<Mobile>> StableMigrations { get; private set; }
|
||||
|
||||
public static void AddToStabledMigration(Mobile m, HashSet<Mobile> stabled)
|
||||
{
|
||||
if (stabled?.Count > 0)
|
||||
{
|
||||
StableMigrations ??= new Dictionary<Mobile, HashSet<Mobile>>();
|
||||
StableMigrations[m] = stabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ public delegate int AOSStatusHandler(Mobile from, int index);
|
|||
/// <summary>
|
||||
/// Base class representing players, npcs, and creatures.
|
||||
/// </summary>
|
||||
public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyListEntity
|
||||
public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyListEntity
|
||||
{
|
||||
// Allow four warmode changes in 0.5 seconds, any more will be delay for two seconds
|
||||
private const int WarmodeCatchCount = 4;
|
||||
|
|
@ -426,8 +426,6 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
}
|
||||
}
|
||||
|
||||
public List<Mobile> Stabled { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
public VirtueInfo Virtues { get; private set; }
|
||||
|
||||
|
|
@ -2279,7 +2277,7 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
|
||||
public virtual void Serialize(IGenericWriter writer)
|
||||
{
|
||||
writer.Write(33); // version
|
||||
writer.Write(34); // version
|
||||
|
||||
writer.WriteDeltaTime(LastStrGain);
|
||||
writer.WriteDeltaTime(LastIntGain);
|
||||
|
|
@ -2317,8 +2315,15 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
|
||||
// writer.Write(CreationTime);
|
||||
|
||||
Stabled.Tidy();
|
||||
writer.Write(Stabled);
|
||||
// if (Stabled == null)
|
||||
// {
|
||||
// writer.Write(0);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Stabled.Tidy();
|
||||
// writer.Write(Stabled);
|
||||
// }
|
||||
|
||||
writer.Write(CantWalk);
|
||||
|
||||
|
|
@ -2448,11 +2453,6 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < Stabled.Count; i++)
|
||||
{
|
||||
Stabled[i].Delete();
|
||||
}
|
||||
|
||||
SendRemovePacket();
|
||||
|
||||
m_Guild?.OnDelete(this);
|
||||
|
|
@ -6074,6 +6074,11 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
|
||||
switch (version)
|
||||
{
|
||||
case 34:
|
||||
{
|
||||
// Moved Stabled to PlayerMobile
|
||||
goto case 33;
|
||||
}
|
||||
case 33:
|
||||
{
|
||||
// Removed created
|
||||
|
|
@ -6148,7 +6153,11 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
case 22: // Just removed followers
|
||||
case 21:
|
||||
{
|
||||
Stabled = reader.ReadEntityList<Mobile>();
|
||||
if (version < 34)
|
||||
{
|
||||
// Migrated to PlayerMobile
|
||||
AddToStabledMigration(this, reader.ReadEntitySet<Mobile>(true));
|
||||
}
|
||||
|
||||
goto case 20;
|
||||
}
|
||||
|
|
@ -6285,11 +6294,6 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
}
|
||||
case 0:
|
||||
{
|
||||
if (version < 21)
|
||||
{
|
||||
Stabled = new List<Mobile>();
|
||||
}
|
||||
|
||||
if (version < 18)
|
||||
{
|
||||
Virtues = new VirtueInfo();
|
||||
|
|
@ -7721,7 +7725,6 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
Aggressors = new List<AggressorInfo>();
|
||||
Aggressed = new List<AggressorInfo>();
|
||||
Virtues = new VirtueInfo();
|
||||
Stabled = new List<Mobile>();
|
||||
DamageEntries = new List<DamageEntry>();
|
||||
|
||||
NextSkillTime = Core.TickCount;
|
||||
|
|
|
|||
|
|
@ -48,10 +48,18 @@ public static class SerializationExtensions
|
|||
return entity?.Created <= reader.LastSerialized ? entity : null;
|
||||
}
|
||||
|
||||
public static List<T> ReadEntityList<T>(this IGenericReader reader) where T : class, ISerializable
|
||||
public static List<T> ReadEntityList<T>(
|
||||
this IGenericReader reader,
|
||||
bool nullIfEmpty = false
|
||||
) where T : class, ISerializable
|
||||
{
|
||||
var count = reader.ReadInt();
|
||||
|
||||
if (count == 0 && nullIfEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<T>(count);
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
|
|
@ -66,10 +74,18 @@ public static class SerializationExtensions
|
|||
return list;
|
||||
}
|
||||
|
||||
public static HashSet<T> ReadEntitySet<T>(this IGenericReader reader) where T : class, ISerializable
|
||||
public static HashSet<T> ReadEntitySet<T>(
|
||||
this IGenericReader reader,
|
||||
bool nullIfEmpty = false
|
||||
) where T : class, ISerializable
|
||||
{
|
||||
var count = reader.ReadInt();
|
||||
|
||||
if (count == 0 && nullIfEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var set = new HashSet<T>(count);
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue