From ea3c9e4b1482052ba6134813e50acd47cd4195ba Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 5 Aug 2023 11:25:41 +0200 Subject: [PATCH 01/24] Remove topmost window setting --- src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs b/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs index 300cb1fd8..0f5f3371a 100644 --- a/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs +++ b/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs @@ -113,7 +113,6 @@ private void MaximizeWindow() MaxHeight = screen.WorkingArea.Height; Visibility = Visibility.Hidden; - Topmost = true; ResizeMode = ResizeMode.NoResize; Visibility = Visibility.Visible; MaximizedButton.Content = 2; @@ -123,7 +122,6 @@ private void RestoreWindow() { WindowState = WindowState.Normal; _isWindowMaximized = false; - Topmost = false; ResizeMode = ResizeMode.CanResize; MaximizedButton.Content = 1; } From 673f4acd45576a90c8970cc7de98562531b55575 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 5 Aug 2023 11:28:24 +0200 Subject: [PATCH 02/24] Change ResizeMode in RestoreWindow to CanResizeWithGrip --- src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs b/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs index 0f5f3371a..eea9b9034 100644 --- a/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs +++ b/src/StatisticsAnalysisTool/Views/MainWindow.xaml.cs @@ -122,7 +122,7 @@ private void RestoreWindow() { WindowState = WindowState.Normal; _isWindowMaximized = false; - ResizeMode = ResizeMode.CanResize; + ResizeMode = ResizeMode.CanResizeWithGrip; MaximizedButton.Content = 1; } From d710ab05dd606c73d921d873c2eb99f2c76538c3 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sun, 6 Aug 2023 11:08:38 +0200 Subject: [PATCH 03/24] Stats drop down width adjustment --- src/StatisticsAnalysisTool/Views/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StatisticsAnalysisTool/Views/MainWindow.xaml b/src/StatisticsAnalysisTool/Views/MainWindow.xaml index ae6af1bec..72382bd1f 100644 --- a/src/StatisticsAnalysisTool/Views/MainWindow.xaml +++ b/src/StatisticsAnalysisTool/Views/MainWindow.xaml @@ -123,7 +123,7 @@ - From 511ee969deb8e6cdcb532bf27b620b030a02adc7 Mon Sep 17 00:00:00 2001 From: Faeeth <37340968+Faeeth@users.noreply.github.com> Date: Sun, 6 Aug 2023 13:01:41 +0200 Subject: [PATCH 04/24] fr-FR-traduction-file-update --- .../Languages/fr-FR.xml | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/StatisticsAnalysisTool/Languages/fr-FR.xml b/src/StatisticsAnalysisTool/Languages/fr-FR.xml index e775a025c..9d271e415 100644 --- a/src/StatisticsAnalysisTool/Languages/fr-FR.xml +++ b/src/StatisticsAnalysisTool/Languages/fr-FR.xml @@ -330,7 +330,7 @@ Vous avez Renommée gagné(e). - Réinitialisation pour chaque carte + Réinitialisation à chaque nouvelle carte Renommée totale Argent total Total Re-Spécialisation @@ -373,13 +373,13 @@ Trier par DPS Trier par nom Trier par soins - Trier par soin par secondes + Trier par soin par seconde Points de Réputation de Faction Points de Faction Nombre d'étages Répertoire du programme Ouvrir le répertoire du programme - Ouvrir ou fermer la console de débogage + Ouvrir la console de débogage Créer un raccourci sur le bureau Favori Autel d'argent @@ -444,7 +444,7 @@ Afin de pouvoir mettre à jour vous-même les prix d'un objet, vous devez installer Albion Online Data Project: Points de saison Exporter le butin vers un fichier - Suivre le butin de groupe uniquement + Traquer le butin de groupe uniquement Réinitialiser le minuteur du donjon Ressources requises Prix de vente par objet @@ -480,12 +480,12 @@ Le rappel de sauvegarde de traqueur de butin est-il actif ? Enregistrer le butin maintenant ? Enregistrer le butin - Traqueur d'argent - Traqueur de renommée + Traquer l'argent + Traquer la renommée Recherche d'objet Donjons Information du joueur - Traqueur + Traqueur de butin Le Traqueur est actif Le Traqueur est partiellement actif Le Traqueur n'est pas actif @@ -495,7 +495,7 @@ Faveur Frais d'utilisation par 100 nourriture Montrer le butin sur les monstres - Suivre le butin sur les monstres + Traquer le butin sur les monstres URL Source de Items.json Intervalle de MAJ de items.json en jours : Catégorie @@ -505,7 +505,7 @@ Essayez de télécharger item.json à nouveau Item.json ne peut pas être chargé. Suggérer des mises à jour en pré-version - ATTENTION! Ces versions sont encore en cours de test + ATTENTION! Ces versions sont encore en cours de test Donjon respé Donjon argent Donjon renommée par heure @@ -606,7 +606,7 @@ Coffres pillés Donjons statiques Routes avaloniennes - Portes de l'enfer + Portes de l'enfer (HellGates) Monde ouvert Les 7 derniers jours Les 30 derniers jours @@ -660,7 +660,7 @@ Joueur local Merci Merci - Jouer un son lors de la fermeture du donjon + Jouer un son à la fermeture du donjon Prix total avec taxes déduites Mettre à jour mobs.json : URL source mobs.json @@ -678,7 +678,7 @@ Supprimer après 365 jours Supprimer les transactions sélectionnées Voulez-vous vraiment supprimer les transactions sélectionnées ? - Surveillance des transactions + Supervision des transactions Transactions Afin de reconnaître les nouvelles transactions, chaque message doit être ouvert dans la boîte de réception dans le jeu. Transaction inconnue @@ -744,7 +744,7 @@ Supprimer après 30 jours Supprimer après 365 jours Sélection du joueur avec le même nom dans la base de donnée - Mettre à jour maintenant + Mettre à jour Si les bonnes armes ne sont pas affichées dans le Damage Meter, cela est généralement dû aux fichiers ItemList.json et Items.json obsolètes. Supprimez manuellement les fichiers du dossier du logiciel et redémarrez le, la dernière version des fichiers sera téléchargée et tout devrait fonctionner. Obtenir world.json world.json ne peut pas être chargé. @@ -777,4 +777,8 @@ Fenêtre de l'objet Enregistreur de butin Outils + Impossible de démarrer l'application avec le chemin : {path} + Ouvrir une autre application au démarrage + Impossible de démarrer une autre application + Canne à pêche \ No newline at end of file From c853f2e3dabc245938b07bb54f1207d4c02e4a18 Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 8 Aug 2023 16:23:57 +0200 Subject: [PATCH 05/24] Added extractor nedded classes --- .../BaseExtractor.cs | 102 +++++++++++++ .../BinaryDecrypter.cs | 64 ++++++++ .../Enums/ServerType.cs | 8 + .../Extractor.cs | 30 ++++ .../IdContainer.cs | 7 + .../ItemContainer.cs | 9 ++ .../ItemExtractor.cs | 141 ++++++++++++++++++ .../StatisticAnalysisTool.Extractor.csproj | 13 ++ .../Utilities/LocalizationData.cs | 80 ++++++++++ src/StatisticsAnalysisTool.sln | 15 +- .../StatisticsAnalysisTool.csproj | 1 + .../ViewModels/MainWindowViewModel.cs | 7 + 12 files changed, 476 insertions(+), 1 deletion(-) create mode 100644 src/StatisticAnalysisTool.Extractor/BaseExtractor.cs create mode 100644 src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs create mode 100644 src/StatisticAnalysisTool.Extractor/Enums/ServerType.cs create mode 100644 src/StatisticAnalysisTool.Extractor/Extractor.cs create mode 100644 src/StatisticAnalysisTool.Extractor/IdContainer.cs create mode 100644 src/StatisticAnalysisTool.Extractor/ItemContainer.cs create mode 100644 src/StatisticAnalysisTool.Extractor/ItemExtractor.cs create mode 100644 src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj create mode 100644 src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs diff --git a/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs b/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs new file mode 100644 index 000000000..c501acffc --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs @@ -0,0 +1,102 @@ +using StatisticAnalysisTool.Extractor.Utilities; +using System.Text; +using System.Text.Json; +using System.Xml; + +namespace StatisticAnalysisTool.Extractor; + +public abstract class BaseExtractor +{ + protected readonly string OutputFolderPath; + protected readonly string MainGameFolder; + + protected BaseExtractor(string mainGameFolder, string outputFolderPath) + { + OutputFolderPath = outputFolderPath; + MainGameFolder = mainGameFolder; + } + + protected abstract string GetBinFilePath(); + protected abstract void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData = default); + + protected static XmlElement? FindElement(XmlNode node, string elementName) + { + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode is XmlElement ele && ele.Name == elementName) + { + return ele; + } + } + + return null; + } + + public void Extract(LocalizationData localizationData = default) + { + var xmlPath = DecryptBinFile(GetBinFilePath(), OutputFolderPath); + Console.WriteLine("Attribute of the File " + OutputFolderPath); + try + { + using var inputFile = File.OpenRead(xmlPath); + var stream = GetExportStream(); + + ExtractFromXml(inputFile, stream, WriteItem, localizationData); + + CloseExportStream(stream); + stream.Close(); + } + catch + { + throw new ArgumentException(); + } + } + + public static string DecryptBinFile(string binFile, string outputFolderPath) + { + var finalOutPath = Path.ChangeExtension(Path.Combine(outputFolderPath, binFile[(binFile.LastIndexOf("GameData\\", StringComparison.Ordinal) + 9)..]), ".xml"); + Directory.CreateDirectory(Path.GetDirectoryName(finalOutPath) ?? string.Empty); + + using var outputStream = File.Create(finalOutPath); + BinaryDecrypter.DecryptBinaryFile(binFile, outputStream); + return finalOutPath; + } + + private Stream GetExportStream() + { + var filePathWithoutExtension = Path.Combine(OutputFolderPath, "formatted", Path.GetFileNameWithoutExtension(GetBinFilePath())); + if (!Directory.Exists(Path.GetDirectoryName(filePathWithoutExtension))) + { + Directory.CreateDirectory(Path.GetDirectoryName(filePathWithoutExtension) ?? string.Empty); + } + + var stream = File.Create(filePathWithoutExtension + ".json"); + WriteString(stream, "[" + Environment.NewLine); + return stream; + } + + private static void CloseExportStream(Stream stream) + { + WriteString(stream, Environment.NewLine + "]"); + } + + private static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) + { + var output = new StringBuilder(); + + if (!first) + { + output.AppendLine(","); + } + output.Append(JsonSerializer.Serialize(idContainer, new JsonSerializerOptions { WriteIndented = true })); + + WriteString(stream, output.ToString()); + output.Clear(); + } + + private static void WriteString(Stream stream, string val) + { + var buffer = Encoding.UTF8.GetBytes(val); + stream.Write(buffer, 0, buffer.Length); + } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs b/src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs new file mode 100644 index 000000000..3f2991994 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs @@ -0,0 +1,64 @@ +using System.IO.Compression; +using System.Security.Cryptography; + +namespace StatisticAnalysisTool.Extractor; + +public static class BinaryDecrypter +{ + private static readonly byte[] Key = { 48, 239, 114, 71, 66, 242, 4, 50 }; + private static readonly byte[] Iv = { 14, 166, 220, 137, 219, 237, 220, 79 }; + + public static void DecryptBinaryFile(string inputPath, Stream outputStream) + { + using var inputFile = File.OpenRead(inputPath); + var fileBuffer = new byte[inputFile.Length]; + int _ = inputFile.Read(fileBuffer, 0, fileBuffer.Length); + + var tDes = new DESCryptoServiceProvider + { + IV = Iv, + Mode = CipherMode.CBC, + Key = Key + }; + var outBuffer = tDes.CreateDecryptor().TransformFinalBlock(fileBuffer, 0, fileBuffer.Length); + + const int size = 4096; + var buffer = new byte[size]; + int bytesRead; + + using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress); + while ((bytesRead = decompression.Read(buffer, 0, buffer.Length)) > 0) + { + outputStream.Write(buffer, 0, bytesRead); + } + } + + public static byte[] DecryptAndDecompress(string inputPath) + { + using var inputFile = File.OpenRead(inputPath); + var fileBuffer = new byte[inputFile.Length]; + int bytesRead = inputFile.Read(fileBuffer, 0, fileBuffer.Length); + + var tDes = new DESCryptoServiceProvider + { + IV = Iv, + Mode = CipherMode.CBC, + Key = Key + }; + var outBuffer = tDes.CreateDecryptor().TransformFinalBlock(fileBuffer, 0, bytesRead); + + const int size = 4096; + var buffer = new byte[size]; + int decompressedBytesRead; + + using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress); + using MemoryStream outputMemoryStream = new MemoryStream(); + + while ((decompressedBytesRead = decompression.Read(buffer, 0, buffer.Length)) > 0) + { + outputMemoryStream.Write(buffer, 0, decompressedBytesRead); + } + + return outputMemoryStream.ToArray(); + } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/Enums/ServerType.cs b/src/StatisticAnalysisTool.Extractor/Enums/ServerType.cs new file mode 100644 index 000000000..0244c4318 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/Enums/ServerType.cs @@ -0,0 +1,8 @@ +namespace StatisticAnalysisTool.Extractor.Enums; + +public enum ServerType +{ + Live, + Staging, + Playground +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/Extractor.cs b/src/StatisticAnalysisTool.Extractor/Extractor.cs new file mode 100644 index 000000000..3829b9387 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/Extractor.cs @@ -0,0 +1,30 @@ +using StatisticAnalysisTool.Extractor.Enums; +using StatisticAnalysisTool.Extractor.Utilities; + +namespace StatisticAnalysisTool.Extractor; + +public class Extractor +{ + public void ExtractGameData(string mainGameFolder, ServerType serverType, string outputDirPath) + { + string mainGameFolderString = Path.Combine(mainGameFolder, GetServerTypeString(serverType)); + mainGameFolderString = mainGameFolderString.Replace("'", ""); + + using var localizationData = new LocalizationData(mainGameFolderString); + + ExtractItems(mainGameFolderString, localizationData, outputDirPath); + // TODO ... + } + + private static string GetServerTypeString(ServerType serverType) + { + string serverTypeString = serverType switch + { + ServerType.Staging => "staging", + ServerType.Playground => "playground", + _ => "game" + }; + + return serverTypeString; + } +} diff --git a/src/StatisticAnalysisTool.Extractor/IdContainer.cs b/src/StatisticAnalysisTool.Extractor/IdContainer.cs new file mode 100644 index 000000000..6879fb74c --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/IdContainer.cs @@ -0,0 +1,7 @@ +namespace StatisticAnalysisTool.Extractor; + +public class IdContainer +{ + public string Index { get; set; } + public string UniqueName { get; set; } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/ItemContainer.cs b/src/StatisticAnalysisTool.Extractor/ItemContainer.cs new file mode 100644 index 000000000..265f2e63f --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/ItemContainer.cs @@ -0,0 +1,9 @@ +namespace StatisticAnalysisTool.Extractor; + +public class ItemContainer : IdContainer +{ + public string LocalizationNameVariable { get; set; } + public string LocalizationDescriptionVariable { get; set; } + public Dictionary LocalizedNames { get; set; } + public Dictionary LocalizedDescriptions { get; set; } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs b/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs new file mode 100644 index 000000000..5f4f867d2 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs @@ -0,0 +1,141 @@ +using StatisticAnalysisTool.Extractor.Enums; +using StatisticAnalysisTool.Extractor.Utilities; +using System.Xml; + +namespace StatisticAnalysisTool.Extractor; + +public class ItemExtractor : BaseExtractor +{ + public ItemExtractor(string mainGameFolder, string outputFolderPath) : base(mainGameFolder, outputFolderPath) + { + } + + protected override void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData = default) + { + var journals = new List(); + var xmlDoc = new XmlDocument(); + xmlDoc.Load(inputXmlFile); + + var rootNode = xmlDoc.LastChild; + + var index = 1; + var first = true; + foreach (XmlNode node in rootNode?.ChildNodes) + { + if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) + { + continue; + } + + var uniqueName = node.Attributes["uniquename"]?.Value; + var enchantmentLevel = node.Attributes["enchantmentlevel"]; + var description = node.Attributes["descriptionlocatag"]; + var name = node.Attributes["descvariable0"]; + var enchantment = ""; + if (enchantmentLevel != null && enchantmentLevel.Value != "0") + { + enchantment = "@" + enchantmentLevel.Value; + } + var localizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName; + if (uniqueName != null && uniqueName.Contains("ARTEFACT")) + { + localizationNameVariable = LocalizationData.ItemPrefix + uniqueName; + } + var container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = uniqueName + enchantment, + LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = localizationNameVariable + }; + SetLocalization(localizationData, container); + writeItem(outputStream, container, first); + if (first) + { + first = false; + } + index++; + + if (node.Name == "journalitem") + { + journals.Add(new ItemContainer() + { + UniqueName = uniqueName + }); + } + + var element = FindElement(node, "enchantments"); + if (element == null) + { + continue; + } + + foreach (XmlElement childNode in element.ChildNodes) + { + var enchantmentName = node.Attributes["uniquename"]?.Value + "@" + childNode.Attributes["enchantmentlevel"]?.Value; + container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = enchantmentName, + LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName + }; + SetLocalization(localizationData, container); + writeItem(outputStream, container, false); + + index++; + } + } + + foreach (var idContainer in journals) + { + var itemContainer = (ItemContainer)idContainer; + var container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = itemContainer.UniqueName + "_EMPTY", + LocalizationDescriptionVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_EMPTY" + LocalizationData.DescPostfix, + LocalizationNameVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_EMPTY" + }; + + SetLocalization(localizationData, container); + writeItem(outputStream, container, false); + index++; + + container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = itemContainer.UniqueName + "_FULL", + LocalizationDescriptionVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_FULL" + LocalizationData.DescPostfix, + LocalizationNameVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_FULL" + }; + + SetLocalization(localizationData, container); + writeItem(outputStream, container, false); + index++; + } + } + + private void SetLocalization(LocalizationData data, ItemContainer item) + { + if (data == default) + { + return; + } + + if (data.LocalizedDescriptions.TryGetValue(item.LocalizationDescriptionVariable, out var descriptions)) + { + item.LocalizedDescriptions = descriptions; + } + + if (data.LocalizedNames.TryGetValue(item.LocalizationNameVariable, out var names)) + { + item.LocalizedNames = names; + } + } + + protected override string GetBinFilePath() + { + return Path.Combine(MainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\items.bin"); + } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj b/src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj new file mode 100644 index 000000000..b5ffb5976 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs b/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs new file mode 100644 index 000000000..2dc5b4242 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs @@ -0,0 +1,80 @@ +using System.Text; +using System.Xml; + +namespace StatisticAnalysisTool.Extractor.Utilities; + +public class LocalizationData : IDisposable +{ + public const string ItemPrefix = "@ITEMS_"; + public const string DescPostfix = "_DESC"; + + public Dictionary> LocalizedNames = new(); + public Dictionary> LocalizedDescriptions = new(); + + public LocalizationData(string mainGameFolder) + { + var localizationBinFilePath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\localization.bin"); + var localizationDataByteArray = BinaryDecrypter.DecryptAndDecompress(localizationBinFilePath); + + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(Encoding.UTF8.GetString(localizationDataByteArray)); + + var rootNode = xmlDoc.LastChild?.LastChild?.ChildNodes; + + if (rootNode is null) + { + return; + } + + foreach (XmlNode node in rootNode) + { + if (node.NodeType != XmlNodeType.Element) + { + continue; + } + + var tuId = node.Attributes?["tuid"]; + + if (tuId?.Value.StartsWith(ItemPrefix) != true) + { + continue; + } + + Dictionary languages; + + try + { + languages = node.ChildNodes + .Cast() + .ToDictionary(x => x.Attributes!["xml:lang"]!.Value, y => y.LastChild!.InnerText); + } + catch (Exception) + { + continue; + } + + // Is item description + if (tuId.Value.EndsWith(DescPostfix)) + { + LocalizedDescriptions[tuId.Value] = languages; + } + // Is item name + else + { + LocalizedNames[tuId.Value] = languages; + } + } + } + + public void Dispose() + { + LocalizedNames.Clear(); + LocalizedDescriptions.Clear(); + GC.SuppressFinalize(this); + } + + ~LocalizationData() + { + Dispose(); + } +} \ No newline at end of file diff --git a/src/StatisticsAnalysisTool.sln b/src/StatisticsAnalysisTool.sln index d6477ea0a..b76b8efc3 100644 --- a/src/StatisticsAnalysisTool.sln +++ b/src/StatisticsAnalysisTool.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32929.385 @@ -14,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatisticsAnalysisTool.Network", "StatisticsAnalysisTool.Network\StatisticsAnalysisTool.Network.csproj", "{3EFADBA6-CBC5-479F-900B-369353AA04BB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatisticAnalysisTool.Extractor", "StatisticAnalysisTool.Extractor\StatisticAnalysisTool.Extractor.csproj", "{BB6567DA-B6A1-468F-8D16-B93272C7E061}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -60,6 +61,18 @@ Global {3EFADBA6-CBC5-479F-900B-369353AA04BB}.Release|x64.Build.0 = Release|Any CPU {3EFADBA6-CBC5-479F-900B-369353AA04BB}.Release|x86.ActiveCfg = Release|Any CPU {3EFADBA6-CBC5-479F-900B-369353AA04BB}.Release|x86.Build.0 = Release|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Debug|x64.ActiveCfg = Debug|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Debug|x64.Build.0 = Debug|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Debug|x86.ActiveCfg = Debug|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Debug|x86.Build.0 = Debug|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Release|Any CPU.Build.0 = Release|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Release|x64.ActiveCfg = Release|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Release|x64.Build.0 = Release|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Release|x86.ActiveCfg = Release|Any CPU + {BB6567DA-B6A1-468F-8D16-B93272C7E061}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj b/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj index a0f34e55f..438f7b169 100644 --- a/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj +++ b/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj @@ -668,6 +668,7 @@ + diff --git a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs index 80c658232..28ed111b0 100644 --- a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs +++ b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs @@ -3,6 +3,7 @@ using LiveChartsCore.SkiaSharpView; using log4net; using Microsoft.Win32; +using StatisticAnalysisTool.Extractor; using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; @@ -31,6 +32,7 @@ using System.Windows; using System.Windows.Data; using System.Windows.Media; +using StatisticAnalysisTool.Extractor.Enums; // ReSharper disable UnusedMember.Global @@ -130,6 +132,11 @@ public MainWindowViewModel() UpgradeSettings(); SetUiElements(); Translation = new MainWindowTranslation(); + + + // TEST + var extractor = new Extractor(); + extractor.ExtractGameData("F:\\AlbionOnline", ServerType.Live, "C:\\Users\\schul\\Desktop\\test"); } public void SetUiElements() From ad20515ae53e1418164d0016c5e95b0c21454af4 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 9 Aug 2023 12:18:06 +0200 Subject: [PATCH 06/24] Items with translations and index can now serialized --- .../BaseExtractor.cs | 11 +- .../BinaryDumper.cs | 66 +++++ .../Extractor.cs | 2 +- .../ItemExtractor.cs | 130 +++++----- .../Utilities/ItemData.cs | 226 ++++++++++++++++++ 5 files changed, 367 insertions(+), 68 deletions(-) create mode 100644 src/StatisticAnalysisTool.Extractor/BinaryDumper.cs create mode 100644 src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs diff --git a/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs b/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs index c501acffc..8c48c77db 100644 --- a/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs +++ b/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs @@ -1,4 +1,5 @@ -using StatisticAnalysisTool.Extractor.Utilities; +using System.Diagnostics; +using StatisticAnalysisTool.Extractor.Utilities; using System.Text; using System.Text.Json; using System.Xml; @@ -17,7 +18,7 @@ protected BaseExtractor(string mainGameFolder, string outputFolderPath) } protected abstract string GetBinFilePath(); - protected abstract void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData = default); + protected abstract void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData); protected static XmlElement? FindElement(XmlNode node, string elementName) { @@ -35,7 +36,7 @@ protected BaseExtractor(string mainGameFolder, string outputFolderPath) public void Extract(LocalizationData localizationData = default) { var xmlPath = DecryptBinFile(GetBinFilePath(), OutputFolderPath); - Console.WriteLine("Attribute of the File " + OutputFolderPath); + Debug.Print("Attribute of the File " + OutputFolderPath); try { using var inputFile = File.OpenRead(xmlPath); @@ -80,7 +81,7 @@ private static void CloseExportStream(Stream stream) WriteString(stream, Environment.NewLine + "]"); } - private static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) + protected static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) { var output = new StringBuilder(); @@ -94,7 +95,7 @@ private static void WriteItem(Stream stream, IdContainer idContainer, bool first output.Clear(); } - private static void WriteString(Stream stream, string val) + protected static void WriteString(Stream stream, string val) { var buffer = Encoding.UTF8.GetBytes(val); stream.Write(buffer, 0, buffer.Length); diff --git a/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs b/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs new file mode 100644 index 000000000..ab8e0bee5 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs @@ -0,0 +1,66 @@ +using System.Text.Json; +using System.Xml; + +namespace StatisticAnalysisTool.Extractor; + +public class BinaryDumper +{ + public void Extract(string mainGameFolder, string outputFolderPath) + { + var allFiles = Directory.GetFiles(GetBinFilePath(mainGameFolder), "*.bin", SearchOption.AllDirectories); + var outFiles = (string[]) allFiles.Clone(); + for (var i = 0; i < outFiles.Length; i++) + { + outFiles[i] = outFiles[i].Remove(0, outFiles[i].LastIndexOf("GameData\\", StringComparison.Ordinal) + "GameData\\".Length); + } + + for (var i = 0; i < allFiles.Length; i++) + { + DecryptBinFile(outputFolderPath, allFiles[i], outFiles[i]); + } + } + + private string GetBinFilePath(string mainGameFolder) + { + return Path.Combine(mainGameFolder, @".\Albion-Online_Data\StreamingAssets\GameData"); + } + + private string DecryptBinFile(string outputFolderPath, string binFile, string subdir) + { + var binFileWOE = Path.GetFileNameWithoutExtension(binFile); + + // Skip profanity as it has no value for us + if (binFileWOE.StartsWith("profanity", StringComparison.OrdinalIgnoreCase)) + { + return ""; + } + + var outSubdirs = Path.GetDirectoryName(Path.Combine(outputFolderPath, subdir)); + + if (outSubdirs != "") + Directory.CreateDirectory(outSubdirs); + var finalOutPath = Path.Combine(outSubdirs, binFileWOE); + var finalXmlPath = finalOutPath + ".xml"; + var finalJsonPath = finalOutPath + ".json"; + Console.Out.WriteLine("Extracting " + binFileWOE + ".bin... to:" + finalOutPath + ".xml"); + + using (var outputXmlFile = File.Create(finalXmlPath)) + { + BinaryDecrypter.DecryptBinaryFile(binFile, outputXmlFile); + } + + if (string.Equals("world", binFileWOE, StringComparison.OrdinalIgnoreCase) || (!subdir.StartsWith("cluster") && !subdir.StartsWith("templates"))) + { + var xmlDocument = new XmlDocument(); + var xmlReaderSettings = new XmlReaderSettings + { + IgnoreComments = true + }; + var xmlReader = XmlReader.Create(finalXmlPath, xmlReaderSettings); + xmlDocument.Load(xmlReader); + File.WriteAllText(finalJsonPath, JsonSerializer.Serialize(xmlDocument, new JsonSerializerOptions { WriteIndented = true })); + } + + return finalOutPath; + } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/Extractor.cs b/src/StatisticAnalysisTool.Extractor/Extractor.cs index 3829b9387..28c504525 100644 --- a/src/StatisticAnalysisTool.Extractor/Extractor.cs +++ b/src/StatisticAnalysisTool.Extractor/Extractor.cs @@ -12,7 +12,7 @@ public void ExtractGameData(string mainGameFolder, ServerType serverType, string using var localizationData = new LocalizationData(mainGameFolderString); - ExtractItems(mainGameFolderString, localizationData, outputDirPath); + ItemData.CreateItemData(mainGameFolderString, localizationData, outputDirPath); // TODO ... } diff --git a/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs b/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs index 5f4f867d2..5139a7f11 100644 --- a/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs +++ b/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs @@ -1,5 +1,4 @@ -using StatisticAnalysisTool.Extractor.Enums; -using StatisticAnalysisTool.Extractor.Utilities; +using StatisticAnalysisTool.Extractor.Utilities; using System.Xml; namespace StatisticAnalysisTool.Extractor; @@ -10,7 +9,7 @@ public ItemExtractor(string mainGameFolder, string outputFolderPath) : base(main { } - protected override void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData = default) + protected override void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData) { var journals = new List(); var xmlDoc = new XmlDocument(); @@ -20,76 +19,88 @@ protected override void ExtractFromXml(Stream inputXmlFile, Stream outputStream, var index = 1; var first = true; - foreach (XmlNode node in rootNode?.ChildNodes) - { - if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) - { - continue; - } - - var uniqueName = node.Attributes["uniquename"]?.Value; - var enchantmentLevel = node.Attributes["enchantmentlevel"]; - var description = node.Attributes["descriptionlocatag"]; - var name = node.Attributes["descvariable0"]; - var enchantment = ""; - if (enchantmentLevel != null && enchantmentLevel.Value != "0") - { - enchantment = "@" + enchantmentLevel.Value; - } - var localizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName; - if (uniqueName != null && uniqueName.Contains("ARTEFACT")) - { - localizationNameVariable = LocalizationData.ItemPrefix + uniqueName; - } - var container = new ItemContainer() - { - Index = index.ToString(), - UniqueName = uniqueName + enchantment, - LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, - LocalizationNameVariable = localizationNameVariable - }; - SetLocalization(localizationData, container); - writeItem(outputStream, container, first); - if (first) - { - first = false; - } - index++; - if (node.Name == "journalitem") + if (rootNode?.ChildNodes != null) + { + foreach (XmlNode node in rootNode.ChildNodes) { - journals.Add(new ItemContainer() + if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) { - UniqueName = uniqueName - }); - } + continue; + } + + var uniqueName = node.Attributes["uniquename"]?.Value; + var enchantmentLevel = node.Attributes["enchantmentlevel"]; + var description = node.Attributes["descriptionlocatag"]; + var name = node.Attributes["descvariable0"]; + var enchantment = ""; + if (enchantmentLevel != null && enchantmentLevel.Value != "0") + { + enchantment = "@" + enchantmentLevel.Value; + } - var element = FindElement(node, "enchantments"); - if (element == null) - { - continue; - } + var localizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName; + if (uniqueName != null && uniqueName.Contains("ARTEFACT")) + { + localizationNameVariable = LocalizationData.ItemPrefix + uniqueName; + } - foreach (XmlElement childNode in element.ChildNodes) - { - var enchantmentName = node.Attributes["uniquename"]?.Value + "@" + childNode.Attributes["enchantmentlevel"]?.Value; - container = new ItemContainer() + var container = new ItemContainer() { Index = index.ToString(), - UniqueName = enchantmentName, - LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, - LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName + UniqueName = uniqueName + enchantment, + LocalizationDescriptionVariable = description != null + ? description.Value + : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = localizationNameVariable }; SetLocalization(localizationData, container); - writeItem(outputStream, container, false); + writeItem(outputStream, container, first); + if (first) + { + first = false; + } index++; + + if (node.Name == "journalitem") + { + journals.Add(new ItemContainer() + { + UniqueName = uniqueName ?? string.Empty + }); + } + + var element = FindElement(node, "enchantments"); + if (element == null) + { + continue; + } + + foreach (XmlElement childNode in element.ChildNodes) + { + var enchantmentName = node.Attributes["uniquename"]?.Value + "@" + + childNode.Attributes["enchantmentlevel"]?.Value; + container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = enchantmentName, + LocalizationDescriptionVariable = description != null + ? description.Value + : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName + }; + SetLocalization(localizationData, container); + writeItem(outputStream, container, false); + + index++; + } } } foreach (var idContainer in journals) { - var itemContainer = (ItemContainer)idContainer; + var itemContainer = (ItemContainer) idContainer; var container = new ItemContainer() { Index = index.ToString(), @@ -118,11 +129,6 @@ protected override void ExtractFromXml(Stream inputXmlFile, Stream outputStream, private void SetLocalization(LocalizationData data, ItemContainer item) { - if (data == default) - { - return; - } - if (data.LocalizedDescriptions.TryGetValue(item.LocalizationDescriptionVariable, out var descriptions)) { item.LocalizedDescriptions = descriptions; diff --git a/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs b/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs new file mode 100644 index 000000000..9431540d4 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs @@ -0,0 +1,226 @@ +using System.Text; +using System.Text.Json; +using System.Xml; + +namespace StatisticAnalysisTool.Extractor.Utilities; + +public class ItemData : IDisposable +{ + public static void CreateItemData(string mainGameFolder, LocalizationData localizationData, string outputFolderPath, string outputFileNameWithExtension = "items.json") + { + var itemBinPath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\items.bin"); + var itemDataByteArray = BinaryDecrypter.DecryptAndDecompress(itemBinPath); + + ExtractFromByteArray(itemDataByteArray, GetExportStream(outputFolderPath, outputFileNameWithExtension), localizationData); + } + + private static Stream GetExportStream(string outputFolderPath, string outputFileNameWithExtension) + { + var stream = File.Create(Path.Combine(outputFolderPath, outputFileNameWithExtension)); + WriteString(stream, "[" + Environment.NewLine); + return stream; + } + + private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream outputStream, LocalizationData localizationData) + { + var journals = new List(); + + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(RemoveNonPrintableCharacters(Encoding.UTF8.GetString(RemoveBom(itemDataByteArray)))); + + var rootNode = xmlDoc.LastChild; + + var index = 1; + var first = true; + foreach (XmlNode node in rootNode?.ChildNodes) + { + if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) + { + continue; + } + + var uniqueName = node.Attributes["uniquename"]?.Value; + var enchantmentLevel = node.Attributes["enchantmentlevel"]; + var description = node.Attributes["descriptionlocatag"]; + var name = node.Attributes["descvariable0"]; + var enchantment = ""; + if (enchantmentLevel != null && enchantmentLevel.Value != "0") + { + enchantment = "@" + enchantmentLevel.Value; + } + var localizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName; + if (uniqueName != null && uniqueName.Contains("ARTEFACT")) + { + localizationNameVariable = LocalizationData.ItemPrefix + uniqueName; + } + var container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = uniqueName + enchantment, + LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = localizationNameVariable + }; + + SetLocalization(localizationData, container); + WriteItem(outputStream, container, first); + if (first) + { + first = false; + } + index++; + + if (node.Name == "journalitem") + { + journals.Add(new ItemContainer() + { + UniqueName = uniqueName + }); + } + + var element = FindElement(node, "enchantments"); + if (element == null) + { + continue; + } + + foreach (XmlElement childNode in element.ChildNodes) + { + var enchantmentName = node.Attributes["uniquename"]?.Value + "@" + childNode.Attributes["enchantmentlevel"]?.Value; + container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = enchantmentName, + LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName + }; + SetLocalization(localizationData, container); + WriteItem(outputStream, container); + + index++; + } + } + + foreach (var idContainer in journals) + { + var itemContainer = (ItemContainer) idContainer; + var container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = itemContainer.UniqueName + "_EMPTY", + LocalizationDescriptionVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_EMPTY" + LocalizationData.DescPostfix, + LocalizationNameVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_EMPTY" + }; + + SetLocalization(localizationData, container); + WriteItem(outputStream, container); + index++; + + container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = itemContainer.UniqueName + "_FULL", + LocalizationDescriptionVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_FULL" + LocalizationData.DescPostfix, + LocalizationNameVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_FULL" + }; + + SetLocalization(localizationData, container); + WriteItem(outputStream, container); + index++; + } + + WriteString(outputStream, Environment.NewLine + "]"); + outputStream.Close(); + } + + private static void SetLocalization(LocalizationData data, ItemContainer item) + { + if (data == default) + { + return; + } + + if (data.LocalizedDescriptions.TryGetValue(item.LocalizationDescriptionVariable, out var descriptions)) + { + item.LocalizedDescriptions = descriptions; + } + + if (data.LocalizedNames.TryGetValue(item.LocalizationNameVariable, out var names)) + { + item.LocalizedNames = names; + } + } + + private static XmlElement? FindElement(XmlNode node, string elementName) + { + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode is XmlElement ele && ele.Name == elementName) + { + return ele; + } + } + + return null; + } + + private static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) + { + var output = new StringBuilder(); + + if (!first) + { + output.AppendLine(","); + } + + var options = new JsonSerializerOptions + { + WriteIndented = true, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + if (idContainer is ItemContainer itemContainer) + { + output.Append(JsonSerializer.Serialize(itemContainer, options)); + } + else + { + output.Append(JsonSerializer.Serialize(idContainer, options)); + } + + WriteString(stream, output.ToString()); + output.Clear(); + } + + private static void WriteString(Stream stream, string val) + { + var buffer = Encoding.UTF8.GetBytes(val); + stream.Write(buffer, 0, buffer.Length); + } + + private static string RemoveNonPrintableCharacters(string input) + { + return new string(input.Where(c => !char.IsControl(c) || char.IsWhiteSpace(c)).ToArray()); + } + + private static byte[] RemoveBom(byte[] byteArray) + { + byte[] utf8Bom = { 0xEF, 0xBB, 0xBF }; + + if (byteArray.Length >= utf8Bom.Length && byteArray[0] == utf8Bom[0] && byteArray[1] == utf8Bom[1] && byteArray[2] == utf8Bom[2]) + { + return byteArray.Skip(utf8Bom.Length).ToArray(); + } + + return byteArray; + } + + public void Dispose() + { + GC.SuppressFinalize(this); + } + + ~ItemData() + { + Dispose(); + } +} \ No newline at end of file From 0c744b4d2c9c779af631793a84fde3d1ba9930f2 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 9 Aug 2023 15:36:42 +0200 Subject: [PATCH 07/24] Make methods async --- .../Extractor.cs | 7 +- .../ItemContainer.cs | 8 +- .../Utilities/ItemData.cs | 131 +++++++++--------- .../Utilities/LocalizationData.cs | 27 ++-- .../ViewModels/MainWindowViewModel.cs | 3 +- 5 files changed, 94 insertions(+), 82 deletions(-) diff --git a/src/StatisticAnalysisTool.Extractor/Extractor.cs b/src/StatisticAnalysisTool.Extractor/Extractor.cs index 28c504525..d10d7ade1 100644 --- a/src/StatisticAnalysisTool.Extractor/Extractor.cs +++ b/src/StatisticAnalysisTool.Extractor/Extractor.cs @@ -5,14 +5,15 @@ namespace StatisticAnalysisTool.Extractor; public class Extractor { - public void ExtractGameData(string mainGameFolder, ServerType serverType, string outputDirPath) + public static async Task ExtractGameDataAsync(string mainGameFolder, ServerType serverType, string outputDirPath) { string mainGameFolderString = Path.Combine(mainGameFolder, GetServerTypeString(serverType)); mainGameFolderString = mainGameFolderString.Replace("'", ""); - using var localizationData = new LocalizationData(mainGameFolderString); + using var localizationData = new LocalizationData(); + await localizationData.LoadDataAsync(mainGameFolderString); - ItemData.CreateItemData(mainGameFolderString, localizationData, outputDirPath); + await ItemData.CreateItemDataAsync(mainGameFolderString, localizationData, outputDirPath); // TODO ... } diff --git a/src/StatisticAnalysisTool.Extractor/ItemContainer.cs b/src/StatisticAnalysisTool.Extractor/ItemContainer.cs index 265f2e63f..c849a2d40 100644 --- a/src/StatisticAnalysisTool.Extractor/ItemContainer.cs +++ b/src/StatisticAnalysisTool.Extractor/ItemContainer.cs @@ -1,9 +1,11 @@ -namespace StatisticAnalysisTool.Extractor; +using System.Collections.Concurrent; + +namespace StatisticAnalysisTool.Extractor; public class ItemContainer : IdContainer { public string LocalizationNameVariable { get; set; } public string LocalizationDescriptionVariable { get; set; } - public Dictionary LocalizedNames { get; set; } - public Dictionary LocalizedDescriptions { get; set; } + public ConcurrentDictionary LocalizedNames { get; set; } + public ConcurrentDictionary LocalizedDescriptions { get; set; } } \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs b/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs index 9431540d4..f3f8a690f 100644 --- a/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs +++ b/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs @@ -6,10 +6,10 @@ namespace StatisticAnalysisTool.Extractor.Utilities; public class ItemData : IDisposable { - public static void CreateItemData(string mainGameFolder, LocalizationData localizationData, string outputFolderPath, string outputFileNameWithExtension = "items.json") + public static async Task CreateItemDataAsync(string mainGameFolder, LocalizationData localizationData, string outputFolderPath, string outputFileNameWithExtension = "items.json") { var itemBinPath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\items.bin"); - var itemDataByteArray = BinaryDecrypter.DecryptAndDecompress(itemBinPath); + var itemDataByteArray = await BinaryDecrypter.DecryptAndDecompressAsync(itemBinPath); ExtractFromByteArray(itemDataByteArray, GetExportStream(outputFolderPath, outputFileNameWithExtension), localizationData); } @@ -32,71 +32,83 @@ private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream output var index = 1; var first = true; - foreach (XmlNode node in rootNode?.ChildNodes) - { - if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) - { - continue; - } - - var uniqueName = node.Attributes["uniquename"]?.Value; - var enchantmentLevel = node.Attributes["enchantmentlevel"]; - var description = node.Attributes["descriptionlocatag"]; - var name = node.Attributes["descvariable0"]; - var enchantment = ""; - if (enchantmentLevel != null && enchantmentLevel.Value != "0") - { - enchantment = "@" + enchantmentLevel.Value; - } - var localizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName; - if (uniqueName != null && uniqueName.Contains("ARTEFACT")) - { - localizationNameVariable = LocalizationData.ItemPrefix + uniqueName; - } - var container = new ItemContainer() - { - Index = index.ToString(), - UniqueName = uniqueName + enchantment, - LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, - LocalizationNameVariable = localizationNameVariable - }; - SetLocalization(localizationData, container); - WriteItem(outputStream, container, first); - if (first) - { - first = false; - } - index++; - - if (node.Name == "journalitem") + if (rootNode?.ChildNodes != null) + { + foreach (XmlNode node in rootNode.ChildNodes) { - journals.Add(new ItemContainer() + if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) { - UniqueName = uniqueName - }); - } + continue; + } + + var uniqueName = node.Attributes["uniquename"]?.Value; + var enchantmentLevel = node.Attributes["enchantmentlevel"]; + var description = node.Attributes["descriptionlocatag"]; + var name = node.Attributes["descvariable0"]; + var enchantment = ""; + if (enchantmentLevel != null && enchantmentLevel.Value != "0") + { + enchantment = "@" + enchantmentLevel.Value; + } - var element = FindElement(node, "enchantments"); - if (element == null) - { - continue; - } + var localizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName; + if (uniqueName != null && uniqueName.Contains("ARTEFACT")) + { + localizationNameVariable = LocalizationData.ItemPrefix + uniqueName; + } - foreach (XmlElement childNode in element.ChildNodes) - { - var enchantmentName = node.Attributes["uniquename"]?.Value + "@" + childNode.Attributes["enchantmentlevel"]?.Value; - container = new ItemContainer() + var container = new ItemContainer() { Index = index.ToString(), - UniqueName = enchantmentName, - LocalizationDescriptionVariable = description != null ? description.Value : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, - LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName + UniqueName = uniqueName + enchantment, + LocalizationDescriptionVariable = description != null + ? description.Value + : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = localizationNameVariable }; + SetLocalization(localizationData, container); - WriteItem(outputStream, container); + WriteItem(outputStream, container, first); + if (first) + { + first = false; + } index++; + + if (node.Name == "journalitem") + { + journals.Add(new ItemContainer() + { + UniqueName = uniqueName ?? string.Empty + }); + } + + var element = FindElement(node, "enchantments"); + if (element == null) + { + continue; + } + + foreach (XmlElement childNode in element.ChildNodes) + { + var enchantmentName = node.Attributes["uniquename"]?.Value + "@" + + childNode.Attributes["enchantmentlevel"]?.Value; + container = new ItemContainer() + { + Index = index.ToString(), + UniqueName = enchantmentName, + LocalizationDescriptionVariable = description != null + ? description.Value + : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, + LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName + }; + SetLocalization(localizationData, container); + WriteItem(outputStream, container); + + index++; + } } } @@ -134,11 +146,6 @@ private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream output private static void SetLocalization(LocalizationData data, ItemContainer item) { - if (data == default) - { - return; - } - if (data.LocalizedDescriptions.TryGetValue(item.LocalizationDescriptionVariable, out var descriptions)) { item.LocalizedDescriptions = descriptions; @@ -166,7 +173,7 @@ private static void SetLocalization(LocalizationData data, ItemContainer item) private static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) { var output = new StringBuilder(); - + if (!first) { output.AppendLine(","); diff --git a/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs b/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs index 2dc5b4242..118e5f1b6 100644 --- a/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs +++ b/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs @@ -1,4 +1,5 @@ -using System.Text; +using System.Collections.Concurrent; +using System.Text; using System.Xml; namespace StatisticAnalysisTool.Extractor.Utilities; @@ -8,13 +9,13 @@ public class LocalizationData : IDisposable public const string ItemPrefix = "@ITEMS_"; public const string DescPostfix = "_DESC"; - public Dictionary> LocalizedNames = new(); - public Dictionary> LocalizedDescriptions = new(); + public ConcurrentDictionary> LocalizedNames = new(); + public ConcurrentDictionary> LocalizedDescriptions = new(); - public LocalizationData(string mainGameFolder) + public async Task LoadDataAsync(string mainGameFolder) { var localizationBinFilePath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\localization.bin"); - var localizationDataByteArray = BinaryDecrypter.DecryptAndDecompress(localizationBinFilePath); + var localizationDataByteArray = await BinaryDecrypter.DecryptAndDecompressAsync(localizationBinFilePath); var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(Encoding.UTF8.GetString(localizationDataByteArray)); @@ -26,18 +27,18 @@ public LocalizationData(string mainGameFolder) return; } - foreach (XmlNode node in rootNode) + await Parallel.ForEachAsync(rootNode.Cast(), (node, _) => { if (node.NodeType != XmlNodeType.Element) { - continue; + return default; } var tuId = node.Attributes?["tuid"]; if (tuId?.Value.StartsWith(ItemPrefix) != true) { - continue; + return default; } Dictionary languages; @@ -50,20 +51,22 @@ public LocalizationData(string mainGameFolder) } catch (Exception) { - continue; + return default; } // Is item description if (tuId.Value.EndsWith(DescPostfix)) { - LocalizedDescriptions[tuId.Value] = languages; + LocalizedDescriptions[tuId.Value] = new ConcurrentDictionary(languages); } // Is item name else { - LocalizedNames[tuId.Value] = languages; + LocalizedNames[tuId.Value] = new ConcurrentDictionary(languages); } - } + + return default; + }); } public void Dispose() diff --git a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs index 28ed111b0..eedbfb1cb 100644 --- a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs +++ b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs @@ -135,8 +135,7 @@ public MainWindowViewModel() // TEST - var extractor = new Extractor(); - extractor.ExtractGameData("F:\\AlbionOnline", ServerType.Live, "C:\\Users\\schul\\Desktop\\test"); + _ = Extractor.ExtractGameDataAsync("F:\\AlbionOnline", ServerType.Live, "C:\\Users\\schul\\Desktop\\test"); } public void SetUiElements() From 90c437ec025fe1c37e6120df52b74c9932f92790 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 10 Aug 2023 19:24:40 +0200 Subject: [PATCH 08/24] Cleanup code + parallelized --- .../BaseExtractor.cs | 103 ------------ .../BinaryDecrypter.cs | 26 ++-- .../BinaryDumper.cs | 68 ++++---- .../Extractor.cs | 3 +- .../ExtractorUtilities.cs | 41 +++++ .../{Utilities => }/ItemData.cs | 51 +----- .../ItemExtractor.cs | 147 ------------------ .../{Utilities => }/LocalizationData.cs | 10 +- .../StatisticAnalysisTool.Extractor.csproj | 4 + src/StatisticsAnalysisTool/App.xaml.cs | 5 + .../ViewModels/MainWindowViewModel.cs | 4 - 11 files changed, 109 insertions(+), 353 deletions(-) delete mode 100644 src/StatisticAnalysisTool.Extractor/BaseExtractor.cs create mode 100644 src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs rename src/StatisticAnalysisTool.Extractor/{Utilities => }/ItemData.cs (82%) delete mode 100644 src/StatisticAnalysisTool.Extractor/ItemExtractor.cs rename src/StatisticAnalysisTool.Extractor/{Utilities => }/LocalizationData.cs (88%) diff --git a/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs b/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs deleted file mode 100644 index 8c48c77db..000000000 --- a/src/StatisticAnalysisTool.Extractor/BaseExtractor.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Diagnostics; -using StatisticAnalysisTool.Extractor.Utilities; -using System.Text; -using System.Text.Json; -using System.Xml; - -namespace StatisticAnalysisTool.Extractor; - -public abstract class BaseExtractor -{ - protected readonly string OutputFolderPath; - protected readonly string MainGameFolder; - - protected BaseExtractor(string mainGameFolder, string outputFolderPath) - { - OutputFolderPath = outputFolderPath; - MainGameFolder = mainGameFolder; - } - - protected abstract string GetBinFilePath(); - protected abstract void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData); - - protected static XmlElement? FindElement(XmlNode node, string elementName) - { - foreach (XmlNode childNode in node.ChildNodes) - { - if (childNode is XmlElement ele && ele.Name == elementName) - { - return ele; - } - } - - return null; - } - - public void Extract(LocalizationData localizationData = default) - { - var xmlPath = DecryptBinFile(GetBinFilePath(), OutputFolderPath); - Debug.Print("Attribute of the File " + OutputFolderPath); - try - { - using var inputFile = File.OpenRead(xmlPath); - var stream = GetExportStream(); - - ExtractFromXml(inputFile, stream, WriteItem, localizationData); - - CloseExportStream(stream); - stream.Close(); - } - catch - { - throw new ArgumentException(); - } - } - - public static string DecryptBinFile(string binFile, string outputFolderPath) - { - var finalOutPath = Path.ChangeExtension(Path.Combine(outputFolderPath, binFile[(binFile.LastIndexOf("GameData\\", StringComparison.Ordinal) + 9)..]), ".xml"); - Directory.CreateDirectory(Path.GetDirectoryName(finalOutPath) ?? string.Empty); - - using var outputStream = File.Create(finalOutPath); - BinaryDecrypter.DecryptBinaryFile(binFile, outputStream); - return finalOutPath; - } - - private Stream GetExportStream() - { - var filePathWithoutExtension = Path.Combine(OutputFolderPath, "formatted", Path.GetFileNameWithoutExtension(GetBinFilePath())); - if (!Directory.Exists(Path.GetDirectoryName(filePathWithoutExtension))) - { - Directory.CreateDirectory(Path.GetDirectoryName(filePathWithoutExtension) ?? string.Empty); - } - - var stream = File.Create(filePathWithoutExtension + ".json"); - WriteString(stream, "[" + Environment.NewLine); - return stream; - } - - private static void CloseExportStream(Stream stream) - { - WriteString(stream, Environment.NewLine + "]"); - } - - protected static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) - { - var output = new StringBuilder(); - - if (!first) - { - output.AppendLine(","); - } - output.Append(JsonSerializer.Serialize(idContainer, new JsonSerializerOptions { WriteIndented = true })); - - WriteString(stream, output.ToString()); - output.Clear(); - } - - protected static void WriteString(Stream stream, string val) - { - var buffer = Encoding.UTF8.GetBytes(val); - stream.Write(buffer, 0, buffer.Length); - } -} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs b/src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs index 3f2991994..477970cd6 100644 --- a/src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs +++ b/src/StatisticAnalysisTool.Extractor/BinaryDecrypter.cs @@ -8,11 +8,11 @@ public static class BinaryDecrypter private static readonly byte[] Key = { 48, 239, 114, 71, 66, 242, 4, 50 }; private static readonly byte[] Iv = { 14, 166, 220, 137, 219, 237, 220, 79 }; - public static void DecryptBinaryFile(string inputPath, Stream outputStream) + public static async Task DecryptBinaryFileAsync(string inputPath, Stream outputStream) { - using var inputFile = File.OpenRead(inputPath); + await using var inputFile = File.OpenRead(inputPath); var fileBuffer = new byte[inputFile.Length]; - int _ = inputFile.Read(fileBuffer, 0, fileBuffer.Length); + _ = await inputFile.ReadAsync(fileBuffer, 0, fileBuffer.Length); var tDes = new DESCryptoServiceProvider { @@ -26,18 +26,18 @@ public static void DecryptBinaryFile(string inputPath, Stream outputStream) var buffer = new byte[size]; int bytesRead; - using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress); + await using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress); while ((bytesRead = decompression.Read(buffer, 0, buffer.Length)) > 0) { - outputStream.Write(buffer, 0, bytesRead); + await outputStream.WriteAsync(buffer, 0, bytesRead); } } - public static byte[] DecryptAndDecompress(string inputPath) + public static async Task DecryptAndDecompressAsync(string inputPath) { - using var inputFile = File.OpenRead(inputPath); + await using var inputFile = File.OpenRead(inputPath); var fileBuffer = new byte[inputFile.Length]; - int bytesRead = inputFile.Read(fileBuffer, 0, fileBuffer.Length); + int bytesRead = await inputFile.ReadAsync(fileBuffer, 0, fileBuffer.Length); var tDes = new DESCryptoServiceProvider { @@ -51,14 +51,14 @@ public static byte[] DecryptAndDecompress(string inputPath) var buffer = new byte[size]; int decompressedBytesRead; - using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress); - using MemoryStream outputMemoryStream = new MemoryStream(); + await using GZipStream decompression = new GZipStream(new MemoryStream(outBuffer), CompressionMode.Decompress); + await using MemoryStream outputMemoryStream = new MemoryStream(); - while ((decompressedBytesRead = decompression.Read(buffer, 0, buffer.Length)) > 0) + while ((decompressedBytesRead = await decompression.ReadAsync(buffer, 0, buffer.Length)) > 0) { - outputMemoryStream.Write(buffer, 0, decompressedBytesRead); + await outputMemoryStream.WriteAsync(buffer, 0, decompressedBytesRead); } - return outputMemoryStream.ToArray(); + return outputMemoryStream; } } \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs b/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs index ab8e0bee5..2222f5d4c 100644 --- a/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs +++ b/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs @@ -1,66 +1,62 @@ -using System.Text.Json; +using Newtonsoft.Json; using System.Xml; +using Formatting = Newtonsoft.Json.Formatting; namespace StatisticAnalysisTool.Extractor; public class BinaryDumper { - public void Extract(string mainGameFolder, string outputFolderPath) + public static async Task ExtractAsync(string mainGameFolder, string outputFolderPath, + string[] binFileNamesToExtract) { - var allFiles = Directory.GetFiles(GetBinFilePath(mainGameFolder), "*.bin", SearchOption.AllDirectories); + var allFiles = GetBinFilePaths(mainGameFolder, binFileNamesToExtract); var outFiles = (string[]) allFiles.Clone(); for (var i = 0; i < outFiles.Length; i++) { - outFiles[i] = outFiles[i].Remove(0, outFiles[i].LastIndexOf("GameData\\", StringComparison.Ordinal) + "GameData\\".Length); + outFiles[i] = outFiles[i].Remove(0, + outFiles[i].LastIndexOf("GameData\\", StringComparison.Ordinal) + "GameData\\".Length); } - for (var i = 0; i < allFiles.Length; i++) + foreach (string binFilePath in allFiles) { - DecryptBinFile(outputFolderPath, allFiles[i], outFiles[i]); + await DecryptBinFileAsync(outputFolderPath, binFilePath); } } - private string GetBinFilePath(string mainGameFolder) + private static string[] GetBinFilePaths(string mainGameFolder, IEnumerable binFileNamesToExtract) { - return Path.Combine(mainGameFolder, @".\Albion-Online_Data\StreamingAssets\GameData"); + return binFileNamesToExtract.Select(fileName => Path.Combine(GetBinFilePath(mainGameFolder), $"{fileName}.bin")) + .ToArray(); } - private string DecryptBinFile(string outputFolderPath, string binFile, string subdir) + private static string GetBinFilePath(string mainGameFolder) { - var binFileWOE = Path.GetFileNameWithoutExtension(binFile); + return Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData"); + } + + private static async Task DecryptBinFileAsync(string outputFolderPath, string binFilePath) + { + var binFileWoe = Path.GetFileNameWithoutExtension(binFilePath); - // Skip profanity as it has no value for us - if (binFileWOE.StartsWith("profanity", StringComparison.OrdinalIgnoreCase)) + if (binFileWoe.StartsWith("profanity", StringComparison.OrdinalIgnoreCase)) { - return ""; + return; } - var outSubdirs = Path.GetDirectoryName(Path.Combine(outputFolderPath, subdir)); + var finalJsonPath = Path.Combine(outputFolderPath, binFileWoe + ".json"); - if (outSubdirs != "") - Directory.CreateDirectory(outSubdirs); - var finalOutPath = Path.Combine(outSubdirs, binFileWOE); - var finalXmlPath = finalOutPath + ".xml"; - var finalJsonPath = finalOutPath + ".json"; - Console.Out.WriteLine("Extracting " + binFileWOE + ".bin... to:" + finalOutPath + ".xml"); + await using var memoryStream = new MemoryStream(); + await BinaryDecrypter.DecryptBinaryFileAsync(binFilePath, memoryStream); + memoryStream.Position = 0; - using (var outputXmlFile = File.Create(finalXmlPath)) + var xmlDocument = new XmlDocument(); + var xmlReaderSettings = new XmlReaderSettings { - BinaryDecrypter.DecryptBinaryFile(binFile, outputXmlFile); - } - - if (string.Equals("world", binFileWOE, StringComparison.OrdinalIgnoreCase) || (!subdir.StartsWith("cluster") && !subdir.StartsWith("templates"))) - { - var xmlDocument = new XmlDocument(); - var xmlReaderSettings = new XmlReaderSettings - { - IgnoreComments = true - }; - var xmlReader = XmlReader.Create(finalXmlPath, xmlReaderSettings); - xmlDocument.Load(xmlReader); - File.WriteAllText(finalJsonPath, JsonSerializer.Serialize(xmlDocument, new JsonSerializerOptions { WriteIndented = true })); - } + IgnoreComments = true + }; + var xmlReader = XmlReader.Create(memoryStream, xmlReaderSettings); + xmlDocument.Load(xmlReader); - return finalOutPath; + await File.WriteAllTextAsync(finalJsonPath, JsonConvert.SerializeXmlNode(xmlDocument, Formatting.Indented, false)); } } \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/Extractor.cs b/src/StatisticAnalysisTool.Extractor/Extractor.cs index d10d7ade1..9a45da7f8 100644 --- a/src/StatisticAnalysisTool.Extractor/Extractor.cs +++ b/src/StatisticAnalysisTool.Extractor/Extractor.cs @@ -1,5 +1,4 @@ using StatisticAnalysisTool.Extractor.Enums; -using StatisticAnalysisTool.Extractor.Utilities; namespace StatisticAnalysisTool.Extractor; @@ -14,7 +13,7 @@ public static async Task ExtractGameDataAsync(string mainGameFolder, ServerType await localizationData.LoadDataAsync(mainGameFolderString); await ItemData.CreateItemDataAsync(mainGameFolderString, localizationData, outputDirPath); - // TODO ... + await BinaryDumper.ExtractAsync(mainGameFolderString, outputDirPath, new[] { "cluster\\world", "mobs", "spells" }); } private static string GetServerTypeString(ServerType serverType) diff --git a/src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs b/src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs new file mode 100644 index 000000000..e7ab47421 --- /dev/null +++ b/src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs @@ -0,0 +1,41 @@ +using System.Text; +using System.Text.Json; + +namespace StatisticAnalysisTool.Extractor; + +public static class ExtractorUtilities +{ + public static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) + { + var output = new StringBuilder(); + + if (!first) + { + output.AppendLine(","); + } + + var options = new JsonSerializerOptions + { + WriteIndented = true, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + if (idContainer is ItemContainer itemContainer) + { + output.Append(JsonSerializer.Serialize(itemContainer, options)); + } + else + { + output.Append(JsonSerializer.Serialize(idContainer, options)); + } + + WriteString(stream, output.ToString()); + output.Clear(); + } + + public static void WriteString(Stream stream, string val) + { + var buffer = Encoding.UTF8.GetBytes(val); + stream.Write(buffer, 0, buffer.Length); + } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs b/src/StatisticAnalysisTool.Extractor/ItemData.cs similarity index 82% rename from src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs rename to src/StatisticAnalysisTool.Extractor/ItemData.cs index f3f8a690f..fa45f0811 100644 --- a/src/StatisticAnalysisTool.Extractor/Utilities/ItemData.cs +++ b/src/StatisticAnalysisTool.Extractor/ItemData.cs @@ -1,8 +1,7 @@ using System.Text; -using System.Text.Json; using System.Xml; -namespace StatisticAnalysisTool.Extractor.Utilities; +namespace StatisticAnalysisTool.Extractor; public class ItemData : IDisposable { @@ -11,13 +10,13 @@ public static async Task CreateItemDataAsync(string mainGameFolder, Localization var itemBinPath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\items.bin"); var itemDataByteArray = await BinaryDecrypter.DecryptAndDecompressAsync(itemBinPath); - ExtractFromByteArray(itemDataByteArray, GetExportStream(outputFolderPath, outputFileNameWithExtension), localizationData); + ExtractFromByteArray(itemDataByteArray.ToArray(), GetExportStream(outputFolderPath, outputFileNameWithExtension), localizationData); } private static Stream GetExportStream(string outputFolderPath, string outputFileNameWithExtension) { var stream = File.Create(Path.Combine(outputFolderPath, outputFileNameWithExtension)); - WriteString(stream, "[" + Environment.NewLine); + ExtractorUtilities.WriteString(stream, "[" + Environment.NewLine); return stream; } @@ -69,7 +68,7 @@ private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream output }; SetLocalization(localizationData, container); - WriteItem(outputStream, container, first); + ExtractorUtilities.WriteItem(outputStream, container, first); if (first) { first = false; @@ -105,7 +104,7 @@ private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream output LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName }; SetLocalization(localizationData, container); - WriteItem(outputStream, container); + ExtractorUtilities.WriteItem(outputStream, container); index++; } @@ -124,7 +123,7 @@ private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream output }; SetLocalization(localizationData, container); - WriteItem(outputStream, container); + ExtractorUtilities.WriteItem(outputStream, container); index++; container = new ItemContainer() @@ -136,11 +135,11 @@ private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream output }; SetLocalization(localizationData, container); - WriteItem(outputStream, container); + ExtractorUtilities.WriteItem(outputStream, container); index++; } - WriteString(outputStream, Environment.NewLine + "]"); + ExtractorUtilities.WriteString(outputStream, Environment.NewLine + "]"); outputStream.Close(); } @@ -170,40 +169,6 @@ private static void SetLocalization(LocalizationData data, ItemContainer item) return null; } - private static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) - { - var output = new StringBuilder(); - - if (!first) - { - output.AppendLine(","); - } - - var options = new JsonSerializerOptions - { - WriteIndented = true, - Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }; - - if (idContainer is ItemContainer itemContainer) - { - output.Append(JsonSerializer.Serialize(itemContainer, options)); - } - else - { - output.Append(JsonSerializer.Serialize(idContainer, options)); - } - - WriteString(stream, output.ToString()); - output.Clear(); - } - - private static void WriteString(Stream stream, string val) - { - var buffer = Encoding.UTF8.GetBytes(val); - stream.Write(buffer, 0, buffer.Length); - } - private static string RemoveNonPrintableCharacters(string input) { return new string(input.Where(c => !char.IsControl(c) || char.IsWhiteSpace(c)).ToArray()); diff --git a/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs b/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs deleted file mode 100644 index 5139a7f11..000000000 --- a/src/StatisticAnalysisTool.Extractor/ItemExtractor.cs +++ /dev/null @@ -1,147 +0,0 @@ -using StatisticAnalysisTool.Extractor.Utilities; -using System.Xml; - -namespace StatisticAnalysisTool.Extractor; - -public class ItemExtractor : BaseExtractor -{ - public ItemExtractor(string mainGameFolder, string outputFolderPath) : base(mainGameFolder, outputFolderPath) - { - } - - protected override void ExtractFromXml(Stream inputXmlFile, Stream outputStream, Action writeItem, LocalizationData localizationData) - { - var journals = new List(); - var xmlDoc = new XmlDocument(); - xmlDoc.Load(inputXmlFile); - - var rootNode = xmlDoc.LastChild; - - var index = 1; - var first = true; - - if (rootNode?.ChildNodes != null) - { - foreach (XmlNode node in rootNode.ChildNodes) - { - if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) - { - continue; - } - - var uniqueName = node.Attributes["uniquename"]?.Value; - var enchantmentLevel = node.Attributes["enchantmentlevel"]; - var description = node.Attributes["descriptionlocatag"]; - var name = node.Attributes["descvariable0"]; - var enchantment = ""; - if (enchantmentLevel != null && enchantmentLevel.Value != "0") - { - enchantment = "@" + enchantmentLevel.Value; - } - - var localizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName; - if (uniqueName != null && uniqueName.Contains("ARTEFACT")) - { - localizationNameVariable = LocalizationData.ItemPrefix + uniqueName; - } - - var container = new ItemContainer() - { - Index = index.ToString(), - UniqueName = uniqueName + enchantment, - LocalizationDescriptionVariable = description != null - ? description.Value - : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, - LocalizationNameVariable = localizationNameVariable - }; - SetLocalization(localizationData, container); - writeItem(outputStream, container, first); - if (first) - { - first = false; - } - - index++; - - if (node.Name == "journalitem") - { - journals.Add(new ItemContainer() - { - UniqueName = uniqueName ?? string.Empty - }); - } - - var element = FindElement(node, "enchantments"); - if (element == null) - { - continue; - } - - foreach (XmlElement childNode in element.ChildNodes) - { - var enchantmentName = node.Attributes["uniquename"]?.Value + "@" + - childNode.Attributes["enchantmentlevel"]?.Value; - container = new ItemContainer() - { - Index = index.ToString(), - UniqueName = enchantmentName, - LocalizationDescriptionVariable = description != null - ? description.Value - : LocalizationData.ItemPrefix + uniqueName + LocalizationData.DescPostfix, - LocalizationNameVariable = name != null ? name.Value : LocalizationData.ItemPrefix + uniqueName - }; - SetLocalization(localizationData, container); - writeItem(outputStream, container, false); - - index++; - } - } - } - - foreach (var idContainer in journals) - { - var itemContainer = (ItemContainer) idContainer; - var container = new ItemContainer() - { - Index = index.ToString(), - UniqueName = itemContainer.UniqueName + "_EMPTY", - LocalizationDescriptionVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_EMPTY" + LocalizationData.DescPostfix, - LocalizationNameVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_EMPTY" - }; - - SetLocalization(localizationData, container); - writeItem(outputStream, container, false); - index++; - - container = new ItemContainer() - { - Index = index.ToString(), - UniqueName = itemContainer.UniqueName + "_FULL", - LocalizationDescriptionVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_FULL" + LocalizationData.DescPostfix, - LocalizationNameVariable = LocalizationData.ItemPrefix + itemContainer.UniqueName + "_FULL" - }; - - SetLocalization(localizationData, container); - writeItem(outputStream, container, false); - index++; - } - } - - private void SetLocalization(LocalizationData data, ItemContainer item) - { - if (data.LocalizedDescriptions.TryGetValue(item.LocalizationDescriptionVariable, out var descriptions)) - { - item.LocalizedDescriptions = descriptions; - } - - if (data.LocalizedNames.TryGetValue(item.LocalizationNameVariable, out var names)) - { - item.LocalizedNames = names; - } - } - - protected override string GetBinFilePath() - { - return Path.Combine(MainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\items.bin"); - } -} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs b/src/StatisticAnalysisTool.Extractor/LocalizationData.cs similarity index 88% rename from src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs rename to src/StatisticAnalysisTool.Extractor/LocalizationData.cs index 118e5f1b6..4cfb0fb2b 100644 --- a/src/StatisticAnalysisTool.Extractor/Utilities/LocalizationData.cs +++ b/src/StatisticAnalysisTool.Extractor/LocalizationData.cs @@ -2,7 +2,7 @@ using System.Text; using System.Xml; -namespace StatisticAnalysisTool.Extractor.Utilities; +namespace StatisticAnalysisTool.Extractor; public class LocalizationData : IDisposable { @@ -15,10 +15,10 @@ public class LocalizationData : IDisposable public async Task LoadDataAsync(string mainGameFolder) { var localizationBinFilePath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\localization.bin"); - var localizationDataByteArray = await BinaryDecrypter.DecryptAndDecompressAsync(localizationBinFilePath); + var localizationData = await BinaryDecrypter.DecryptAndDecompressAsync(localizationBinFilePath); var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(Encoding.UTF8.GetString(localizationDataByteArray)); + xmlDoc.LoadXml(Encoding.UTF8.GetString(localizationData.ToArray())); var rootNode = xmlDoc.LastChild?.LastChild?.ChildNodes; @@ -27,7 +27,7 @@ public async Task LoadDataAsync(string mainGameFolder) return; } - await Parallel.ForEachAsync(rootNode.Cast(), (node, _) => + await Parallel.ForEachAsync(rootNode.Cast(), (node, _) => { if (node.NodeType != XmlNodeType.Element) { @@ -62,7 +62,7 @@ await Parallel.ForEachAsync(rootNode.Cast(), (node, _) => // Is item name else { - LocalizedNames[tuId.Value] = new ConcurrentDictionary(languages); + LocalizedNames[tuId.Value] = new ConcurrentDictionary(languages); } return default; diff --git a/src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj b/src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj index b5ffb5976..dcfb82f05 100644 --- a/src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj +++ b/src/StatisticAnalysisTool.Extractor/StatisticAnalysisTool.Extractor.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/src/StatisticsAnalysisTool/App.xaml.cs b/src/StatisticsAnalysisTool/App.xaml.cs index fa0d46b15..96c32f145 100644 --- a/src/StatisticsAnalysisTool/App.xaml.cs +++ b/src/StatisticsAnalysisTool/App.xaml.cs @@ -1,5 +1,7 @@ using log4net; using Notification.Wpf; +using StatisticAnalysisTool.Extractor; +using StatisticAnalysisTool.Extractor.Enums; using StatisticsAnalysisTool.Backup; using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; @@ -34,6 +36,9 @@ protected override async void OnStartup(StartupEventArgs e) SettingsController.LoadSettings(); InitializeLanguage(); + // TEST + await Extractor.ExtractGameDataAsync("F:\\AlbionOnline", ServerType.Live, "C:\\Users\\schul\\Desktop\\test"); + AutoUpdateController.RemoveUpdateFiles(); await AutoUpdateController.AutoUpdateAsync(); await BackupController.DeleteOldestBackupsIfNeededAsync(); diff --git a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs index eedbfb1cb..2d4391476 100644 --- a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs +++ b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs @@ -132,10 +132,6 @@ public MainWindowViewModel() UpgradeSettings(); SetUiElements(); Translation = new MainWindowTranslation(); - - - // TEST - _ = Extractor.ExtractGameDataAsync("F:\\AlbionOnline", ServerType.Live, "C:\\Users\\schul\\Desktop\\test"); } public void SetUiElements() From cd5c04ee8d3acaf33e0bf8baf9544f1608a421b4 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 11 Aug 2023 22:52:35 +0200 Subject: [PATCH 09/24] Fixed a bug that prevented "Treasure" lists from saving data correctly --- .../Network/Manager/TreasureController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StatisticsAnalysisTool/Network/Manager/TreasureController.cs b/src/StatisticsAnalysisTool/Network/Manager/TreasureController.cs index 7cccf34db..d4ac51bc7 100644 --- a/src/StatisticsAnalysisTool/Network/Manager/TreasureController.cs +++ b/src/StatisticsAnalysisTool/Network/Manager/TreasureController.cs @@ -20,7 +20,7 @@ public class TreasureController private readonly TrackingController _trackingController; private readonly MainWindowViewModel _mainWindowViewModel; private readonly ObservableCollection _temporaryTreasures = new(); - private ObservableCollection _treasures; + private ObservableCollection _treasures = new (); public TreasureController(TrackingController trackingController, MainWindowViewModel mainWindowViewModel) { From 57b4ad3f8058fc057d61152dc164e037fc73f282 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 12 Aug 2023 09:03:51 +0200 Subject: [PATCH 10/24] Added nuget Ookii.Dialogs.Wpf --- src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj b/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj index 438f7b169..29358336e 100644 --- a/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj +++ b/src/StatisticsAnalysisTool/StatisticsAnalysisTool.csproj @@ -554,6 +554,7 @@ + From 0b7c022f4bb7017ae2be38b3d6561a8d84423c74 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 12 Aug 2023 09:06:09 +0200 Subject: [PATCH 11/24] Change namespace from GameData to GameFileData --- .../Cluster/ClusterController.cs | 2 +- .../Cluster/ClusterInfo.cs | 2 +- .../Dungeon/DungeonController.cs | 4 +-- .../Dungeon/DungeonNotificationFragment.cs | 2 +- .../GameData/Models/SpellsJsonRootObject.cs | 10 ------ .../Converter/MarkerToMarkersListConverter.cs | 4 +-- .../LootChestData.cs | 12 +++---- .../{GameData => GameFileData}/MobsData.cs | 6 ++-- .../Models/Marker.cs | 2 +- .../Models/Minimapmarkers.cs | 4 +-- .../Models/MobJsonObject.cs | 2 +- .../Models/MobJsonRootObject.cs | 2 +- .../Models/MobObjects.cs | 2 +- .../Models/SpellsJsonObject.cs | 2 +- .../Models/SpellsJsonRootObject.cs | 10 ++++++ .../Models/WorldJsonClusterObject.cs | 2 +- .../Models/WorldJsonClustersObject.cs | 2 +- .../Models/WorldJsonObject.cs | 2 +- .../Models/WorldJsonRootObject.cs | 2 +- .../{GameData => GameFileData}/SpellData.cs | 4 +-- .../{GameData => GameFileData}/WorldData.cs | 4 +-- .../Models/ActiveSpellJsonObject.cs | 4 +-- .../Models/CurrentMapInfoBinding.cs | 2 +- .../EssentialCraftingValues.cs | 6 ++-- .../Models/ItemWindowModel/RequiredJournal.cs | 6 ++-- .../ItemWindowModel/RequiredResource.cs | 6 ++-- .../Models/NetworkModel/Vault.cs | 13 ++++---- .../Models/NetworkModel/VaultInfo.cs | 2 +- src/StatisticsAnalysisTool/Models/Spell.cs | 2 +- .../Models/VaultSearchItem.cs | 6 ++-- .../Responses/ChangeClusterResponse.cs | 8 ++--- .../Operations/Responses/JoinResponse.cs | 6 ++-- src/StatisticsAnalysisTool/Trade/Trade.cs | 2 +- .../ViewModels/ItemWindowViewModel.cs | 4 +-- .../ViewModels/MainWindowViewModel.cs | 31 +++---------------- 35 files changed, 79 insertions(+), 101 deletions(-) delete mode 100644 src/StatisticsAnalysisTool/GameData/Models/SpellsJsonRootObject.cs rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Converter/MarkerToMarkersListConverter.cs (96%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/LootChestData.cs (97%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/MobsData.cs (95%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/Marker.cs (71%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/Minimapmarkers.cs (68%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/MobJsonObject.cs (85%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/MobJsonRootObject.cs (73%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/MobObjects.cs (77%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/SpellsJsonObject.cs (85%) create mode 100644 src/StatisticsAnalysisTool/GameFileData/Models/SpellsJsonRootObject.cs rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/WorldJsonClusterObject.cs (79%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/WorldJsonClustersObject.cs (76%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/WorldJsonObject.cs (89%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/Models/WorldJsonRootObject.cs (75%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/SpellData.cs (95%) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/WorldData.cs (98%) diff --git a/src/StatisticsAnalysisTool/Cluster/ClusterController.cs b/src/StatisticsAnalysisTool/Cluster/ClusterController.cs index 3878a9e42..22ddc3467 100644 --- a/src/StatisticsAnalysisTool/Cluster/ClusterController.cs +++ b/src/StatisticsAnalysisTool/Cluster/ClusterController.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Network.Manager; using StatisticsAnalysisTool.ViewModels; using System; diff --git a/src/StatisticsAnalysisTool/Cluster/ClusterInfo.cs b/src/StatisticsAnalysisTool/Cluster/ClusterInfo.cs index c82878a44..756ad5567 100644 --- a/src/StatisticsAnalysisTool/Cluster/ClusterInfo.cs +++ b/src/StatisticsAnalysisTool/Cluster/ClusterInfo.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using System; using System.Collections.Generic; diff --git a/src/StatisticsAnalysisTool/Dungeon/DungeonController.cs b/src/StatisticsAnalysisTool/Dungeon/DungeonController.cs index d4ccd268d..4f40615a4 100644 --- a/src/StatisticsAnalysisTool/Dungeon/DungeonController.cs +++ b/src/StatisticsAnalysisTool/Dungeon/DungeonController.cs @@ -2,7 +2,7 @@ using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Models; using StatisticsAnalysisTool.Models.NetworkModel; using StatisticsAnalysisTool.Network.Manager; @@ -241,7 +241,7 @@ public async Task RemoveDungeonByHashAsync(IEnumerable dungeonHash) } } - await foreach (var dungeonFragment in _mainWindowViewModel?.DungeonBindings?.TrackingDungeons?.ToList().ToAsyncEnumerable() + await foreach (var dungeonFragment in _mainWindowViewModel?.DungeonBindings?.TrackingDungeons?.ToList().ToAsyncEnumerable() ?? new List().ToAsyncEnumerable()) { await Application.Current.Dispatcher.InvokeAsync(() => diff --git a/src/StatisticsAnalysisTool/Dungeon/DungeonNotificationFragment.cs b/src/StatisticsAnalysisTool/Dungeon/DungeonNotificationFragment.cs index 97db8c8db..bc7afc2e7 100644 --- a/src/StatisticsAnalysisTool/Dungeon/DungeonNotificationFragment.cs +++ b/src/StatisticsAnalysisTool/Dungeon/DungeonNotificationFragment.cs @@ -1,7 +1,7 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Enumerations; using StatisticsAnalysisTool.EventLogging.Notification; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Models; using StatisticsAnalysisTool.Models.NetworkModel; using StatisticsAnalysisTool.Network.Notification; diff --git a/src/StatisticsAnalysisTool/GameData/Models/SpellsJsonRootObject.cs b/src/StatisticsAnalysisTool/GameData/Models/SpellsJsonRootObject.cs deleted file mode 100644 index d9b0d1324..000000000 --- a/src/StatisticsAnalysisTool/GameData/Models/SpellsJsonRootObject.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; -using StatisticsAnalysisTool.Models; - -namespace StatisticsAnalysisTool.GameData.Models; - -public class SpellsJsonRootObject -{ - [JsonPropertyName("spells")] - public ActiveSpellJsonObject SpellsJson { get; set; } -} \ No newline at end of file diff --git a/src/StatisticsAnalysisTool/GameData/Converter/MarkerToMarkersListConverter.cs b/src/StatisticsAnalysisTool/GameFileData/Converter/MarkerToMarkersListConverter.cs similarity index 96% rename from src/StatisticsAnalysisTool/GameData/Converter/MarkerToMarkersListConverter.cs rename to src/StatisticsAnalysisTool/GameFileData/Converter/MarkerToMarkersListConverter.cs index 2ea720a4c..a24b60b00 100644 --- a/src/StatisticsAnalysisTool/GameData/Converter/MarkerToMarkersListConverter.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Converter/MarkerToMarkersListConverter.cs @@ -1,10 +1,10 @@ -using StatisticsAnalysisTool.GameData.Models; +using StatisticsAnalysisTool.GameFileData.Models; using System; using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Converter; +namespace StatisticsAnalysisTool.GameFileData.Converter; public class MarkerToMarkersListConverter : JsonConverter> { diff --git a/src/StatisticsAnalysisTool/GameData/LootChestData.cs b/src/StatisticsAnalysisTool/GameFileData/LootChestData.cs similarity index 97% rename from src/StatisticsAnalysisTool/GameData/LootChestData.cs rename to src/StatisticsAnalysisTool/GameFileData/LootChestData.cs index 35b963a0b..1f5b33f00 100644 --- a/src/StatisticsAnalysisTool/GameData/LootChestData.cs +++ b/src/StatisticsAnalysisTool/GameFileData/LootChestData.cs @@ -1,15 +1,15 @@ -using StatisticsAnalysisTool.Common; -using StatisticsAnalysisTool.Common.UserSettings; -using StatisticsAnalysisTool.Models; -using StatisticsAnalysisTool.Properties; using System; using System.Collections.Generic; using System.Linq; -using System.Text.Json.Serialization; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; +using StatisticsAnalysisTool.Common; +using StatisticsAnalysisTool.Common.UserSettings; +using StatisticsAnalysisTool.Models; +using StatisticsAnalysisTool.Properties; -namespace StatisticsAnalysisTool.GameData; +namespace StatisticsAnalysisTool.GameFileData; public static class LootChestData { diff --git a/src/StatisticsAnalysisTool/GameData/MobsData.cs b/src/StatisticsAnalysisTool/GameFileData/MobsData.cs similarity index 95% rename from src/StatisticsAnalysisTool/GameData/MobsData.cs rename to src/StatisticsAnalysisTool/GameFileData/MobsData.cs index 82bd6b26a..198f946c3 100644 --- a/src/StatisticsAnalysisTool/GameData/MobsData.cs +++ b/src/StatisticsAnalysisTool/GameFileData/MobsData.cs @@ -1,15 +1,15 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; -using StatisticsAnalysisTool.GameData.Models; +using StatisticsAnalysisTool.GameFileData.Models; using StatisticsAnalysisTool.Properties; using System; using System.Collections.Generic; using System.Linq; -using System.Text.Json.Serialization; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; -namespace StatisticsAnalysisTool.GameData; +namespace StatisticsAnalysisTool.GameFileData; public static class MobsData { diff --git a/src/StatisticsAnalysisTool/GameData/Models/Marker.cs b/src/StatisticsAnalysisTool/GameFileData/Models/Marker.cs similarity index 71% rename from src/StatisticsAnalysisTool/GameData/Models/Marker.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/Marker.cs index 9a645a7c5..3dee959e5 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/Marker.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/Marker.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class Marker { diff --git a/src/StatisticsAnalysisTool/GameData/Models/Minimapmarkers.cs b/src/StatisticsAnalysisTool/GameFileData/Models/Minimapmarkers.cs similarity index 68% rename from src/StatisticsAnalysisTool/GameData/Models/Minimapmarkers.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/Minimapmarkers.cs index 48000046f..db5861075 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/Minimapmarkers.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/Minimapmarkers.cs @@ -1,8 +1,8 @@ -using StatisticsAnalysisTool.GameData.Converter; +using StatisticsAnalysisTool.GameFileData.Converter; using System.Collections.Generic; using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class MiniMapMarkers { diff --git a/src/StatisticsAnalysisTool/GameData/Models/MobJsonObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/MobJsonObject.cs similarity index 85% rename from src/StatisticsAnalysisTool/GameData/Models/MobJsonObject.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/MobJsonObject.cs index fc1c620cf..b99a5a0a2 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/MobJsonObject.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/MobJsonObject.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class MobJsonObject { diff --git a/src/StatisticsAnalysisTool/GameData/Models/MobJsonRootObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/MobJsonRootObject.cs similarity index 73% rename from src/StatisticsAnalysisTool/GameData/Models/MobJsonRootObject.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/MobJsonRootObject.cs index 782bca71c..f2f9afd4a 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/MobJsonRootObject.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/MobJsonRootObject.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class MobJsonRootObject { diff --git a/src/StatisticsAnalysisTool/GameData/Models/MobObjects.cs b/src/StatisticsAnalysisTool/GameFileData/Models/MobObjects.cs similarity index 77% rename from src/StatisticsAnalysisTool/GameData/Models/MobObjects.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/MobObjects.cs index 2e5f4a3fd..c01a87459 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/MobObjects.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/MobObjects.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class MobObjects { diff --git a/src/StatisticsAnalysisTool/GameData/Models/SpellsJsonObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/SpellsJsonObject.cs similarity index 85% rename from src/StatisticsAnalysisTool/GameData/Models/SpellsJsonObject.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/SpellsJsonObject.cs index 8fab3573c..037db74a4 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/SpellsJsonObject.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/SpellsJsonObject.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class SpellsJsonObject { diff --git a/src/StatisticsAnalysisTool/GameFileData/Models/SpellsJsonRootObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/SpellsJsonRootObject.cs new file mode 100644 index 000000000..630068905 --- /dev/null +++ b/src/StatisticsAnalysisTool/GameFileData/Models/SpellsJsonRootObject.cs @@ -0,0 +1,10 @@ +using StatisticsAnalysisTool.Models; +using System.Text.Json.Serialization; + +namespace StatisticsAnalysisTool.GameFileData.Models; + +public class SpellsJsonRootObject +{ + [JsonPropertyName("spells")] + public ActiveSpellJsonObject SpellsJson { get; set; } +} \ No newline at end of file diff --git a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonClusterObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonClusterObject.cs similarity index 79% rename from src/StatisticsAnalysisTool/GameData/Models/WorldJsonClusterObject.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonClusterObject.cs index 817ff2ca3..e883c9196 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonClusterObject.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonClusterObject.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class WorldJsonClusterObject { diff --git a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonClustersObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonClustersObject.cs similarity index 76% rename from src/StatisticsAnalysisTool/GameData/Models/WorldJsonClustersObject.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonClustersObject.cs index 3170875d8..5474b098a 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonClustersObject.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonClustersObject.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class WorldJsonClustersObject { diff --git a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonObject.cs similarity index 89% rename from src/StatisticsAnalysisTool/GameData/Models/WorldJsonObject.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonObject.cs index 5e7e873fc..df96ca90e 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonObject.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonObject.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class WorldJsonObject { diff --git a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonRootObject.cs b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonRootObject.cs similarity index 75% rename from src/StatisticsAnalysisTool/GameData/Models/WorldJsonRootObject.cs rename to src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonRootObject.cs index b58664a44..bd56028bb 100644 --- a/src/StatisticsAnalysisTool/GameData/Models/WorldJsonRootObject.cs +++ b/src/StatisticsAnalysisTool/GameFileData/Models/WorldJsonRootObject.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace StatisticsAnalysisTool.GameData.Models; +namespace StatisticsAnalysisTool.GameFileData.Models; public class WorldJsonRootObject { diff --git a/src/StatisticsAnalysisTool/GameData/SpellData.cs b/src/StatisticsAnalysisTool/GameFileData/SpellData.cs similarity index 95% rename from src/StatisticsAnalysisTool/GameData/SpellData.cs rename to src/StatisticsAnalysisTool/GameFileData/SpellData.cs index ae4659645..8b6014c02 100644 --- a/src/StatisticsAnalysisTool/GameData/SpellData.cs +++ b/src/StatisticsAnalysisTool/GameFileData/SpellData.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; -using StatisticsAnalysisTool.GameData.Models; +using StatisticsAnalysisTool.GameFileData.Models; using StatisticsAnalysisTool.Properties; using System; using System.Collections.Generic; @@ -9,7 +9,7 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; -namespace StatisticsAnalysisTool.GameData; +namespace StatisticsAnalysisTool.GameFileData; public static class SpellData { diff --git a/src/StatisticsAnalysisTool/GameData/WorldData.cs b/src/StatisticsAnalysisTool/GameFileData/WorldData.cs similarity index 98% rename from src/StatisticsAnalysisTool/GameData/WorldData.cs rename to src/StatisticsAnalysisTool/GameFileData/WorldData.cs index bdac7de47..48f3c412d 100644 --- a/src/StatisticsAnalysisTool/GameData/WorldData.cs +++ b/src/StatisticsAnalysisTool/GameFileData/WorldData.cs @@ -2,7 +2,7 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.GameData.Models; +using StatisticsAnalysisTool.GameFileData.Models; using StatisticsAnalysisTool.Properties; using System; using System.Collections.Generic; @@ -10,7 +10,7 @@ using System.Text.Json; using System.Threading.Tasks; -namespace StatisticsAnalysisTool.GameData; +namespace StatisticsAnalysisTool.GameFileData; public static class WorldData { diff --git a/src/StatisticsAnalysisTool/Models/ActiveSpellJsonObject.cs b/src/StatisticsAnalysisTool/Models/ActiveSpellJsonObject.cs index 478a07483..4ac74cb06 100644 --- a/src/StatisticsAnalysisTool/Models/ActiveSpellJsonObject.cs +++ b/src/StatisticsAnalysisTool/Models/ActiveSpellJsonObject.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using StatisticsAnalysisTool.GameFileData.Models; +using System.Collections.Generic; using System.Text.Json.Serialization; -using StatisticsAnalysisTool.GameData.Models; namespace StatisticsAnalysisTool.Models; diff --git a/src/StatisticsAnalysisTool/Models/CurrentMapInfoBinding.cs b/src/StatisticsAnalysisTool/Models/CurrentMapInfoBinding.cs index 1cabc8fe4..5b558018b 100644 --- a/src/StatisticsAnalysisTool/Models/CurrentMapInfoBinding.cs +++ b/src/StatisticsAnalysisTool/Models/CurrentMapInfoBinding.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Properties; using System.ComponentModel; using System.Runtime.CompilerServices; diff --git a/src/StatisticsAnalysisTool/Models/ItemWindowModel/EssentialCraftingValues.cs b/src/StatisticsAnalysisTool/Models/ItemWindowModel/EssentialCraftingValues.cs index af68f9302..0b07e5094 100644 --- a/src/StatisticsAnalysisTool/Models/ItemWindowModel/EssentialCraftingValues.cs +++ b/src/StatisticsAnalysisTool/Models/ItemWindowModel/EssentialCraftingValues.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.ViewModels; using System; using System.Collections.Generic; @@ -53,7 +53,7 @@ private async void LoadSellPriceAsync(Location location) var buyPriceMax = _marketResponse?.FirstOrDefault(x => string.Equals(x?.City, Locations.GetParameterName(location), StringComparison.CurrentCultureIgnoreCase))?.BuyPriceMax; if (buyPriceMax != null) { - SellPricePerItem = (long)buyPriceMax; + SellPricePerItem = (long) buyPriceMax; } return; @@ -62,7 +62,7 @@ private async void LoadSellPriceAsync(Location location) var sellPriceMin = _marketResponse?.FirstOrDefault(x => string.Equals(x?.City, Locations.GetParameterName(location), StringComparison.CurrentCultureIgnoreCase))?.SellPriceMin; if (sellPriceMin != null) { - SellPricePerItem = (long)sellPriceMin; + SellPricePerItem = (long) sellPriceMin; } } diff --git a/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredJournal.cs b/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredJournal.cs index 17529a890..82039ebfd 100644 --- a/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredJournal.cs +++ b/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredJournal.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.ViewModels; using System; using System.Collections.Generic; @@ -56,7 +56,7 @@ private async void LoadSellPriceEmptyJournalAsync(Location location) var sellPriceMin = _marketResponseEmptyJournal?.FirstOrDefault(x => string.Equals(x?.City, Locations.GetParameterName(location), StringComparison.CurrentCultureIgnoreCase))?.SellPriceMin; if (sellPriceMin != null) { - CostsPerJournal = (long)sellPriceMin; + CostsPerJournal = (long) sellPriceMin; } } @@ -72,7 +72,7 @@ private async void LoadSellPriceFullJournalAsync(Location location) var sellPriceMin = _marketResponseFullJournal?.FirstOrDefault(x => string.Equals(x?.City, Locations.GetParameterName(location), StringComparison.CurrentCultureIgnoreCase))?.SellPriceMin; if (sellPriceMin != null) { - SellPricePerJournal = (long)sellPriceMin; + SellPricePerJournal = (long) sellPriceMin; } } diff --git a/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredResource.cs b/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredResource.cs index 0aab04fc2..5dd83ffa0 100644 --- a/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredResource.cs +++ b/src/StatisticsAnalysisTool/Models/ItemWindowModel/RequiredResource.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.ViewModels; using System; using System.Collections.Generic; @@ -49,7 +49,7 @@ private async void LoadSellPriceAsync(Location location) var sellPriceMin = _marketResponse?.FirstOrDefault(x => string.Equals(x?.City, Locations.GetParameterName(location), StringComparison.CurrentCultureIgnoreCase))?.SellPriceMin; if (sellPriceMin != null) { - ResourceCost = (long)sellPriceMin; + ResourceCost = (long) sellPriceMin; } } @@ -134,7 +134,7 @@ public long ResourceCost set { _resourceCost = value; - + TotalCost = ResourceCost * TotalQuantity; _itemWindowViewModelOld.UpdateCraftingCalculationTab(); OnPropertyChanged(); diff --git a/src/StatisticsAnalysisTool/Models/NetworkModel/Vault.cs b/src/StatisticsAnalysisTool/Models/NetworkModel/Vault.cs index fdd33eac9..5c3eb1673 100644 --- a/src/StatisticsAnalysisTool/Models/NetworkModel/Vault.cs +++ b/src/StatisticsAnalysisTool/Models/NetworkModel/Vault.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using System.Text.Json.Serialization; -using StatisticsAnalysisTool.Cluster; +using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Common; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; +using System.Collections.Generic; +using System.Text.Json.Serialization; namespace StatisticsAnalysisTool.Models.NetworkModel; @@ -13,10 +13,11 @@ public class Vault public MapType MapType { get; set; } public List VaultContainer { get; set; } = new(); - [JsonIgnore] + [JsonIgnore] public string MainLocation => WorldData.GetUniqueNameOrDefault(MainLocationIndex); [JsonIgnore] - public string LocationDisplayString { + public string LocationDisplayString + { get { if (MapType is MapType.Hideout) diff --git a/src/StatisticsAnalysisTool/Models/NetworkModel/VaultInfo.cs b/src/StatisticsAnalysisTool/Models/NetworkModel/VaultInfo.cs index f6fe54282..807ab9e5a 100644 --- a/src/StatisticsAnalysisTool/Models/NetworkModel/VaultInfo.cs +++ b/src/StatisticsAnalysisTool/Models/NetworkModel/VaultInfo.cs @@ -1,5 +1,5 @@ using StatisticsAnalysisTool.Cluster; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using System; using System.Collections.Generic; diff --git a/src/StatisticsAnalysisTool/Models/Spell.cs b/src/StatisticsAnalysisTool/Models/Spell.cs index 8537c63f9..4185d41e8 100644 --- a/src/StatisticsAnalysisTool/Models/Spell.cs +++ b/src/StatisticsAnalysisTool/Models/Spell.cs @@ -1,5 +1,5 @@ using StatisticsAnalysisTool.Common; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using System.Windows; using System.Windows.Media.Imaging; diff --git a/src/StatisticsAnalysisTool/Models/VaultSearchItem.cs b/src/StatisticsAnalysisTool/Models/VaultSearchItem.cs index 6593a0554..6eeddf66e 100644 --- a/src/StatisticsAnalysisTool/Models/VaultSearchItem.cs +++ b/src/StatisticsAnalysisTool/Models/VaultSearchItem.cs @@ -1,7 +1,7 @@ -using System.Text.Json.Serialization; -using StatisticsAnalysisTool.Cluster; +using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Common; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; +using System.Text.Json.Serialization; namespace StatisticsAnalysisTool.Models; diff --git a/src/StatisticsAnalysisTool/Network/Operations/Responses/ChangeClusterResponse.cs b/src/StatisticsAnalysisTool/Network/Operations/Responses/ChangeClusterResponse.cs index 101721eff..53df9755d 100644 --- a/src/StatisticsAnalysisTool/Network/Operations/Responses/ChangeClusterResponse.cs +++ b/src/StatisticsAnalysisTool/Network/Operations/Responses/ChangeClusterResponse.cs @@ -1,12 +1,12 @@ using log4net; +using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Common; +using StatisticsAnalysisTool.Enumerations; +using StatisticsAnalysisTool.GameFileData; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.GameData; -using StatisticsAnalysisTool.Cluster; namespace StatisticsAnalysisTool.Network.Operations.Responses; @@ -61,7 +61,7 @@ public ChangeClusterResponse(Dictionary parameters) if (parameters.ContainsKey(3)) { - DungeonInformation = ((byte[])parameters[3]).ToArray(); + DungeonInformation = ((byte[]) parameters[3]).ToArray(); } } catch (Exception e) diff --git a/src/StatisticsAnalysisTool/Network/Operations/Responses/JoinResponse.cs b/src/StatisticsAnalysisTool/Network/Operations/Responses/JoinResponse.cs index 091e3bced..7c79f55db 100644 --- a/src/StatisticsAnalysisTool/Network/Operations/Responses/JoinResponse.cs +++ b/src/StatisticsAnalysisTool/Network/Operations/Responses/JoinResponse.cs @@ -1,12 +1,12 @@ using log4net; +using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Common; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.Enumerations; +using StatisticsAnalysisTool.GameFileData; using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; -using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.Cluster; namespace StatisticsAnalysisTool.Network.Operations.Responses; diff --git a/src/StatisticsAnalysisTool/Trade/Trade.cs b/src/StatisticsAnalysisTool/Trade/Trade.cs index 79002c8d6..bae8b1c8d 100644 --- a/src/StatisticsAnalysisTool/Trade/Trade.cs +++ b/src/StatisticsAnalysisTool/Trade/Trade.cs @@ -1,6 +1,6 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Enumerations; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Models; using StatisticsAnalysisTool.Properties; using StatisticsAnalysisTool.Trade.Mails; diff --git a/src/StatisticsAnalysisTool/ViewModels/ItemWindowViewModel.cs b/src/StatisticsAnalysisTool/ViewModels/ItemWindowViewModel.cs index 4820117ff..2d7835af8 100644 --- a/src/StatisticsAnalysisTool/ViewModels/ItemWindowViewModel.cs +++ b/src/StatisticsAnalysisTool/ViewModels/ItemWindowViewModel.cs @@ -5,7 +5,7 @@ using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; using StatisticsAnalysisTool.Exceptions; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Models; using StatisticsAnalysisTool.Models.BindingModel; using StatisticsAnalysisTool.Models.ItemsJsonModel; @@ -427,7 +427,7 @@ private void IsFocusCheckboxEnabled(object fullItemInfo) { if (fullItemInfo is EquipmentItem equipmentItem) { - if (int.TryParse(equipmentItem.CraftingRequirements?.FirstOrDefault()?.CraftingFocus, NumberStyles.Any, + if (int.TryParse(equipmentItem.CraftingRequirements?.FirstOrDefault()?.CraftingFocus, NumberStyles.Any, CultureInfo.InvariantCulture, out int craftingFocusNumber) && (craftingFocusNumber <= 0)) { EssentialCraftingValues.IsCraftingWithFocusCheckboxEnabled = false; diff --git a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs index 2d4391476..29ed3e629 100644 --- a/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs +++ b/src/StatisticsAnalysisTool/ViewModels/MainWindowViewModel.cs @@ -3,14 +3,13 @@ using LiveChartsCore.SkiaSharpView; using log4net; using Microsoft.Win32; -using StatisticAnalysisTool.Extractor; using StatisticsAnalysisTool.Cluster; using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; using StatisticsAnalysisTool.Enumerations; using StatisticsAnalysisTool.EstimatedMarketValue; using StatisticsAnalysisTool.EventLogging; -using StatisticsAnalysisTool.GameData; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Models; using StatisticsAnalysisTool.Models.BindingModel; using StatisticsAnalysisTool.Models.NetworkModel; @@ -32,7 +31,6 @@ using System.Windows; using System.Windows.Data; using System.Windows.Media; -using StatisticAnalysisTool.Extractor.Enums; // ReSharper disable UnusedMember.Global @@ -378,31 +376,10 @@ public async Task InitAsync() IsTaskProgressbarIndeterminate = false; IsDataLoaded = true; - CloseButtonActivationDelayAync(); + CloseButtonActivationDelayAsync(); } - public async Task DownloadItemsJsonAsync() - { - if (!ItemController.IsItemListLoaded()) - { - var itemListTaskTextObject = new TaskTextObject(LanguageController.Translation("GET_ITEM_LIST_JSON")); - ToolTaskBindings.Add(itemListTaskTextObject); - var isItemListLoaded = await ItemController.GetItemListFromJsonAsync().ConfigureAwait(true); - if (!isItemListLoaded) - { - SetErrorBar(Visibility.Visible, LanguageController.Translation("ITEM_LIST_CAN_NOT_BE_LOADED")); - GridTryToLoadTheItemListAgainVisibility = Visibility.Visible; - IsTaskProgressbarIndeterminate = false; - itemListTaskTextObject.SetStatus(TaskTextObject.TaskTextObjectStatus.Canceled); - } - else - { - itemListTaskTextObject.SetStatus(TaskTextObject.TaskTextObjectStatus.Done); - } - } - } - - private async void CloseButtonActivationDelayAync() + private async void CloseButtonActivationDelayAsync() { await Task.Delay(2000); IsCloseButtonActive = true; @@ -430,7 +407,7 @@ public void SwitchToolTasksState() #endregion #region Stats drop down - + public void SwitchStatsDropDownState() { StatsDropDownVisibility = StatsDropDownVisibility switch From 78f6e554610bb8edb71e5b6e67eda4f0e1d5d81d Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 12 Aug 2023 09:07:09 +0200 Subject: [PATCH 12/24] Cleanup + better GC after loading of data --- .../BinaryDumper.cs | 13 +-- .../Extractor.cs | 79 +++++++++++-- .../ExtractorUtilities.cs | 30 ++--- .../ItemContainer.cs | 8 +- .../ItemData.cs | 8 +- .../LocalizationData.cs | 104 +++++++++--------- 6 files changed, 151 insertions(+), 91 deletions(-) diff --git a/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs b/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs index 2222f5d4c..ff78b793a 100644 --- a/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs +++ b/src/StatisticAnalysisTool.Extractor/BinaryDumper.cs @@ -6,15 +6,13 @@ namespace StatisticAnalysisTool.Extractor; public class BinaryDumper { - public static async Task ExtractAsync(string mainGameFolder, string outputFolderPath, - string[] binFileNamesToExtract) + public static async Task ExtractAsync(string mainGameFolder, string outputFolderPath, string[] binFileNamesToExtract) { var allFiles = GetBinFilePaths(mainGameFolder, binFileNamesToExtract); var outFiles = (string[]) allFiles.Clone(); for (var i = 0; i < outFiles.Length; i++) { - outFiles[i] = outFiles[i].Remove(0, - outFiles[i].LastIndexOf("GameData\\", StringComparison.Ordinal) + "GameData\\".Length); + outFiles[i] = outFiles[i].Remove(0, outFiles[i].LastIndexOf("GameData\\", StringComparison.Ordinal) + "GameData\\".Length); } foreach (string binFilePath in allFiles) @@ -25,15 +23,10 @@ public static async Task ExtractAsync(string mainGameFolder, string outputFolder private static string[] GetBinFilePaths(string mainGameFolder, IEnumerable binFileNamesToExtract) { - return binFileNamesToExtract.Select(fileName => Path.Combine(GetBinFilePath(mainGameFolder), $"{fileName}.bin")) + return binFileNamesToExtract.Select(fileName => Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolder), $"{fileName}.bin")) .ToArray(); } - private static string GetBinFilePath(string mainGameFolder) - { - return Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData"); - } - private static async Task DecryptBinFileAsync(string outputFolderPath, string binFilePath) { var binFileWoe = Path.GetFileNameWithoutExtension(binFilePath); diff --git a/src/StatisticAnalysisTool.Extractor/Extractor.cs b/src/StatisticAnalysisTool.Extractor/Extractor.cs index 9a45da7f8..5969749ee 100644 --- a/src/StatisticAnalysisTool.Extractor/Extractor.cs +++ b/src/StatisticAnalysisTool.Extractor/Extractor.cs @@ -4,16 +4,35 @@ namespace StatisticAnalysisTool.Extractor; public class Extractor { - public static async Task ExtractGameDataAsync(string mainGameFolder, ServerType serverType, string outputDirPath) + private readonly LocalizationData _localizationData = new(); + private readonly string _mainGameServerFolderString; + + public Extractor(string mainGameFolder, ServerType serverType) { string mainGameFolderString = Path.Combine(mainGameFolder, GetServerTypeString(serverType)); - mainGameFolderString = mainGameFolderString.Replace("'", ""); + _mainGameServerFolderString = mainGameFolderString.Replace("'", ""); + } + + private async Task LoadLocationDataAsync() + { + if (_localizationData.IsDataLoaded()) + { + return; + } + + await _localizationData.LoadDataAsync(_mainGameServerFolderString); + } - using var localizationData = new LocalizationData(); - await localizationData.LoadDataAsync(mainGameFolderString); + public async Task ExtractIndexedItemGameDataAsync(string outputDirPath, string indexedItemsFileName) + { + await LoadLocationDataAsync(); + await ItemData.CreateItemDataAsync(_mainGameServerFolderString, _localizationData, outputDirPath, indexedItemsFileName); + } - await ItemData.CreateItemDataAsync(mainGameFolderString, localizationData, outputDirPath); - await BinaryDumper.ExtractAsync(mainGameFolderString, outputDirPath, new[] { "cluster\\world", "mobs", "spells" }); + public async Task ExtractGameDataAsync(string outputDirPath, string[] binFileNamesToExtract) + { + await LoadLocationDataAsync(); + await BinaryDumper.ExtractAsync(_mainGameServerFolderString, outputDirPath, binFileNamesToExtract); } private static string GetServerTypeString(ServerType serverType) @@ -27,4 +46,50 @@ private static string GetServerTypeString(ServerType serverType) return serverTypeString; } -} + + public static bool IsBinFileNewer(DateTime toolFileDateTime, string mainGameFolder, ServerType serverType, string fileName) + { + string mainGameFolderPath = Path.Combine(mainGameFolder, GetServerTypeString(serverType)); + var binFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), $"{fileName}.bin"); + + if (!File.Exists(binFilePath)) + { + return false; + } + + try + { + if (File.GetLastWriteTime(binFilePath) > toolFileDateTime) + { + return true; + } + } + catch + { + return false; + } + + return false; + } + + public static bool IsValidMainGameFolder(string mainGameFolder, ServerType serverType) + { + string mainGameFolderPath = Path.Combine(mainGameFolder, GetServerTypeString(serverType)); + + var itemsBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "items.bin"); + var mobsBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "mobs.bin"); + var spellsBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "spells.bin"); + var worldBinFilePath = Path.Combine(ExtractorUtilities.GetBinFilePath(mainGameFolderPath), "cluster", "world.bin"); + + return File.Exists(itemsBinFilePath) + && File.Exists(mobsBinFilePath) + && File.Exists(spellsBinFilePath) + && File.Exists(worldBinFilePath); + } + + public void Dispose() + { + _localizationData.Dispose(); + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs b/src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs index e7ab47421..19219bd68 100644 --- a/src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs +++ b/src/StatisticAnalysisTool.Extractor/ExtractorUtilities.cs @@ -5,32 +5,29 @@ namespace StatisticAnalysisTool.Extractor; public static class ExtractorUtilities { + private static readonly JsonWriterOptions JsonWriterOptions = new () + { + Indented = true, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + public static void WriteItem(Stream stream, IdContainer idContainer, bool first = false) { - var output = new StringBuilder(); - if (!first) { - output.AppendLine(","); + stream.WriteByte((byte) ','); + stream.WriteByte((byte) '\n'); } - var options = new JsonSerializerOptions - { - WriteIndented = true, - Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }; - + using var writer = new Utf8JsonWriter(stream, JsonWriterOptions); if (idContainer is ItemContainer itemContainer) { - output.Append(JsonSerializer.Serialize(itemContainer, options)); + JsonSerializer.Serialize(writer, itemContainer); } else { - output.Append(JsonSerializer.Serialize(idContainer, options)); + JsonSerializer.Serialize(writer, idContainer); } - - WriteString(stream, output.ToString()); - output.Clear(); } public static void WriteString(Stream stream, string val) @@ -38,4 +35,9 @@ public static void WriteString(Stream stream, string val) var buffer = Encoding.UTF8.GetBytes(val); stream.Write(buffer, 0, buffer.Length); } + + public static string GetBinFilePath(string mainGameFolder) + { + return Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData"); + } } \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/ItemContainer.cs b/src/StatisticAnalysisTool.Extractor/ItemContainer.cs index c849a2d40..265f2e63f 100644 --- a/src/StatisticAnalysisTool.Extractor/ItemContainer.cs +++ b/src/StatisticAnalysisTool.Extractor/ItemContainer.cs @@ -1,11 +1,9 @@ -using System.Collections.Concurrent; - -namespace StatisticAnalysisTool.Extractor; +namespace StatisticAnalysisTool.Extractor; public class ItemContainer : IdContainer { public string LocalizationNameVariable { get; set; } public string LocalizationDescriptionVariable { get; set; } - public ConcurrentDictionary LocalizedNames { get; set; } - public ConcurrentDictionary LocalizedDescriptions { get; set; } + public Dictionary LocalizedNames { get; set; } + public Dictionary LocalizedDescriptions { get; set; } } \ No newline at end of file diff --git a/src/StatisticAnalysisTool.Extractor/ItemData.cs b/src/StatisticAnalysisTool.Extractor/ItemData.cs index fa45f0811..55bff22be 100644 --- a/src/StatisticAnalysisTool.Extractor/ItemData.cs +++ b/src/StatisticAnalysisTool.Extractor/ItemData.cs @@ -5,7 +5,7 @@ namespace StatisticAnalysisTool.Extractor; public class ItemData : IDisposable { - public static async Task CreateItemDataAsync(string mainGameFolder, LocalizationData localizationData, string outputFolderPath, string outputFileNameWithExtension = "items.json") + public static async Task CreateItemDataAsync(string mainGameFolder, LocalizationData localizationData, string outputFolderPath, string outputFileNameWithExtension = "indexedItems.json") { var itemBinPath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\items.bin"); var itemDataByteArray = await BinaryDecrypter.DecryptAndDecompressAsync(itemBinPath); @@ -27,14 +27,14 @@ private static void ExtractFromByteArray(byte[] itemDataByteArray, Stream output var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(RemoveNonPrintableCharacters(Encoding.UTF8.GetString(RemoveBom(itemDataByteArray)))); - var rootNode = xmlDoc.LastChild; + using var childNodes = xmlDoc.LastChild?.ChildNodes; var index = 1; var first = true; - if (rootNode?.ChildNodes != null) + if (childNodes != null) { - foreach (XmlNode node in rootNode.ChildNodes) + foreach (XmlNode node in childNodes) { if (node.NodeType != XmlNodeType.Element || string.IsNullOrEmpty(node.Attributes?["uniquename"]?.Value)) { diff --git a/src/StatisticAnalysisTool.Extractor/LocalizationData.cs b/src/StatisticAnalysisTool.Extractor/LocalizationData.cs index 4cfb0fb2b..391ca6b1b 100644 --- a/src/StatisticAnalysisTool.Extractor/LocalizationData.cs +++ b/src/StatisticAnalysisTool.Extractor/LocalizationData.cs @@ -1,5 +1,4 @@ -using System.Collections.Concurrent; -using System.Text; +using System.Text; using System.Xml; namespace StatisticAnalysisTool.Extractor; @@ -9,64 +8,72 @@ public class LocalizationData : IDisposable public const string ItemPrefix = "@ITEMS_"; public const string DescPostfix = "_DESC"; - public ConcurrentDictionary> LocalizedNames = new(); - public ConcurrentDictionary> LocalizedDescriptions = new(); + public Dictionary> LocalizedNames = new(); + public Dictionary> LocalizedDescriptions = new(); public async Task LoadDataAsync(string mainGameFolder) { - var localizationBinFilePath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\localization.bin"); - var localizationData = await BinaryDecrypter.DecryptAndDecompressAsync(localizationBinFilePath); - - var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(Encoding.UTF8.GetString(localizationData.ToArray())); - - var rootNode = xmlDoc.LastChild?.LastChild?.ChildNodes; - - if (rootNode is null) + await Task.Run(async () => { - return; - } + var localizationBinFilePath = Path.Combine(mainGameFolder, ".\\Albion-Online_Data\\StreamingAssets\\GameData\\localization.bin"); + using var localizationData = await BinaryDecrypter.DecryptAndDecompressAsync(localizationBinFilePath); - await Parallel.ForEachAsync(rootNode.Cast(), (node, _) => - { - if (node.NodeType != XmlNodeType.Element) - { - return default; - } + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(Encoding.UTF8.GetString(localizationData.ToArray())); - var tuId = node.Attributes?["tuid"]; + using var rootNode = xmlDoc.LastChild?.LastChild?.ChildNodes; - if (tuId?.Value.StartsWith(ItemPrefix) != true) + if (rootNode is null) { - return default; + return; } - Dictionary languages; - - try + foreach (XmlNode node in rootNode) { - languages = node.ChildNodes - .Cast() - .ToDictionary(x => x.Attributes!["xml:lang"]!.Value, y => y.LastChild!.InnerText); - } - catch (Exception) - { - return default; + if (node.NodeType != XmlNodeType.Element) + { + continue; + } + + var tuId = node.Attributes?["tuid"]; + + if (tuId?.Value.StartsWith(ItemPrefix) != true) + { + continue; + } + + Dictionary languages; + + try + { + languages = node.ChildNodes + .Cast() + .ToDictionary(x => x.Attributes!["xml:lang"]!.Value, y => y.LastChild!.InnerText); + } + catch (Exception) + { + continue; + } + + // Is item description + if (tuId.Value.EndsWith(DescPostfix)) + { + LocalizedDescriptions[tuId.Value] = languages; + } + // Is item name + else + { + LocalizedNames[tuId.Value] = languages; + } } + }); - // Is item description - if (tuId.Value.EndsWith(DescPostfix)) - { - LocalizedDescriptions[tuId.Value] = new ConcurrentDictionary(languages); - } - // Is item name - else - { - LocalizedNames[tuId.Value] = new ConcurrentDictionary(languages); - } + GC.Collect(); + } - return default; - }); + public bool IsDataLoaded() + { + return LocalizedNames.Count > 0 && LocalizedDescriptions.Count > 0; } public void Dispose() @@ -75,9 +82,4 @@ public void Dispose() LocalizedDescriptions.Clear(); GC.SuppressFinalize(this); } - - ~LocalizationData() - { - Dispose(); - } } \ No newline at end of file From b2e14154984d350bf1a7a152ef8614b511b835ce Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 12 Aug 2023 09:07:40 +0200 Subject: [PATCH 13/24] Added MainGameFolderPath setting field --- src/StatisticsAnalysisTool/Common/UserSettings/SettingsObject.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/StatisticsAnalysisTool/Common/UserSettings/SettingsObject.cs b/src/StatisticsAnalysisTool/Common/UserSettings/SettingsObject.cs index e450254cd..553e0b571 100644 --- a/src/StatisticsAnalysisTool/Common/UserSettings/SettingsObject.cs +++ b/src/StatisticsAnalysisTool/Common/UserSettings/SettingsObject.cs @@ -98,4 +98,5 @@ public class SettingsObject public double PartyBuilderMinimalBasicItemPower { get; set; } = 600; public double PartyBuilderMaximumBasicItemPower { get; set; } = 900; public string AnotherAppToStartPath { get; set; } + public string MainGameFolderPath { get; set; } = string.Empty; } \ No newline at end of file From 7dd6c4d047fe6657a6d09b53e0b88c85a50e0a5f Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 12 Aug 2023 09:10:00 +0200 Subject: [PATCH 14/24] Init main game folder with data via dialog window --- src/StatisticsAnalysisTool/App.xaml | 3 +- src/StatisticsAnalysisTool/App.xaml.cs | 20 ++- .../{GameData => GameFileData}/GameData.cs | 81 +++++++++++- .../GameDataPreparationWindowViewModel.cs | 117 ++++++++++++++++++ .../Views/DialogWindow.xaml | 1 - .../Views/GameDataPreparationWindow.xaml | 42 +++++++ .../Views/GameDataPreparationWindow.xaml.cs | 44 +++++++ 7 files changed, 293 insertions(+), 15 deletions(-) rename src/StatisticsAnalysisTool/{GameData => GameFileData}/GameData.cs (57%) create mode 100644 src/StatisticsAnalysisTool/ViewModels/GameDataPreparationWindowViewModel.cs create mode 100644 src/StatisticsAnalysisTool/Views/GameDataPreparationWindow.xaml create mode 100644 src/StatisticsAnalysisTool/Views/GameDataPreparationWindow.xaml.cs diff --git a/src/StatisticsAnalysisTool/App.xaml b/src/StatisticsAnalysisTool/App.xaml index 5d182bf44..68e1e68f1 100644 --- a/src/StatisticsAnalysisTool/App.xaml +++ b/src/StatisticsAnalysisTool/App.xaml @@ -2,7 +2,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" DispatcherUnhandledException="Application_DispatcherUnhandledException" - SessionEnding="OnSessionEnding"> + SessionEnding="OnSessionEnding" + ShutdownMode="OnMainWindowClose"> diff --git a/src/StatisticsAnalysisTool/App.xaml.cs b/src/StatisticsAnalysisTool/App.xaml.cs index 96c32f145..5241bce4f 100644 --- a/src/StatisticsAnalysisTool/App.xaml.cs +++ b/src/StatisticsAnalysisTool/App.xaml.cs @@ -1,11 +1,10 @@ using log4net; using Notification.Wpf; -using StatisticAnalysisTool.Extractor; -using StatisticAnalysisTool.Extractor.Enums; using StatisticsAnalysisTool.Backup; using StatisticsAnalysisTool.Common; using StatisticsAnalysisTool.Common.UserSettings; using StatisticsAnalysisTool.Enumerations; +using StatisticsAnalysisTool.GameFileData; using StatisticsAnalysisTool.Network.Manager; using StatisticsAnalysisTool.Notification; using StatisticsAnalysisTool.ViewModels; @@ -36,18 +35,17 @@ protected override async void OnStartup(StartupEventArgs e) SettingsController.LoadSettings(); InitializeLanguage(); - // TEST - await Extractor.ExtractGameDataAsync("F:\\AlbionOnline", ServerType.Live, "C:\\Users\\schul\\Desktop\\test"); - AutoUpdateController.RemoveUpdateFiles(); await AutoUpdateController.AutoUpdateAsync(); await BackupController.DeleteOldestBackupsIfNeededAsync(); RegisterServices(); - var mainWindow = new MainWindow(_mainWindowViewModel); - mainWindow.Show(); + Current.MainWindow = new MainWindow(_mainWindowViewModel); + await GameData.InitializeGameDataFilesAsync(); + _mainWindowViewModel.InitMainWindowData(); + Current.MainWindow.Show(); Utilities.AnotherAppToStart(SettingsController.CurrentSettings.AnotherAppToStartPath); } @@ -107,21 +105,21 @@ private void Application_DispatcherUnhandledException(object sender, DispatcherU protected override void OnExit(ExitEventArgs e) { - _trackingController.StopTracking(); + _trackingController?.StopTracking(); + CriticalData.Save(); if (!BackupController.ExistBackupOnSettingConditions()) { BackupController.Save(); } - CriticalData.Save(); } private void OnSessionEnding(object sender, SessionEndingCancelEventArgs e) { - _trackingController.StopTracking(); + _trackingController?.StopTracking(); + CriticalData.Save(); if (!BackupController.ExistBackupOnSettingConditions()) { BackupController.Save(); } - CriticalData.Save(); } } \ No newline at end of file diff --git a/src/StatisticsAnalysisTool/GameData/GameData.cs b/src/StatisticsAnalysisTool/GameFileData/GameData.cs similarity index 57% rename from src/StatisticsAnalysisTool/GameData/GameData.cs rename to src/StatisticsAnalysisTool/GameFileData/GameData.cs index e724baf7a..6bfd2ef0a 100644 --- a/src/StatisticsAnalysisTool/GameData/GameData.cs +++ b/src/StatisticsAnalysisTool/GameFileData/GameData.cs @@ -1,8 +1,13 @@ using log4net; +using StatisticAnalysisTool.Extractor; +using StatisticAnalysisTool.Extractor.Enums; using StatisticsAnalysisTool.Common; -using StatisticsAnalysisTool.GameData.Models; +using StatisticsAnalysisTool.Common.UserSettings; +using StatisticsAnalysisTool.GameFileData.Models; using StatisticsAnalysisTool.Models; using StatisticsAnalysisTool.Properties; +using StatisticsAnalysisTool.ViewModels; +using StatisticsAnalysisTool.Views; using System; using System.Collections.Generic; using System.IO; @@ -12,13 +17,85 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; +using System.Windows; -namespace StatisticsAnalysisTool.GameData; +namespace StatisticsAnalysisTool.GameFileData; public static class GameData { private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType); + public static async Task InitializeGameDataFilesAsync() + { + if (string.IsNullOrEmpty(SettingsController.CurrentSettings.MainGameFolderPath)) + { + var result = await GetMainGameDataWithDialogAsync(); + if (!result) + { + Application.Current.Shutdown(); + return; + } + } + else if (!string.IsNullOrEmpty(SettingsController.CurrentSettings.MainGameFolderPath) + && Extractor.IsBinFileNewer( + File.GetLastWriteTime(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Settings.Default.ItemListFileName)), + SettingsController.CurrentSettings.MainGameFolderPath, ServerType.Live, "items")) + { + await GetMainGameDataAsync(SettingsController.CurrentSettings.MainGameFolderPath); + return; + } + + if (!Extractor.IsValidMainGameFolder(SettingsController.CurrentSettings?.MainGameFolderPath ?? string.Empty, ServerType.Live)) + { + var result = await GetMainGameDataWithDialogAsync(); + if (!result) + { + Application.Current.Shutdown(); + } + } + } + + public static async Task GetMainGameDataWithDialogAsync() + { + var dialogWindow = new GameDataPreparationWindow(); + var dialogResult = dialogWindow.ShowDialog(); + + if (dialogResult is true) + { + var gameDataPreparationWindowViewModel = (GameDataPreparationWindowViewModel) dialogWindow.DataContext; + var mainGameFolderPath = gameDataPreparationWindowViewModel.Path; + + SettingsController.CurrentSettings.MainGameFolderPath = mainGameFolderPath; + return await GetMainGameDataAsync(SettingsController.CurrentSettings.MainGameFolderPath); + } + + return false; + } + + public static async Task GetMainGameDataAsync(string mainGameFolderPath) + { + try + { + var tempDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Settings.Default.TempDirecoryName); + var gameFilesDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Settings.Default.GameFilesDirectoryName); + + var extractor = new Extractor(mainGameFolderPath, ServerType.Live); + await extractor.ExtractIndexedItemGameDataAsync(gameFilesDirPath, "indexedItems.json"); + await extractor.ExtractGameDataAsync(gameFilesDirPath, new[] { "items" }); + await extractor.ExtractGameDataAsync(tempDirPath, new[] { "cluster\\world", "mobs", "spells", "items" }); + extractor.Dispose(); + + return true; + } + catch (Exception e) + { + SettingsController.CurrentSettings.MainGameFolderPath = string.Empty; + ConsoleManager.WriteLineForError(MethodBase.GetCurrentMethod()?.DeclaringType, e); + Log.Error(MethodBase.GetCurrentMethod()?.DeclaringType, e); + return false; + } + } + public static async Task> LoadDataAsync( string tempFileName, string regularDataFileName, diff --git a/src/StatisticsAnalysisTool/ViewModels/GameDataPreparationWindowViewModel.cs b/src/StatisticsAnalysisTool/ViewModels/GameDataPreparationWindowViewModel.cs new file mode 100644 index 000000000..b47cd2839 --- /dev/null +++ b/src/StatisticsAnalysisTool/ViewModels/GameDataPreparationWindowViewModel.cs @@ -0,0 +1,117 @@ +using Ookii.Dialogs.Wpf; +using StatisticsAnalysisTool.Common.UserSettings; +using StatisticsAnalysisTool.Common; +using StatisticsAnalysisTool.Properties; +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using StatisticAnalysisTool.Extractor.Enums; +using StatisticAnalysisTool.Extractor; + +namespace StatisticsAnalysisTool.ViewModels; + +public class GameDataPreparationWindowViewModel : INotifyPropertyChanged +{ + private string _title; + private string _message; + private string _path; + private bool _isConfirmButtonEnabled; + private string _errorMessage; + + public GameDataPreparationWindowViewModel() + { + Title = LanguageController.Translation("SELECT_ALBION_ONLINE_MAIN_GAME_FOLDER"); + Message = LanguageController.Translation("PLEASE_SELECT_A_CORRECT_ALBION_ONLINE_MAIN_GAME_FOLDER"); + } + + public void OpenPathSelection() + { + ErrorMessage = string.Empty; + + var dialog = new VistaFolderBrowserDialog() + { + Description = LanguageController.Translation("SELECT_ALBION_ONLINE_MAIN_GAME_FOLDER"), + RootFolder = Environment.SpecialFolder.Desktop, + ShowNewFolderButton = false, + UseDescriptionForTitle = true, + Multiselect = false + }; + + var result = dialog.ShowDialog(); + + if (result.HasValue && result.Value) + { + if (Extractor.IsValidMainGameFolder(dialog.SelectedPath ?? string.Empty, ServerType.Live)) + { + Path = dialog.SelectedPath; + IsConfirmButtonEnabled = true; + } + else + { + ErrorMessage = LanguageController.Translation("PLEASE_SELECT_A_CORRECT_FOLDER"); + IsConfirmButtonEnabled = false; + } + } + } + + public string Title + { + get => _title; + set + { + _title = value; + OnPropertyChanged(); + } + } + + public string Message + { + get => _message; + set + { + _message = value; + OnPropertyChanged(); + } + } + + public string ErrorMessage + { + get => _errorMessage; + set + { + _errorMessage = value; + OnPropertyChanged(); + } + } + + public string Path + { + get => _path; + set + { + _path = value; + OnPropertyChanged(); + } + } + + public bool IsConfirmButtonEnabled + { + get => _isConfirmButtonEnabled; + set + { + _isConfirmButtonEnabled = value; + OnPropertyChanged(); + } + } + + public static string TranslationSelectAlbionOnlineMainGameFolder => LanguageController.Translation("ConfirmButtonText"); + public static string TranslationConfirm => LanguageController.Translation("CONFIRM"); + + public event PropertyChangedEventHandler PropertyChanged; + + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} \ No newline at end of file diff --git a/src/StatisticsAnalysisTool/Views/DialogWindow.xaml b/src/StatisticsAnalysisTool/Views/DialogWindow.xaml index a3f919fdb..c6c2b8321 100644 --- a/src/StatisticsAnalysisTool/Views/DialogWindow.xaml +++ b/src/StatisticsAnalysisTool/Views/DialogWindow.xaml @@ -4,7 +4,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:fa5="http://schemas.fontawesome.com/icons/" - xmlns:enumerations="clr-namespace:StatisticsAnalysisTool.Enumerations" xmlns:viewModels="clr-namespace:StatisticsAnalysisTool.ViewModels" mc:Ignorable="d" d:DataContext="{d:DesignInstance Type=viewModels:DialogWindowViewModel}" diff --git a/src/StatisticsAnalysisTool/Views/GameDataPreparationWindow.xaml b/src/StatisticsAnalysisTool/Views/GameDataPreparationWindow.xaml new file mode 100644 index 000000000..080f6c506 --- /dev/null +++ b/src/StatisticsAnalysisTool/Views/GameDataPreparationWindow.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + +