fix: Adds Created, LastSerialized, and BeforeSerialize for all entities. (#775)

* Adds `BeforeSerialized` for entities to handle cleanup.
* Adds `Created` and `LastSerialized` fields to all entities. While this is a big bloat, this will be necessary for identifying dangling references to other invalid entities.
* Changes formula for determining a valid reference to be _not null, not deleted, and reference's created date must be at or before the entities last serialized date_.
* Adds versioning to idx file and serializes `Created` and `LastSerialized`.
* Fixes Save Stats and also disables it by default.
This commit is contained in:
Kamron Batman 2021-09-26 01:09:45 -07:00 • committed by GitHub
parent 3f6a87483b
commit fa5eafdaff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 325 additions and 88 deletions

View file

@ -11,7 +11,7 @@ using Server.Network;
namespace Server.Accounting
{
[Serializable(3)]
[Serializable(4)]
public partial class Account : IAccount, IComparable<Account>, ISerializable
{
public static readonly TimeSpan YoungDuration = TimeSpan.FromHours(40.0);
@ -33,10 +33,7 @@ namespace Server.Accounting
[SerializableField(4)]
private int _flags;
[SerializableField(5, setter: "private")]
private DateTime _created;
[SerializableField(6)]
[SerializableField(5)]
private DateTime _lastLogin;
/// <summary>
@ -44,7 +41,7 @@ namespace Server.Accounting
/// The value does not include the value of Platinum and ranges from
/// 0 to 999,999,999 by default.
/// </summary>
[SerializableField(7, setter: "private")]
[SerializableField(6, setter: "private")]
[SerializableFieldAttr("[CommandProperty(AccessLevel.Administrator)]")]
public int _totalGold;
@ -54,16 +51,16 @@ namespace Server.Accounting
/// 0 to 2,147,483,647 by default.
/// One Platinum represents the value of CurrencyThreshold in Gold.
/// </summary>
[SerializableField(8, setter: "private")]
[SerializableField(7, setter: "private")]
[SerializableFieldAttr("[CommandProperty(AccessLevel.Administrator)]")]
public int _totalPlat;
[SerializableField(9, "private", "private")]
[SerializableField(8, "private", "private")]
private Mobile[] _mobiles;
private List<AccountComment> _comments;
[SerializableField(10)]
[SerializableField(9)]
public List<AccountComment> Comments
{
get => _comments ??= new List<AccountComment>();
@ -76,7 +73,7 @@ namespace Server.Accounting
private List<AccountTag> _tags;
[SerializableField(11)]
[SerializableField(10)]
public List<AccountTag> Tags
{
get => _tags ??= new List<AccountTag>();
@ -87,14 +84,14 @@ namespace Server.Accounting
}
}
[SerializableField(12)]
[SerializableField(11)]
private IPAddress[] _loginIPs;
/// <summary>
/// List of IP addresses for restricted access. '*' wildcard supported. If the array contains zero entries, all IP addresses
/// are allowed.
/// </summary>
[SerializableField(13)]
[SerializableField(12)]
private string[] _ipRestrictions;
private TimeSpan _totalGameTime;
@ -103,7 +100,7 @@ namespace Server.Accounting
/// Gets the total game time of this account, also considering the game time of characters
/// that have been deleted.
/// </summary>
[SerializableField(14)]
[SerializableField(13)]
public TimeSpan TotalGameTime
{
get
@ -125,7 +122,7 @@ namespace Server.Accounting
}
}
[SerializableField(15)]
[SerializableField(14)]
[SerializableFieldAttr("[CommandProperty(AccessLevel.Administrator)]")]
private string _email;
@ -139,7 +136,7 @@ namespace Server.Accounting
_accessLevel = AccessLevel.Player;
_created = _lastLogin = Core.Now;
_lastLogin = Core.Now;
_totalGameTime = TimeSpan.Zero;
_mobiles = new Mobile[7];
@ -184,7 +181,7 @@ namespace Server.Accounting
Enum.TryParse(Utility.GetText(node["accessLevel"], "Player"), true, out _accessLevel);
_flags = Utility.GetXMLInt32(Utility.GetText(node["flags"], "0"), 0);
_created = Utility.GetXMLDateTime(Utility.GetText(node["created"], null), Core.Now);
Created = Utility.GetXMLDateTime(Utility.GetText(node["created"], null), Core.Now);
_lastLogin = Utility.GetXMLDateTime(Utility.GetText(node["lastLogin"], null), Core.Now);
_totalGold = Utility.GetXMLInt32(Utility.GetText(node["totalGold"], "0"), 0);
@ -306,10 +303,22 @@ namespace Server.Accounting
}
}
public TimeSpan AccountAge => Core.Now - Created;
[CommandProperty(AccessLevel.GameMaster, readOnly: true)]
public DateTime Created { get; set; } = Core.Now;
[CommandProperty(AccessLevel.GameMaster)]
DateTime ISerializable.LastSerialized { get; set; } = Core.Now;
public int TypeRef { get; private set; }
public Serial Serial { get; set; }
public void BeforeSerialize()
{
}
[AfterDeserialization]
private void AfterDeserialization()
{
@ -348,6 +357,26 @@ namespace Server.Accounting
}
}
private void MigrateFrom(V3Content content)
{
_username = content.Username;
_passwordAlgorithm = content.PasswordAlgorithm;
_password = content.Password;
_accessLevel = content.AccessLevel;
_flags = content.Flags;
Created = content.Created;
_lastLogin = content.LastLogin;
_totalGold = content.TotalGold;
_totalPlat = content.TotalPlat;
_mobiles = content.Mobiles;
_comments = content.Comments;
_tags = content.Tags;
_loginIPs = content.LoginIPs;
_ipRestrictions = content.IpRestrictions;
_totalGameTime = content.TotalGameTime;
_email = content.Email;
}
private void Deserialize(IGenericReader reader, int version)
{
if (version != 2)
@ -361,7 +390,7 @@ namespace Server.Accounting
_password = reader.ReadString();
_accessLevel = version < 2 ? (AccessLevel)reader.ReadInt() : reader.ReadEnum<AccessLevel>();
_flags = reader.ReadInt();
_created = reader.ReadDateTime();
Created = reader.ReadDateTime();
_lastLogin = reader.ReadDateTime();
_totalGold = reader.ReadInt();

View file

@ -241,7 +241,7 @@ namespace Server.Misc
{
res = DeleteResultType.CharBeingPlayed;
}
else if (RestrictDeletion && Core.Now < m.CreationTime + DeleteDelay)
else if (RestrictDeletion && Core.Now < m.Created + DeleteDelay)
{
res = DeleteResultType.CharTooYoung;
}