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:
parent
3f6a87483b
commit
fa5eafdaff
23 changed files with 325 additions and 88 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,9 +75,8 @@ namespace Server.Compression
|
|||
{
|
||||
_pathToTar ??= GetPathToTar();
|
||||
|
||||
var tarFlags = compressCommand == null ? "-axf" : "-xf";
|
||||
var useExternalCompression = compressCommand != null ? $"--use-compress-program \"{compressCommand}\" " : "";
|
||||
var arguments = $"{useExternalCompression}{tarFlags} \"{fileNamePath}\" -C \"{outputDirectory}\"";
|
||||
var arguments = $"{useExternalCompression} -xf \"{fileNamePath}\" -C \"{outputDirectory}\"";
|
||||
|
||||
return RunTar(arguments, compressionProgramPath) == 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -515,8 +515,7 @@ namespace Server.Mobiles
|
|||
{
|
||||
if (from.Account is Account acct && from.AccessLevel == AccessLevel.Player)
|
||||
{
|
||||
var time = TimeSpan.FromDays(RewardSystem.RewardInterval.TotalDays * 6) -
|
||||
(Core.Now - acct.Created);
|
||||
var time = TimeSpan.FromDays(RewardSystem.RewardInterval.TotalDays * 6) - acct.AccountAge;
|
||||
|
||||
if (time > TimeSpan.Zero)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,15 +59,8 @@ namespace Server.Engines.VeteranRewards
|
|||
return false;
|
||||
}
|
||||
|
||||
public static bool HasAccess(Mobile mob, RewardEntry entry)
|
||||
{
|
||||
if (Core.Expansion < entry.RequiredExpansion)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return HasAccess(mob, entry.List, out var _);
|
||||
}
|
||||
public static bool HasAccess(Mobile mob, RewardEntry entry) =>
|
||||
Core.Expansion >= entry.RequiredExpansion && HasAccess(mob, entry.List, out var _);
|
||||
|
||||
public static bool HasAccess(Mobile mob, RewardList list, out TimeSpan ts)
|
||||
{
|
||||
|
|
@ -77,13 +70,13 @@ namespace Server.Engines.VeteranRewards
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!(mob.Account is Account acct))
|
||||
if (mob.Account is not Account acct)
|
||||
{
|
||||
ts = TimeSpan.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
ts = list.Age - (Core.Now - acct.Created);
|
||||
ts = list.Age - acct.AccountAge;
|
||||
|
||||
return ts <= TimeSpan.Zero;
|
||||
}
|
||||
|
|
@ -98,12 +91,8 @@ namespace Server.Engines.VeteranRewards
|
|||
return GetRewardLevel(acct);
|
||||
}
|
||||
|
||||
public static int GetRewardLevel(Account acct)
|
||||
{
|
||||
var totalTime = Core.Now - acct.Created;
|
||||
|
||||
return Math.Max((int)(totalTime.TotalDays / RewardInterval.TotalDays), 0);
|
||||
}
|
||||
public static int GetRewardLevel(Account acct) =>
|
||||
Math.Max((int)(acct.AccountAge.TotalDays / RewardInterval.TotalDays), 0);
|
||||
|
||||
public static bool HasHalfLevel(Mobile mob)
|
||||
{
|
||||
|
|
@ -115,14 +104,7 @@ namespace Server.Engines.VeteranRewards
|
|||
return HasHalfLevel(acct);
|
||||
}
|
||||
|
||||
public static bool HasHalfLevel(Account acct)
|
||||
{
|
||||
var totalTime = Core.Now - acct.Created;
|
||||
|
||||
var level = totalTime.TotalDays / RewardInterval.TotalDays;
|
||||
|
||||
return level >= 0.5;
|
||||
}
|
||||
public static bool HasHalfLevel(Account acct) => acct.AccountAge.TotalDays / RewardInterval.TotalDays >= 0.5;
|
||||
|
||||
public static bool ConsumeRewardPoint(Mobile mob)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ namespace Server.Items
|
|||
|
||||
m_Entries = new List<CampfireEntry>();
|
||||
|
||||
Created = Core.Now;
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), OnTick, out _timerToken);
|
||||
}
|
||||
|
||||
|
|
@ -37,9 +36,6 @@ namespace Server.Items
|
|||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime Created { get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public CampfireStatus Status
|
||||
{
|
||||
|
|
|
|||
127
Projects/UOContent/Migrations/Server.Accounting.Account.v4.json
Normal file
127
Projects/UOContent/Migrations/Server.Accounting.Account.v4.json
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
{
|
||||
"version": 4,
|
||||
"type": "Server.Accounting.Account",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Username",
|
||||
"type": "string",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PasswordAlgorithm",
|
||||
"type": "Server.Accounting.Security.PasswordProtectionAlgorithm",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Password",
|
||||
"type": "string",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "AccessLevel",
|
||||
"type": "Server.AccessLevel",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Flags",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LastLogin",
|
||||
"type": "System.DateTime",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TotalGold",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TotalPlat",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Mobiles",
|
||||
"type": "Server.Mobile[]",
|
||||
"rule": "ArrayMigrationRule",
|
||||
"ruleArguments": [
|
||||
"Server.Mobile",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Comments",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Accounting.AccountComment\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"",
|
||||
"Server.Accounting.AccountComment",
|
||||
"SerializationMethodSignatureMigrationRule",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tags",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Accounting.AccountTag\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"",
|
||||
"Server.Accounting.AccountTag",
|
||||
"SerializationMethodSignatureMigrationRule",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LoginIPs",
|
||||
"type": "System.Net.IPAddress[]",
|
||||
"rule": "ArrayMigrationRule",
|
||||
"ruleArguments": [
|
||||
"System.Net.IPAddress",
|
||||
"PrimitiveTypeMigrationRule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "IpRestrictions",
|
||||
"type": "string[]",
|
||||
"rule": "ArrayMigrationRule",
|
||||
"ruleArguments": [
|
||||
"string",
|
||||
"PrimitiveTypeMigrationRule",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TotalGameTime",
|
||||
"type": "System.TimeSpan",
|
||||
"rule": "PrimitiveTypeMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"type": "string",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ namespace Server.Misc
|
|||
|
||||
if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick ||
|
||||
m_OldClientResponse == OldClientResponse.LenientKick &&
|
||||
Core.Now - state.Mobile.CreationTime > m_AgeLeniency &&
|
||||
Core.Now - state.Mobile.Created > m_AgeLeniency &&
|
||||
state.Mobile is PlayerMobile mobile &&
|
||||
mobile.GameTime > m_GameTimeLeniency))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1156,6 +1156,10 @@ namespace Server.Guilds
|
|||
list.TrimExcess();
|
||||
}
|
||||
|
||||
public override void BeforeSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
if (LastFealty + TimeSpan.FromDays(1.0) < Core.Now)
|
||||
|
|
|
|||
|
|
@ -69,24 +69,24 @@ namespace Server.Misc
|
|||
return "";
|
||||
}
|
||||
|
||||
var ts = Core.Now - a.Created;
|
||||
var age = a.AccountAge;
|
||||
|
||||
if (Format(ts.TotalDays, "This account is {0} day{1} old.", out var v))
|
||||
if (Format(age.TotalDays, "This account is {0} day{1} old.", out var v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
if (Format(ts.TotalHours, "This account is {0} hour{1} old.", out v))
|
||||
if (Format(age.TotalHours, "This account is {0} hour{1} old.", out v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
if (Format(ts.TotalMinutes, "This account is {0} minute{1} old.", out v))
|
||||
if (Format(age.TotalMinutes, "This account is {0} minute{1} old.", out v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
if (Format(ts.TotalSeconds, "This account is {0} second{1} old.", out v))
|
||||
if (Format(age.TotalSeconds, "This account is {0} second{1} old.", out v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ namespace Server.Mobiles
|
|||
{
|
||||
SayTo(pm, 501046); // Thou must resign from thy other guild first.
|
||||
}
|
||||
else if (pm.GameTime < JoinGameAge || pm.CreationTime + JoinAge > Core.Now)
|
||||
else if (pm.GameTime < JoinGameAge || pm.Created + JoinAge > Core.Now)
|
||||
{
|
||||
SayTo(pm, 501048); // You are too young to join my guild...
|
||||
}
|
||||
|
|
@ -141,7 +141,7 @@ namespace Server.Mobiles
|
|||
{
|
||||
SayTo(pm, 501046); // Thou must resign from thy other guild first.
|
||||
}
|
||||
else if (pm.GameTime < JoinGameAge || pm.CreationTime + JoinAge > Core.Now)
|
||||
else if (pm.GameTime < JoinGameAge || pm.Created + JoinAge > Core.Now)
|
||||
{
|
||||
SayTo(pm, 501048); // You are too young to join my guild...
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue