using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Threading.Tasks; using System.Xml.Linq; using JD.MicrosoftAchievement.Service.Extension; using Plume.Interfaces.Services; namespace JD.MicrosoftAchievement.Service { public sealed class MicrosoftAchievementService : IMicrosoftAchievementService { #region IMicrosoftAchievementService public Task ReadAchievementsAsync(string settingsFilePath) => Task.Run(() => { if (settingsFilePath is null) { throw new ArgumentNullException(nameof(settingsFilePath)); } if (!File.Exists(settingsFilePath)) { throw new ArgumentException($"Settings file \"{settingsFilePath}\" does not exists", nameof(settingsFilePath)); } List achievements = new List(); using (ZipArchive archive = ZipFile.OpenRead(settingsFilePath)) { ZipArchiveEntry entry = archive.Entries.FirstOrDefault(e => e.Name == "achievements2017.xml"); if (entry is null) throw new ArgumentException($"Could not find \"achievements2017.xml\" in settings file \"{settingsFilePath}\"", nameof(settingsFilePath)); using (Stream stream = entry.Open()) { XDocument document = XDocument.Load(stream); foreach (XElement element in document.Root.GetElements("Achievement")) { achievements.Add(new Achievement( int.TryParse(element.GetElement("AchievementId")?.Value, out int id) ? id : -1, element.GetElement("AchievementNameId")?.Value, element.GetElement("LockedDescriptionId")?.Value, element.GetElement("UnlockedDescriptionId")?.Value, element.GetElement("IsHidden")?.Value == "true", element.GetElement("BaseAchievement")?.Value == "true", int.TryParse(element.GetElement("Rewards").GetElement("Gamerscore")?.Value, out int gamerscore) ? gamerscore : 0)); } } } return achievements.ToArray(); }); public Task UpdateAchievementsAsync(string settingsFilePath, Achievement[] achievements) => Task.Run(() => { if (settingsFilePath is null) { throw new ArgumentNullException(nameof(settingsFilePath)); } if (achievements is null) { throw new ArgumentNullException(nameof(achievements)); } if (!File.Exists(settingsFilePath)) { throw new ArgumentException($"Settings file \"{settingsFilePath}\" does not exist", nameof(settingsFilePath)); } FileInfo settingsFile = new FileInfo(settingsFilePath); settingsFile.Attributes &= ~FileAttributes.ReadOnly; using (ZipArchive archive = ZipFile.Open(settingsFilePath, ZipArchiveMode.Update)) { ZipArchiveEntry entry = archive.Entries.FirstOrDefault(e => e.FullName == "achievements2017.xml"); if (entry is null) throw new ArgumentException($"Could not find \"achievements2017.xml\" in settings file \"{settingsFilePath}\"", nameof(settingsFilePath)); XDocument document; using (Stream stream = entry.Open()) { document = XDocument.Load(stream); } Dictionary achievementsById = achievements.ToDictionary(a => a.Id); foreach (XElement element in document.Root.GetElements("Achievement")) { if (int.TryParse(element.GetElement("AchievementId")?.Value, out int id) && achievementsById.TryGetValue(id, out Achievement achievement)) { element.UpdateOrAddElement("IsHidden", achievement.IsSecret ? "true" : "false"); element.UpdateOrAddElement("BaseAchievement", achievement.IsBaseAchievement ? "true" : "false"); element.UpdateOrAddElement("Rewards", null).UpdateOrAddElement("Gamerscore", achievement.Gamerscore.ToString()); } } entry.Delete(); using (Stream stream = archive.CreateEntry(entry.Name).Open()) { document.Save(stream); } } }); public Task UpdateLocalizationAsync(string settingsFilePath, LocalizedString[] localizedStrings) => Task.Run(() => { if (settingsFilePath is null) { throw new ArgumentNullException(nameof(settingsFilePath)); } if (localizedStrings is null) { throw new ArgumentNullException(nameof(localizedStrings)); } if (!File.Exists(settingsFilePath)) { throw new ArgumentException($"Settings file \"{settingsFilePath}\" does not exists", nameof(settingsFilePath)); } FileInfo settingsFile = new FileInfo(settingsFilePath); settingsFile.Attributes &= ~FileAttributes.ReadOnly; using (ZipArchive archive = ZipFile.Open(settingsFilePath, ZipArchiveMode.Update)) { ZipArchiveEntry entry = archive.Entries.FirstOrDefault(e => e.FullName == "localization.xml"); if (entry is null) throw new ArgumentException($"Could not find \"localization.xml\" in settings file \"{settingsFilePath}\"", nameof(settingsFilePath)); XDocument document; using (Stream stream = entry.Open()) { document = XDocument.Load(stream); } Dictionary localizedStringsById = localizedStrings.ToDictionary(a => a.Id); foreach (XElement element in document.Root.GetElements("LocalizedString")) { if (localizedStringsById.TryGetValue(element.Attribute("id")?.Value, out LocalizedString localizedString)) { element.RemoveNodes(); foreach (KeyValuePair pair in localizedString.Values) { element.AddElement("Value", pair.Value).SetAttributeValue("locale", pair.Key); } } } entry.Delete(); using (Stream stream = archive.CreateEntry(entry.Name).Open()) { document.Save(stream); } } }); #endregion #region IService public void Initialize(IServiceContext serviceContext) { } #endregion #region IDisposable public void Dispose() { } #endregion } }