D2Multi/D2AccountsXmlStore.cs
2026-03-22 19:54:19 -07:00

145 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
namespace D2Multi
{
[XmlRoot("Accounts")]
public class D2AccountsRoot
{
[XmlElement("Account")]
public List<D2AccountPersisted> AccountList { get; set; } = new List<D2AccountPersisted>();
}
static class D2AccountsXmlStore
{
public static string DefaultPath =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "accounts.xml");
public static List<D2Account> Load(string path)
{
if (!File.Exists(path))
return new List<D2Account>();
using (var stream = File.OpenRead(path))
{
var ser = new XmlSerializer(typeof(D2AccountsRoot));
var root = (D2AccountsRoot)ser.Deserialize(stream);
if (root?.AccountList == null)
return new List<D2Account>();
var result = new List<D2Account>(root.AccountList.Count);
foreach (var p in root.AccountList)
{
var cipher = p?.EncryptedPassword ?? string.Empty;
result.Add(new D2Account
{
Name = p?.Name,
Email = p?.Email,
EncryptedPassword = cipher,
Password = D2AccountCrypto.Unprotect(cipher),
Characters = MapCharactersFromPersisted(p?.Characters),
});
}
return result;
}
}
/// <summary>Builds XML from accounts; encrypts only here from <see cref="D2Account.Password"/> when non-empty.</summary>
public static void Save(string path, IEnumerable<D2Account> accounts)
{
var dir = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(dir))
Directory.CreateDirectory(dir);
var persisted = (accounts ?? Enumerable.Empty<D2Account>())
.Select(ToPersistedForXml)
.ToList();
var root = new D2AccountsRoot { AccountList = persisted };
using (var stream = File.Create(path))
{
var ser = new XmlSerializer(typeof(D2AccountsRoot));
ser.Serialize(stream, root);
}
}
static D2AccountPersisted ToPersistedForXml(D2Account a)
{
string encrypted;
if (!string.IsNullOrEmpty(a?.Password))
encrypted = D2AccountCrypto.Protect(a.Password);
else
encrypted = a?.EncryptedPassword ?? string.Empty;
return new D2AccountPersisted
{
Name = a?.Name,
Email = a?.Email,
EncryptedPassword = encrypted,
Characters = MapCharactersToPersisted(a?.Characters),
};
}
static List<D2Character> MapCharactersFromPersisted(List<D2CharacterPersisted> list)
{
if (list == null || list.Count == 0)
return new List<D2Character>();
var result = new List<D2Character>(list.Count);
foreach (var cp in list)
{
if (cp == null)
continue;
var missions = new List<D2Mission>();
if (cp.Missions != null)
{
foreach (var mp in cp.Missions)
{
if (mp == null)
continue;
missions.Add(new D2Mission
{
Level = mp.Level,
A1_Enpowered = mp.A1_Enpowered,
A5_Socket = mp.A5_Socket,
});
}
}
result.Add(new D2Character { Name = cp.Name, Class = cp.Class, Missions = missions });
}
return result;
}
static List<D2CharacterPersisted> MapCharactersToPersisted(List<D2Character> list)
{
if (list == null || list.Count == 0)
return null;
var result = new List<D2CharacterPersisted>(list.Count);
foreach (var c in list)
{
if (c == null)
continue;
var mpList = new List<D2MissionPersisted>();
if (c.Missions != null)
{
foreach (var m in c.Missions)
{
if (m == null)
continue;
mpList.Add(new D2MissionPersisted
{
Level = m.Level,
A1_Enpowered = m.A1_Enpowered,
A5_Socket = m.A5_Socket,
});
}
}
result.Add(new D2CharacterPersisted { Name = c.Name, Class = c.Class, Missions = mpList });
}
return result.Count == 0 ? null : result;
}
}
}