fix(core): Fixes accounts and moves it to codegen (#644)
- [X] Fixes TimeSpan not working with codegen
- [X] Fixes bad check for generic classes with a serialize method and deserialize ctor
- [X] Moves Accounts to codegen so it is versioned
- [X] Fixes deserialization of old Accounts with no version variable.
- [X] Fixes deserialize seek not doing anything. 🙈
- [X] Adds Email to serialization
This commit is contained in:
parent
ac4d349caa
commit
75db56edc4
13 changed files with 378 additions and 464 deletions
|
|
@ -44,12 +44,11 @@ namespace SerializationGenerator
|
|||
|
||||
if (isOverride)
|
||||
{
|
||||
source.AppendLine();
|
||||
source.AppendLine($"{indent}base.Serialize(writer);");
|
||||
source.AppendLine();
|
||||
}
|
||||
|
||||
// Version
|
||||
source.AppendLine();
|
||||
source.AppendLine($"{indent}writer.{(encodedVersion ? "WriteEncodedInt" : "Write")}(_version);");
|
||||
|
||||
foreach (var property in properties)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace SerializableMigration
|
|||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol.IsIpAddress(compilation))
|
||||
if (symbol.IsIpAddress(compilation) || symbol.IsTimeSpan(compilation))
|
||||
{
|
||||
ruleArguments = Array.Empty<string>();
|
||||
return true;
|
||||
|
|
@ -91,6 +91,7 @@ namespace SerializableMigration
|
|||
var argument = property.RuleArguments.Length >= 1 ? property.RuleArguments[0] : null;
|
||||
|
||||
const string ipAddress = SymbolMetadata.IPADDRESS_CLASS;
|
||||
const string timeSpan = SymbolMetadata.TIMESPAN_STRUCT;
|
||||
const string date = "System.DateTime";
|
||||
|
||||
var readMethod = property.Type switch
|
||||
|
|
@ -111,7 +112,8 @@ namespace SerializableMigration
|
|||
"decimal" => "ReadDecimal",
|
||||
date when argument == "DeltaTime" => "ReadDeltaTime",
|
||||
date => "ReadDateTime",
|
||||
ipAddress => "ReadIPAddress"
|
||||
ipAddress => "ReadIPAddress",
|
||||
timeSpan => "ReadTimeSpan"
|
||||
};
|
||||
|
||||
var readArgument = readMethod == "ReadString" && argument == "InternString" ? "true" : "";
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
|
@ -63,7 +64,7 @@ namespace SerializableMigration
|
|||
var argument = property.RuleArguments.Length >= 1 &&
|
||||
property.RuleArguments[0] == "DeserializationRequiresParent" ? ", this" : "";
|
||||
|
||||
source.AppendLine($"{indent}{propertyName} = new {property.Type}(reader{argument})");
|
||||
source.AppendLine($"{indent}{propertyName} = new {property.Type}(reader{argument});");
|
||||
}
|
||||
|
||||
public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ namespace SerializationGenerator
|
|||
public const string HASHSET_CLASS = "System.Collections.Generic.HashSet`1";
|
||||
public const string IPADDRESS_CLASS = "System.Net.IPAddress";
|
||||
public const string KEYVALUEPAIR_STRUCT = "System.Collections.Generic.KeyValuePair";
|
||||
public const string TIMESPAN_STRUCT = "System.TimeSpan";
|
||||
|
||||
public static bool IsTimeSpan(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(TIMESPAN_STRUCT),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsIpAddress(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
|
|
|
|||
|
|
@ -73,10 +73,10 @@ namespace SerializationGenerator
|
|||
m => !m.IsStatic &&
|
||||
m.MethodKind == MethodKind.Constructor &&
|
||||
m.Parameters.Length <= 2 &&
|
||||
m.Parameters[0].Equals(genericReaderInterface, SymbolEqualityComparer.Default)
|
||||
SymbolEqualityComparer.Default.Equals(m.Parameters[0].Type, genericReaderInterface)
|
||||
);
|
||||
|
||||
requiresParent = genericCtor?.Parameters.Length == 2 && genericCtor.Parameters[1].Equals(symbol, SymbolEqualityComparer.Default);
|
||||
requiresParent = genericCtor?.Parameters.Length == 2 && SymbolEqualityComparer.Default.Equals(genericCtor.Parameters[1].Type, symbol);
|
||||
return genericCtor != null;
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ namespace SerializationGenerator
|
|||
m => !m.IsStatic &&
|
||||
m.ReturnsVoid &&
|
||||
m.Parameters.Length == 1 &&
|
||||
m.Parameters[0].Equals(genericWriterInterface, SymbolEqualityComparer.Default) &&
|
||||
SymbolEqualityComparer.Default.Equals(m.Parameters[0].Type, genericWriterInterface) &&
|
||||
m.DeclaredAccessibility == Accessibility.Public
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ namespace Server.Accounting
|
|||
long GetTotalGold();
|
||||
}
|
||||
|
||||
public interface IAccount : IGoldAccount, IComparable<IAccount>, ISerializable
|
||||
public interface IAccount : IGoldAccount, IComparable<IAccount>
|
||||
{
|
||||
string Username { get; set; }
|
||||
string Email { get; set; }
|
||||
|
|
|
|||
|
|
@ -164,6 +164,8 @@ namespace Server
|
|||
throw new ArgumentException($"BufferReader does not support {nameof(offset)} beyond Int32.MaxValue");
|
||||
}
|
||||
|
||||
_position = (int)position;
|
||||
|
||||
return _position;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
using Server.Accounting.Security;
|
||||
|
|
@ -10,57 +11,137 @@ using Server.Network;
|
|||
|
||||
namespace Server.Accounting
|
||||
{
|
||||
public partial class Account : IAccount, IComparable<Account>
|
||||
[Serializable(2)]
|
||||
public partial class Account : IAccount, IComparable<Account>, ISerializable
|
||||
{
|
||||
public static readonly TimeSpan YoungDuration = TimeSpan.FromHours(40.0);
|
||||
public static readonly TimeSpan InactiveDuration = TimeSpan.FromDays(180.0);
|
||||
public static readonly TimeSpan EmptyInactiveDuration = TimeSpan.FromDays(30.0);
|
||||
|
||||
private Mobile[] m_Mobiles;
|
||||
private AccessLevel m_AccessLevel;
|
||||
private List<AccountComment> m_Comments;
|
||||
private PasswordProtectionAlgorithm m_PasswordAlgorithm;
|
||||
private List<AccountTag> m_Tags;
|
||||
private TimeSpan m_TotalGameTime;
|
||||
[SerializableField(0)]
|
||||
private string _username;
|
||||
|
||||
[SerializableField(1)]
|
||||
private PasswordProtectionAlgorithm _passwordAlgorithm;
|
||||
|
||||
[SerializableField(2)]
|
||||
private string _password;
|
||||
|
||||
[SerializableField(3)]
|
||||
private AccessLevel _accessLevel;
|
||||
|
||||
[SerializableField(4)]
|
||||
private int _flags;
|
||||
|
||||
[SerializableField(5, setter: "private")]
|
||||
private DateTime _created;
|
||||
|
||||
[SerializableField(6)]
|
||||
private DateTime _lastLogin;
|
||||
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Gold owned by the player.
|
||||
/// The value does not include the value of Platinum and ranges from
|
||||
/// 0 to 999,999,999 by default.
|
||||
/// </summary>
|
||||
[SerializableField(7, setter: "private")]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.Administrator)]")]
|
||||
public int _totalGold;
|
||||
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Platinum owned by the player.
|
||||
/// The value does not include the value of Gold and ranges from
|
||||
/// 0 to 2,147,483,647 by default.
|
||||
/// One Platinum represents the value of CurrencyThreshold in Gold.
|
||||
/// </summary>
|
||||
[SerializableField(8, setter: "private")]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.Administrator)]")]
|
||||
public int _totalPlat;
|
||||
|
||||
[SerializableField(9, "private", "private")]
|
||||
private Mobile[] _mobiles;
|
||||
|
||||
[SerializableField(10, setter: "private")]
|
||||
private List<AccountComment> _comments;
|
||||
|
||||
[SerializableField(10, setter: "private")]
|
||||
private List<AccountTag> _tags;
|
||||
|
||||
[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(12)]
|
||||
private string[] _ipRestrictions;
|
||||
|
||||
private TimeSpan _totalGameTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total game time of this account, also considering the game time of characters
|
||||
/// that have been deleted.
|
||||
/// </summary>
|
||||
[SerializableField(13)]
|
||||
public TimeSpan TotalGameTime
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < _mobiles.Length; i++)
|
||||
{
|
||||
if (_mobiles[i] is PlayerMobile m && m.NetState != null)
|
||||
{
|
||||
return _totalGameTime + (Core.Now - m.SessionStart);
|
||||
}
|
||||
}
|
||||
|
||||
return _totalGameTime;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_totalGameTime = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
[SerializableField(14)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.Administrator)]")]
|
||||
private string _email;
|
||||
|
||||
private Timer m_YoungTimer;
|
||||
|
||||
public Account(string username, string password) : this(Accounts.NewAccount)
|
||||
{
|
||||
Username = username;
|
||||
_username = username;
|
||||
|
||||
SetPassword(password);
|
||||
|
||||
m_AccessLevel = AccessLevel.Player;
|
||||
_accessLevel = AccessLevel.Player;
|
||||
|
||||
Created = LastLogin = Core.Now;
|
||||
m_TotalGameTime = TimeSpan.Zero;
|
||||
_created = _lastLogin = Core.Now;
|
||||
_totalGameTime = TimeSpan.Zero;
|
||||
|
||||
m_Mobiles = new Mobile[7];
|
||||
_mobiles = new Mobile[7];
|
||||
|
||||
IPRestrictions = Array.Empty<string>();
|
||||
LoginIPs = Array.Empty<IPAddress>();
|
||||
_ipRestrictions = Array.Empty<string>();
|
||||
_loginIPs = Array.Empty<IPAddress>();
|
||||
|
||||
Accounts.Add(this);
|
||||
((ISerializable)this).MarkDirty();
|
||||
}
|
||||
|
||||
public Account(Serial serial)
|
||||
{
|
||||
Serial = serial;
|
||||
SetTypeRef(GetType());
|
||||
}
|
||||
|
||||
public Account(XmlElement node)
|
||||
{
|
||||
Serial = Accounts.NewAccount;
|
||||
SetTypeRef(GetType());
|
||||
|
||||
Username = Utility.GetText(node["username"], "empty");
|
||||
_username = Utility.GetText(node["username"], "empty");
|
||||
|
||||
Enum.TryParse(Utility.GetText(node["passwordAlgorithm"], null), true, out m_PasswordAlgorithm);
|
||||
Enum.TryParse(Utility.GetText(node["passwordAlgorithm"], null), true, out _passwordAlgorithm);
|
||||
|
||||
// Backward compatibility with RunUO/ServUO
|
||||
if (m_PasswordAlgorithm == PasswordProtectionAlgorithm.None)
|
||||
if (_passwordAlgorithm == PasswordProtectionAlgorithm.None)
|
||||
{
|
||||
var upgraded =
|
||||
UpgradePassword(
|
||||
|
|
@ -78,44 +159,44 @@ namespace Server.Accounting
|
|||
}
|
||||
else
|
||||
{
|
||||
Password = Utility.GetText(node["password"], null);
|
||||
_password = Utility.GetText(node["password"], null);
|
||||
}
|
||||
|
||||
Enum.TryParse(Utility.GetText(node["accessLevel"], "Player"), true, out m_AccessLevel);
|
||||
Flags = Utility.GetXMLInt32(Utility.GetText(node["flags"], "0"), 0);
|
||||
Created = Utility.GetXMLDateTime(Utility.GetText(node["created"], null), Core.Now);
|
||||
LastLogin = Utility.GetXMLDateTime(Utility.GetText(node["lastLogin"], null), Core.Now);
|
||||
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);
|
||||
_lastLogin = Utility.GetXMLDateTime(Utility.GetText(node["lastLogin"], null), Core.Now);
|
||||
|
||||
TotalGold = Utility.GetXMLInt32(Utility.GetText(node["totalGold"], "0"), 0);
|
||||
TotalPlat = Utility.GetXMLInt32(Utility.GetText(node["totalPlat"], "0"), 0);
|
||||
_totalGold = Utility.GetXMLInt32(Utility.GetText(node["totalGold"], "0"), 0);
|
||||
_totalPlat = Utility.GetXMLInt32(Utility.GetText(node["totalPlat"], "0"), 0);
|
||||
|
||||
m_Mobiles = LoadMobiles(node);
|
||||
m_Comments = LoadComments(node);
|
||||
m_Tags = LoadTags(node);
|
||||
LoginIPs = LoadAddressList(node);
|
||||
IPRestrictions = LoadAccessCheck(node);
|
||||
_mobiles = LoadMobiles(node);
|
||||
_comments = LoadComments(node);
|
||||
_tags = LoadTags(node);
|
||||
_loginIPs = LoadAddressList(node);
|
||||
_ipRestrictions = LoadAccessCheck(node);
|
||||
|
||||
for (var i = 0; i < m_Mobiles.Length; ++i)
|
||||
for (var i = 0; i < _mobiles.Length; ++i)
|
||||
{
|
||||
if (m_Mobiles[i] != null)
|
||||
if (_mobiles[i] != null)
|
||||
{
|
||||
m_Mobiles[i].Account = this;
|
||||
_mobiles[i].Account = this;
|
||||
}
|
||||
}
|
||||
|
||||
var totalGameTime = Utility.GetXMLTimeSpan(Utility.GetText(node["totalGameTime"], null), TimeSpan.Zero);
|
||||
if (totalGameTime == TimeSpan.Zero)
|
||||
{
|
||||
for (var i = 0; i < m_Mobiles.Length; i++)
|
||||
for (var i = 0; i < _mobiles.Length; i++)
|
||||
{
|
||||
if (m_Mobiles[i] is PlayerMobile m)
|
||||
if (_mobiles[i] is PlayerMobile m)
|
||||
{
|
||||
totalGameTime += m.GameTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_TotalGameTime = totalGameTime;
|
||||
_totalGameTime = totalGameTime;
|
||||
|
||||
if (Young)
|
||||
{
|
||||
|
|
@ -123,6 +204,7 @@ namespace Server.Accounting
|
|||
}
|
||||
|
||||
Accounts.Add(this);
|
||||
((ISerializable)this).MarkDirty();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
|
|
@ -141,37 +223,6 @@ namespace Server.Accounting
|
|||
/// </summary>
|
||||
public HardwareInfo HardwareInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of IP addresses for restricted access. '*' wildcard supported. If the array contains zero entries, all IP addresses
|
||||
/// are allowed.
|
||||
/// </summary>
|
||||
public string[] IPRestrictions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of IP addresses which have successfully logged into this account.
|
||||
/// </summary>
|
||||
public IPAddress[] LoginIPs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of account comments. Type of contained objects is AccountComment.
|
||||
/// </summary>
|
||||
public List<AccountComment> Comments => m_Comments ?? (m_Comments = new List<AccountComment>());
|
||||
|
||||
/// <summary>
|
||||
/// List of account tags. Type of contained objects is AccountTag.
|
||||
/// </summary>
|
||||
public List<AccountTag> Tags => m_Tags ?? (m_Tags = new List<AccountTag>());
|
||||
|
||||
/// <summary>
|
||||
/// Account username and password. May be null.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Internal bitfield of account flags. Consider using direct access properties (Banned, Young), or GetFlag/SetFlag methods
|
||||
/// </summary>
|
||||
public int Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag indicating if this account is banned.
|
||||
/// </summary>
|
||||
|
|
@ -216,16 +267,6 @@ namespace Server.Accounting
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The date and time of when this account was created.
|
||||
/// </summary>
|
||||
public DateTime Created { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when this account was last accessed.
|
||||
/// </summary>
|
||||
public DateTime LastLogin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An account is considered inactive based upon LastLogin and InactiveDuration. If the account is empty, it is based upon
|
||||
/// EmptyInactiveDuration
|
||||
|
|
@ -239,168 +280,110 @@ namespace Server.Accounting
|
|||
return false;
|
||||
}
|
||||
|
||||
var inactiveLength = Core.Now - LastLogin;
|
||||
var inactiveLength = Core.Now - _lastLogin;
|
||||
|
||||
return inactiveLength > (Count == 0 ? EmptyInactiveDuration : InactiveDuration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total game time of this account, also considering the game time of characters
|
||||
/// that have been deleted.
|
||||
/// </summary>
|
||||
public TimeSpan TotalGameTime
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < m_Mobiles.Length; i++)
|
||||
{
|
||||
if (m_Mobiles[i] is PlayerMobile m && m.NetState != null)
|
||||
{
|
||||
return m_TotalGameTime + (Core.Now - m.SessionStart);
|
||||
}
|
||||
}
|
||||
|
||||
return m_TotalGameTime;
|
||||
}
|
||||
}
|
||||
|
||||
long ISerializable.SavePosition { get; set; }
|
||||
|
||||
BufferWriter ISerializable.SaveBuffer { get; set; }
|
||||
|
||||
public int TypeRef { get; private set; }
|
||||
|
||||
public Serial Serial { get; set; }
|
||||
|
||||
public void Deserialize(IGenericReader reader)
|
||||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
Username = reader.ReadString();
|
||||
m_PasswordAlgorithm = (PasswordProtectionAlgorithm)reader.ReadInt();
|
||||
Password = reader.ReadString();
|
||||
m_AccessLevel = (AccessLevel)reader.ReadInt();
|
||||
Flags = reader.ReadInt();
|
||||
Created = reader.ReadDateTime();
|
||||
LastLogin = reader.ReadDateTime();
|
||||
|
||||
TotalGold = reader.ReadInt();
|
||||
TotalPlat = reader.ReadInt();
|
||||
|
||||
m_Mobiles = new Mobile[7];
|
||||
var length = reader.ReadInt();
|
||||
for (int i = 0; i < length; i++)
|
||||
if (_comments.Count == 0)
|
||||
{
|
||||
m_Mobiles[i] = reader.ReadEntity<Mobile>();
|
||||
_comments = null;
|
||||
}
|
||||
|
||||
length = reader.ReadInt();
|
||||
m_Comments = length > 0 ? new List<AccountComment>(length) : null;
|
||||
for (int i = 0; i < length; i++)
|
||||
if (_tags.Count == 0)
|
||||
{
|
||||
m_Comments!.Add(new AccountComment(reader));
|
||||
_tags = null;
|
||||
}
|
||||
|
||||
length = reader.ReadInt();
|
||||
m_Tags = length > 0 ? new List<AccountTag>(length) : null;
|
||||
for (int i = 0; i < length; i++)
|
||||
for (var i = 0; i < _mobiles.Length; ++i)
|
||||
{
|
||||
m_Tags!.Add(new AccountTag(reader));
|
||||
}
|
||||
|
||||
length = reader.ReadInt();
|
||||
LoginIPs = new IPAddress[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
if (_mobiles[i] != null)
|
||||
{
|
||||
if (IPAddress.TryParse(reader.ReadString(), out var address))
|
||||
{
|
||||
LoginIPs[i] = Utility.Intern(address);
|
||||
_mobiles[i].Account = this;
|
||||
}
|
||||
}
|
||||
|
||||
length = reader.ReadInt();
|
||||
IPRestrictions = new string[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
if (_totalGameTime == TimeSpan.Zero)
|
||||
{
|
||||
IPRestrictions[i] = reader.ReadString();
|
||||
}
|
||||
|
||||
for (var i = 0; i < m_Mobiles.Length; ++i)
|
||||
for (var i = 0; i < _mobiles.Length; i++)
|
||||
{
|
||||
if (m_Mobiles[i] != null)
|
||||
if (_mobiles[i] is PlayerMobile m)
|
||||
{
|
||||
m_Mobiles[i].Account = this;
|
||||
}
|
||||
}
|
||||
|
||||
var totalGameTime = reader.ReadTimeSpan();
|
||||
if (totalGameTime == TimeSpan.Zero)
|
||||
{
|
||||
for (var i = 0; i < m_Mobiles.Length; i++)
|
||||
{
|
||||
if (m_Mobiles[i] is PlayerMobile m)
|
||||
{
|
||||
totalGameTime += m.GameTime;
|
||||
_totalGameTime += m.GameTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_TotalGameTime = totalGameTime;
|
||||
|
||||
if (Young)
|
||||
{
|
||||
CheckYoung();
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
// Handle old deserialization before codegen
|
||||
private void Deserialize(IGenericReader reader, int version)
|
||||
{
|
||||
writer.Write(Username);
|
||||
writer.Write((int)m_PasswordAlgorithm);
|
||||
writer.Write(Password);
|
||||
writer.Write((int)m_AccessLevel);
|
||||
writer.Write(Flags);
|
||||
writer.Write(Created);
|
||||
writer.Write(LastLogin);
|
||||
writer.Write(TotalGold);
|
||||
writer.Write(TotalPlat);
|
||||
// Due to a bug where we were not versioning at all, reset so we don't have an issue deserializing
|
||||
reader.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
writer.Write(Count);
|
||||
for (int i = 0; i < m_Mobiles.Length; i++)
|
||||
{
|
||||
var m = m_Mobiles[i];
|
||||
if (m != null)
|
||||
{
|
||||
writer.Write(m);
|
||||
}
|
||||
}
|
||||
_username = reader.ReadString();
|
||||
_passwordAlgorithm = (PasswordProtectionAlgorithm)reader.ReadInt();
|
||||
_password = reader.ReadString();
|
||||
_accessLevel = (AccessLevel)reader.ReadInt();
|
||||
_flags = reader.ReadInt();
|
||||
_created = reader.ReadDateTime();
|
||||
_lastLogin = reader.ReadDateTime();
|
||||
|
||||
var length = m_Comments?.Count ?? 0;
|
||||
writer.Write(length);
|
||||
_totalGold = reader.ReadInt();
|
||||
_totalPlat = reader.ReadInt();
|
||||
|
||||
_mobiles = new Mobile[7];
|
||||
var length = reader.ReadInt();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
m_Comments![i].Serialize(writer);
|
||||
_mobiles[i] = reader.ReadEntity<Mobile>();
|
||||
}
|
||||
|
||||
length = m_Tags?.Count ?? 0;
|
||||
writer.Write(length);
|
||||
length = reader.ReadInt();
|
||||
_comments = length > 0 ? new List<AccountComment>(length) : null;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
m_Tags![i].Serialize(writer);
|
||||
_comments!.Add(new AccountComment(reader));
|
||||
}
|
||||
|
||||
writer.Write(LoginIPs.Length);
|
||||
for (int i = 0; i < LoginIPs.Length; i++)
|
||||
length = reader.ReadInt();
|
||||
_tags = length > 0 ? new List<AccountTag>(length) : null;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
writer.Write(LoginIPs[i].ToString());
|
||||
_tags!.Add(new AccountTag(reader));
|
||||
}
|
||||
|
||||
writer.Write(IPRestrictions.Length);
|
||||
for (int i = 0; i < IPRestrictions.Length; i++)
|
||||
length = reader.ReadInt();
|
||||
_loginIPs = new IPAddress[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
writer.Write(IPRestrictions[i]);
|
||||
if (IPAddress.TryParse(reader.ReadString(), out var address))
|
||||
{
|
||||
_loginIPs[i] = Utility.Intern(address);
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write(TotalGameTime);
|
||||
length = reader.ReadInt();
|
||||
_ipRestrictions = new string[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
_ipRestrictions[i] = reader.ReadString();
|
||||
}
|
||||
|
||||
_totalGameTime = reader.ReadTimeSpan();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -427,12 +410,12 @@ namespace Server.Accounting
|
|||
m.Delete();
|
||||
|
||||
m.Account = null;
|
||||
m_Mobiles[i] = null;
|
||||
_mobiles[i] = null;
|
||||
}
|
||||
|
||||
if (LoginIPs.Length != 0 && AccountHandler.IPTable.ContainsKey(LoginIPs[0]))
|
||||
if (_loginIPs.Length != 0 && AccountHandler.IPTable.ContainsKey(_loginIPs[0]))
|
||||
{
|
||||
--AccountHandler.IPTable[LoginIPs[0]];
|
||||
--AccountHandler.IPTable[_loginIPs[0]];
|
||||
}
|
||||
|
||||
Deleted = true;
|
||||
|
|
@ -441,45 +424,26 @@ namespace Server.Accounting
|
|||
|
||||
public bool Deleted { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Account username. Case insensitive validation.
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Account email address.
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initial AccessLevel for new characters created on this account.
|
||||
/// </summary>
|
||||
public AccessLevel AccessLevel
|
||||
{
|
||||
get => m_AccessLevel;
|
||||
set => m_AccessLevel = value;
|
||||
}
|
||||
|
||||
public void SetPassword(string plainPassword)
|
||||
{
|
||||
Password = AccountSecurity.CurrentPasswordProtection.EncryptPassword(plainPassword);
|
||||
m_PasswordAlgorithm = AccountSecurity.CurrentAlgorithm;
|
||||
PasswordAlgorithm = AccountSecurity.CurrentAlgorithm;
|
||||
}
|
||||
|
||||
public bool CheckPassword(string plainPassword)
|
||||
{
|
||||
var phrase = m_PasswordAlgorithm == PasswordProtectionAlgorithm.SHA1
|
||||
? $"{Username}{plainPassword}"
|
||||
var phrase = _passwordAlgorithm == PasswordProtectionAlgorithm.SHA1
|
||||
? $"{_username}{plainPassword}"
|
||||
: plainPassword;
|
||||
|
||||
var ok = AccountSecurity.GetPasswordProtection(m_PasswordAlgorithm).ValidatePassword(Password, phrase);
|
||||
var ok = AccountSecurity.GetPasswordProtection(_passwordAlgorithm).ValidatePassword(Password, phrase);
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upgrade the password protection in case we change the algorithm
|
||||
if (m_PasswordAlgorithm != AccountSecurity.CurrentAlgorithm)
|
||||
if (_passwordAlgorithm != AccountSecurity.CurrentAlgorithm)
|
||||
{
|
||||
SetPassword(plainPassword);
|
||||
}
|
||||
|
|
@ -518,7 +482,7 @@ namespace Server.Accounting
|
|||
/// <summary>
|
||||
/// Gets the maximum amount of characters that this account can hold.
|
||||
/// </summary>
|
||||
public int Length => m_Mobiles.Length;
|
||||
public int Length => _mobiles.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the character at a specified index for this account. Out of bound index values are handled; null returned
|
||||
|
|
@ -528,9 +492,9 @@ namespace Server.Accounting
|
|||
{
|
||||
get
|
||||
{
|
||||
if (index >= 0 && index < m_Mobiles.Length)
|
||||
if (index >= 0 && index < _mobiles.Length)
|
||||
{
|
||||
var m = m_Mobiles[index];
|
||||
var m = _mobiles[index];
|
||||
|
||||
if (m?.Deleted != true)
|
||||
{
|
||||
|
|
@ -540,25 +504,27 @@ namespace Server.Accounting
|
|||
// This is the only place that clears a mobile for garbage collection
|
||||
// outside of an entire account deletion.
|
||||
m.Account = null;
|
||||
m_Mobiles[index] = null;
|
||||
_mobiles[index] = null;
|
||||
((ISerializable)this).MarkDirty();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (index >= 0 && index < m_Mobiles.Length)
|
||||
if (index >= 0 && index < _mobiles.Length)
|
||||
{
|
||||
if (m_Mobiles[index] != null)
|
||||
if (_mobiles[index] != null)
|
||||
{
|
||||
m_Mobiles[index].Account = null;
|
||||
_mobiles[index].Account = null;
|
||||
}
|
||||
|
||||
m_Mobiles[index] = value;
|
||||
_mobiles[index] = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
|
||||
if (m_Mobiles[index] != null)
|
||||
if (_mobiles[index] != null)
|
||||
{
|
||||
m_Mobiles[index].Account = this;
|
||||
_mobiles[index].Account = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -566,23 +532,6 @@ namespace Server.Accounting
|
|||
|
||||
public int CompareTo(IAccount other) => string.CompareOrdinal(Username, other?.Username);
|
||||
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Gold owned by the player.
|
||||
/// The value does not include the value of Platinum and ranges from
|
||||
/// 0 to 999,999,999 by default.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int TotalGold { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Platinum owned by the player.
|
||||
/// The value does not include the value of Gold and ranges from
|
||||
/// 0 to 2,147,483,647 by default.
|
||||
/// One Platinum represents the value of CurrencyThreshold in Gold.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int TotalPlat { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to deposit the given amount of Gold into this account.
|
||||
/// If the given amount is greater than the CurrencyThreshold,
|
||||
|
|
@ -634,7 +583,7 @@ namespace Server.Accounting
|
|||
return true;
|
||||
}
|
||||
|
||||
if (amount > TotalGold)
|
||||
if (amount > _totalGold)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -656,7 +605,7 @@ namespace Server.Accounting
|
|||
return true;
|
||||
}
|
||||
|
||||
if (amount > TotalPlat)
|
||||
if (amount > _totalPlat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -671,15 +620,15 @@ namespace Server.Accounting
|
|||
/// This is strictly for backwards compatibility
|
||||
/// </summary>
|
||||
/// <returns>Total gold, capped at Int32.MaxValue</returns>
|
||||
public long GetTotalGold() => TotalGold + TotalPlat * AccountGold.CurrencyThreshold;
|
||||
public long GetTotalGold() => _totalGold + _totalPlat * AccountGold.CurrencyThreshold;
|
||||
|
||||
public int CompareTo(Account other) => string.CompareOrdinal(Username, other?.Username);
|
||||
public int CompareTo(Account other) => string.CompareOrdinal(_username, other?._username);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a specific flag in the Flags bitfield.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based flag index.</param>
|
||||
public bool GetFlag(int index) => (Flags & (1 << index)) != 0;
|
||||
public bool GetFlag(int index) => (_flags & (1 << index)) != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a specific flag in the Flags bitfield.
|
||||
|
|
@ -705,7 +654,8 @@ namespace Server.Accounting
|
|||
/// <param name="value">New tag value.</param>
|
||||
public void AddTag(string name, string value)
|
||||
{
|
||||
Tags.Add(new AccountTag(name, value));
|
||||
_tags.Add(new AccountTag(name, value));
|
||||
((ISerializable)this).MarkDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -714,18 +664,19 @@ namespace Server.Accounting
|
|||
/// <param name="name">Tag name to remove.</param>
|
||||
public void RemoveTag(string name)
|
||||
{
|
||||
for (var i = Tags.Count - 1; i >= 0; --i)
|
||||
for (var i = _tags.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (i >= Tags.Count)
|
||||
if (i >= _tags.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var tag = Tags[i];
|
||||
var tag = _tags[i];
|
||||
|
||||
if (tag.Name == name)
|
||||
{
|
||||
Tags.RemoveAt(i);
|
||||
_tags.RemoveAt(i);
|
||||
((ISerializable)this).MarkDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -737,13 +688,14 @@ namespace Server.Accounting
|
|||
/// <param name="value">Tag value.</param>
|
||||
public void SetTag(string name, string value)
|
||||
{
|
||||
for (var i = 0; i < Tags.Count; ++i)
|
||||
for (var i = 0; i < _tags.Count; ++i)
|
||||
{
|
||||
var tag = Tags[i];
|
||||
var tag = _tags[i];
|
||||
|
||||
if (tag.Name == name)
|
||||
{
|
||||
tag.Value = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -757,9 +709,9 @@ namespace Server.Accounting
|
|||
/// <param name="name">Name of the desired tag value.</param>
|
||||
public string GetTag(string name)
|
||||
{
|
||||
for (var i = 0; i < Tags.Count; ++i)
|
||||
for (var i = 0; i < _tags.Count; ++i)
|
||||
{
|
||||
var tag = Tags[i];
|
||||
var tag = _tags[i];
|
||||
|
||||
if (tag.Name == name)
|
||||
{
|
||||
|
|
@ -850,7 +802,7 @@ namespace Server.Accounting
|
|||
|
||||
private static void EventSink_Disconnected(Mobile m)
|
||||
{
|
||||
if (!(m.Account is Account acc))
|
||||
if (m.Account is not Account acc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -861,22 +813,22 @@ namespace Server.Accounting
|
|||
acc.m_YoungTimer = null;
|
||||
}
|
||||
|
||||
if (!(m is PlayerMobile pm))
|
||||
if (m is not PlayerMobile pm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
acc.m_TotalGameTime += Core.Now - pm.SessionStart;
|
||||
acc.TotalGameTime += Core.Now - pm.SessionStart;
|
||||
}
|
||||
|
||||
private static void EventSink_Login(Mobile m)
|
||||
{
|
||||
if (!(m is PlayerMobile pm))
|
||||
if (m is not PlayerMobile pm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(m.Account is Account acc))
|
||||
if (m.Account is not Account acc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -898,9 +850,9 @@ namespace Server.Accounting
|
|||
{
|
||||
Young = false;
|
||||
|
||||
for (var i = 0; i < m_Mobiles.Length; i++)
|
||||
for (var i = 0; i < _mobiles.Length; i++)
|
||||
{
|
||||
if (m_Mobiles[i] is PlayerMobile m && m.Young)
|
||||
if (_mobiles[i] is PlayerMobile { Young: true } m)
|
||||
{
|
||||
m.Young = false;
|
||||
|
||||
|
|
@ -930,12 +882,12 @@ namespace Server.Accounting
|
|||
|
||||
private bool UpgradePassword(string password, PasswordProtectionAlgorithm algorithm)
|
||||
{
|
||||
if (password == null || algorithm < m_PasswordAlgorithm)
|
||||
if (password == null || algorithm < _passwordAlgorithm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_PasswordAlgorithm = algorithm;
|
||||
PasswordAlgorithm = algorithm;
|
||||
Password = password.ReplaceOrdinal("-", string.Empty);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1136,7 +1088,7 @@ namespace Server.Accounting
|
|||
{
|
||||
var hasAccess = false;
|
||||
|
||||
if (m_AccessLevel >= level)
|
||||
if (_accessLevel >= level)
|
||||
{
|
||||
hasAccess = true;
|
||||
}
|
||||
|
|
@ -1153,7 +1105,7 @@ namespace Server.Accounting
|
|||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("{0} {1}", hasAccess ? "yes" : "no", m_AccessLevel);
|
||||
Console.WriteLine("{0} {1}", hasAccess ? "yes" : "no", _accessLevel);
|
||||
|
||||
if (!hasAccess)
|
||||
{
|
||||
|
|
@ -1161,11 +1113,11 @@ namespace Server.Accounting
|
|||
}
|
||||
}
|
||||
|
||||
var accessAllowed = IPRestrictions.Length == 0 || IPLimiter.IsExempt(ipAddress);
|
||||
var accessAllowed = _ipRestrictions.Length == 0 || IPLimiter.IsExempt(ipAddress);
|
||||
|
||||
for (var i = 0; !accessAllowed && i < IPRestrictions.Length; ++i)
|
||||
for (var i = 0; !accessAllowed && i < _ipRestrictions.Length; ++i)
|
||||
{
|
||||
accessAllowed = IPAddress.Parse(IPRestrictions[i]).Equals(ipAddress);
|
||||
accessAllowed = IPAddress.Parse(_ipRestrictions[i]).Equals(ipAddress);
|
||||
}
|
||||
|
||||
return accessAllowed;
|
||||
|
|
@ -1190,7 +1142,7 @@ namespace Server.Accounting
|
|||
return;
|
||||
}
|
||||
|
||||
if (LoginIPs.Length == 0)
|
||||
if (_loginIPs.Length == 0)
|
||||
{
|
||||
AccountHandler.IPTable.TryGetValue(ipAddress, out var result);
|
||||
AccountHandler.IPTable[ipAddress] = result + 1;
|
||||
|
|
@ -1198,9 +1150,9 @@ namespace Server.Accounting
|
|||
|
||||
var contains = false;
|
||||
|
||||
for (var i = 0; !contains && i < LoginIPs.Length; ++i)
|
||||
for (var i = 0; !contains && i < _loginIPs.Length; ++i)
|
||||
{
|
||||
contains = LoginIPs[i].Equals(ipAddress);
|
||||
contains = _loginIPs[i].Equals(ipAddress);
|
||||
}
|
||||
|
||||
if (contains)
|
||||
|
|
@ -1208,7 +1160,7 @@ namespace Server.Accounting
|
|||
return;
|
||||
}
|
||||
|
||||
var old = LoginIPs;
|
||||
var old = _loginIPs;
|
||||
LoginIPs = new IPAddress[old.Length + 1];
|
||||
|
||||
for (var i = 0; i < old.Length; ++i)
|
||||
|
|
@ -1239,135 +1191,7 @@ namespace Server.Accounting
|
|||
return hasAccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes this Account instance to an XmlTextWriter.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XmlTextWriter instance from which to serialize.</param>
|
||||
public void Save(XmlTextWriter xml)
|
||||
{
|
||||
xml.WriteStartElement("account");
|
||||
|
||||
xml.WriteStartElement("username");
|
||||
xml.WriteString(Username);
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.WriteStartElement("passwordAlgorithm");
|
||||
xml.WriteString(m_PasswordAlgorithm.ToString());
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.WriteStartElement("password");
|
||||
xml.WriteString(Password);
|
||||
xml.WriteEndElement();
|
||||
|
||||
if (m_AccessLevel != AccessLevel.Player)
|
||||
{
|
||||
xml.WriteStartElement("accessLevel");
|
||||
xml.WriteString(m_AccessLevel.ToString());
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
if (Flags != 0)
|
||||
{
|
||||
xml.WriteStartElement("flags");
|
||||
xml.WriteString(XmlConvert.ToString(Flags));
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
xml.WriteStartElement("created");
|
||||
xml.WriteString(XmlConvert.ToString(Created, XmlDateTimeSerializationMode.Utc));
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.WriteStartElement("lastLogin");
|
||||
xml.WriteString(XmlConvert.ToString(LastLogin, XmlDateTimeSerializationMode.Utc));
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.WriteStartElement("totalGameTime");
|
||||
xml.WriteString(XmlConvert.ToString(TotalGameTime));
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.WriteStartElement("chars");
|
||||
|
||||
for (var i = 0; i < m_Mobiles.Length; ++i)
|
||||
{
|
||||
var m = m_Mobiles[i];
|
||||
|
||||
if (m?.Deleted == false)
|
||||
{
|
||||
xml.WriteStartElement("char");
|
||||
xml.WriteAttributeString("index", i.ToString());
|
||||
xml.WriteString(m.Serial.Value.ToString());
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
|
||||
if (m_Comments?.Count > 0)
|
||||
{
|
||||
xml.WriteStartElement("comments");
|
||||
|
||||
for (var i = 0; i < m_Comments.Count; ++i)
|
||||
{
|
||||
m_Comments[i].Save(xml);
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
if (m_Tags?.Count > 0)
|
||||
{
|
||||
xml.WriteStartElement("tags");
|
||||
|
||||
for (var i = 0; i < m_Tags.Count; ++i)
|
||||
{
|
||||
m_Tags[i].Save(xml);
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
if (LoginIPs.Length > 0)
|
||||
{
|
||||
xml.WriteStartElement("addressList");
|
||||
|
||||
xml.WriteAttributeString("count", LoginIPs.Length.ToString());
|
||||
|
||||
for (var i = 0; i < LoginIPs.Length; ++i)
|
||||
{
|
||||
xml.WriteStartElement("ip");
|
||||
xml.WriteString(LoginIPs[i].ToString());
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
if (IPRestrictions.Length > 0)
|
||||
{
|
||||
xml.WriteStartElement("accessCheck");
|
||||
|
||||
for (var i = 0; i < IPRestrictions.Length; ++i)
|
||||
{
|
||||
xml.WriteStartElement("ip");
|
||||
xml.WriteString(IPRestrictions[i]);
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
xml.WriteStartElement("totalGold");
|
||||
xml.WriteString(XmlConvert.ToString(TotalGold));
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.WriteStartElement("totalPlat");
|
||||
xml.WriteString(XmlConvert.ToString(TotalPlat));
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
public override string ToString() => Username;
|
||||
public override string ToString() => _username;
|
||||
|
||||
private class YoungTimer : Timer
|
||||
{
|
||||
|
|
|
|||
|
|
@ -64,23 +64,6 @@ namespace Server.Accounting
|
|||
/// </summary>
|
||||
public DateTime LastModified { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serializes this AccountComment instance to an XmlTextWriter.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XmlTextWriter instance from which to serialize.</param>
|
||||
public void Save(XmlTextWriter xml)
|
||||
{
|
||||
xml.WriteStartElement("comment");
|
||||
|
||||
xml.WriteAttributeString("addedBy", AddedBy);
|
||||
|
||||
xml.WriteAttributeString("lastModified", XmlConvert.ToString(LastModified, XmlDateTimeSerializationMode.Utc));
|
||||
|
||||
xml.WriteString(m_Content);
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes this AccountComment instance.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -45,18 +45,6 @@ namespace Server.Accounting
|
|||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serializes this AccountTag instance to an XmlTextWriter.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XmlTextWriter instance from which to serialize.</param>
|
||||
public void Save(XmlTextWriter xml)
|
||||
{
|
||||
xml.WriteStartElement("tag");
|
||||
xml.WriteAttributeString("name", Name);
|
||||
xml.WriteString(Value);
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes this AccountTag instance to an XmlTextWriter.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ namespace Server.Accounting
|
|||
{
|
||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(Accounts));
|
||||
|
||||
private static readonly Dictionary<string, IAccount> _accountsByName = new(32, StringComparer.OrdinalIgnoreCase);
|
||||
private static Dictionary<Serial, IAccount> _accountsById = new(32);
|
||||
private static readonly Dictionary<string, Account> _accountsByName = new(32, StringComparer.OrdinalIgnoreCase);
|
||||
private static Dictionary<Serial, Account> _accountsById = new(32);
|
||||
private static Serial _lastAccount;
|
||||
internal static List<Type> Types { get; } = new();
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ namespace Server.Accounting
|
|||
Persistence.Register("Accounts", Serialize, WriteSnapshot, Deserialize);
|
||||
|
||||
internal static void Serialize() =>
|
||||
EntityPersistence.SaveEntities(_accountsById.Values, account => account.Serialize());
|
||||
EntityPersistence.SaveEntities(_accountsById.Values, account => ((ISerializable)account).Serialize());
|
||||
|
||||
internal static void WriteSnapshot(string basePath)
|
||||
{
|
||||
|
|
@ -54,19 +54,19 @@ namespace Server.Accounting
|
|||
|
||||
public static IEnumerable<IAccount> GetAccounts() => _accountsByName.Values;
|
||||
|
||||
public static IAccount GetAccount(string username)
|
||||
public static Account GetAccount(string username)
|
||||
{
|
||||
_accountsByName.TryGetValue(username, out var a);
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void Add(IAccount a)
|
||||
public static void Add(Account a)
|
||||
{
|
||||
_accountsByName[a.Username] = a;
|
||||
_accountsById[a.Serial] = a;
|
||||
}
|
||||
|
||||
public static void Remove(IAccount a)
|
||||
public static void Remove(Account a)
|
||||
{
|
||||
_accountsByName.Remove(a.Username);
|
||||
_accountsById.Remove(a.Serial);
|
||||
|
|
@ -85,7 +85,7 @@ namespace Server.Accounting
|
|||
|
||||
IIndexInfo<Serial> indexInfo = new EntityTypeIndex("Accounts");
|
||||
|
||||
_accountsById = EntityPersistence.LoadIndex(path, indexInfo, out List<EntityIndex<IAccount>> accounts);
|
||||
_accountsById = EntityPersistence.LoadIndex(path, indexInfo, out List<EntityIndex<Account>> accounts);
|
||||
EntityPersistence.LoadData(path, indexInfo, accounts);
|
||||
|
||||
foreach (var a in _accountsById.Values)
|
||||
|
|
|
|||
|
|
@ -1056,7 +1056,7 @@ namespace Server.Gumps
|
|||
|
||||
if (m_List == null)
|
||||
{
|
||||
ipRestrictions = a.IPRestrictions.ToList();
|
||||
ipRestrictions = a.IpRestrictions.ToList();
|
||||
m_List = ipRestrictions.ToList<object>();
|
||||
}
|
||||
else
|
||||
|
|
@ -3000,7 +3000,7 @@ namespace Server.Gumps
|
|||
}
|
||||
else
|
||||
{
|
||||
var list = a.IPRestrictions;
|
||||
var list = a.IpRestrictions;
|
||||
|
||||
var contains = false;
|
||||
for (var i = 0; !contains && i < list.Length; ++i)
|
||||
|
|
@ -3023,7 +3023,7 @@ namespace Server.Gumps
|
|||
|
||||
newList[list.Length] = ip;
|
||||
|
||||
a.IPRestrictions = newList;
|
||||
a.IpRestrictions = newList;
|
||||
|
||||
notice = $"{ip} : Added to restriction list.";
|
||||
}
|
||||
|
|
@ -3888,9 +3888,9 @@ namespace Server.Gumps
|
|||
}
|
||||
else if (m_PageType == AdminGumpPage.AccountDetails_Access_Restrictions)
|
||||
{
|
||||
var list = a.IPRestrictions.ToList();
|
||||
var list = a.IpRestrictions.ToList();
|
||||
list.Remove(m_List[index] as string);
|
||||
a.IPRestrictions = list.ToArray();
|
||||
a.IpRestrictions = list.ToArray();
|
||||
|
||||
from.SendGump(
|
||||
new AdminGump(
|
||||
|
|
|
|||
108
Projects/UOContent/Migrations/Server.Accounting.Account.v2.json
Normal file
108
Projects/UOContent/Migrations/Server.Accounting.Account.v2.json
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"version": 2,
|
||||
"type": "Server.Accounting.Account",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Username",
|
||||
"type": "string",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": []
|
||||
},
|
||||
{
|
||||
"name": "PasswordAlgorithm",
|
||||
"type": "Server.Accounting.Security.PasswordProtectionAlgorithm",
|
||||
"rule": "EnumMigrationRule",
|
||||
"ruleArguments": []
|
||||
},
|
||||
{
|
||||
"name": "Password",
|
||||
"type": "string",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": []
|
||||
},
|
||||
{
|
||||
"name": "AccessLevel",
|
||||
"type": "Server.AccessLevel",
|
||||
"rule": "EnumMigrationRule",
|
||||
"ruleArguments": []
|
||||
},
|
||||
{
|
||||
"name": "Flags",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": []
|
||||
},
|
||||
{
|
||||
"name": "Created",
|
||||
"type": "System.DateTime",
|
||||
"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": "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",
|
||||
"ruleArguments": []
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"type": "string",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue