diff --git a/Glamourer/CharacterSave.cs b/Glamourer/CharacterSave.cs index bb45e4e..ea35669 100644 --- a/Glamourer/CharacterSave.cs +++ b/Glamourer/CharacterSave.cs @@ -342,7 +342,7 @@ public class CharacterSave WriteEquipment = oldEquip; } - public void Load(string base64) + public void Load(string base64, out bool oldVersion) { var bytes = Convert.FromBase64String(base64); switch (bytes[0]) @@ -350,12 +350,14 @@ public class CharacterSave case 1: CheckSize(bytes.Length, TotalSizeVersion1); CheckRange(2, bytes[1], 0, 1); - Alpha = 1.0f; - bytes[0] = CurrentVersion; + Alpha = 1.0f; + bytes[0] = CurrentVersion; + oldVersion = true; break; case 2: CheckSize(bytes.Length, TotalSizeVersion2); CheckRange(2, bytes[1], 0, 0x3F); + oldVersion = false; break; default: throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid Version {bytes[0]}."); } @@ -364,13 +366,16 @@ public class CharacterSave bytes.CopyTo(_bytes, 0); } - public static CharacterSave FromString(string base64) + public static CharacterSave FromString(string base64, out bool oldVersion) { var ret = new CharacterSave(); - ret.Load(base64); + ret.Load(base64, out oldVersion); return ret; } + public static CharacterSave FromString(string base64) + => FromString(base64, out _); + public unsafe ref CharacterCustomization Customizations { get diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs index 31fefcf..5bec0bb 100644 --- a/Glamourer/Designs/DesignManager.cs +++ b/Glamourer/Designs/DesignManager.cs @@ -5,155 +5,172 @@ using System.Linq; using Dalamud.Logging; using Glamourer.FileSystem; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; -namespace Glamourer.Designs +namespace Glamourer.Designs; + +public class DesignManager { - public class DesignManager + public const string FileName = "Designs.json"; + private readonly FileInfo _saveFile; + + public SortedList Designs = null!; + public FileSystem.FileSystem FileSystem { get; } = new(); + + public DesignManager() { - public const string FileName = "Designs.json"; - private readonly FileInfo _saveFile; + var saveFolder = new DirectoryInfo(Dalamud.PluginInterface.GetPluginConfigDirectory()); + if (!saveFolder.Exists) + Directory.CreateDirectory(saveFolder.FullName); - public SortedList Designs = null!; - public FileSystem.FileSystem FileSystem { get; } = new(); + _saveFile = new FileInfo(Path.Combine(saveFolder.FullName, FileName)); - public DesignManager() - { - var saveFolder = new DirectoryInfo(Dalamud.PluginInterface.GetPluginConfigDirectory()); - if (!saveFolder.Exists) - Directory.CreateDirectory(saveFolder.FullName); + LoadFromFile(); + } - _saveFile = new FileInfo(Path.Combine(saveFolder.FullName, FileName)); - - LoadFromFile(); - } - - private void BuildStructure() - { - FileSystem.Clear(); - var anyChanges = false; - foreach (var (path, save) in Designs.ToArray()) - { - try - { - var (folder, name) = FileSystem.CreateAllFolders(path); - var design = new Design(folder, name) { Data = save }; - folder.FindOrAddChild(design); - var fixedPath = design.FullName(); - if (string.Equals(fixedPath, path, StringComparison.InvariantCultureIgnoreCase)) - continue; - - Designs.Remove(path); - Designs[fixedPath] = save; - anyChanges = true; - PluginLog.Debug($"Problem loading saved designs, {path} was renamed to {fixedPath}."); - } - catch (Exception e) - { - PluginLog.Error($"Problem loading saved designs, {path} was removed because:\n{e}"); - Designs.Remove(path); - } - } - - if (anyChanges) - SaveToFile(); - } - - private bool UpdateRoot(string oldPath, Design child) - { - var newPath = child.FullName(); - if (string.Equals(newPath, oldPath, StringComparison.InvariantCultureIgnoreCase)) - return false; - - Designs.Remove(oldPath); - Designs[child.FullName()] = child.Data; - return true; - } - - private void UpdateChild(string oldRootPath, string newRootPath, Design child) - { - var newPath = child.FullName(); - var oldPath = $"{oldRootPath}{newPath.Remove(0, newRootPath.Length)}"; - Designs.Remove(oldPath); - Designs[newPath] = child.Data; - } - - public void DeleteAllChildren(IFileSystemBase root, bool deleteEmpty) - { - if (root is Folder f) - foreach (var child in f.AllLeaves(SortMode.Lexicographical)) - Designs.Remove(child.FullName()); - var fullPath = root.FullName(); - root.Parent.RemoveChild(root, deleteEmpty); - Designs.Remove(fullPath); - - SaveToFile(); - } - - public void UpdateAllChildren(string oldPath, IFileSystemBase root) - { - var changes = false; - switch (root) - { - case Design d: - changes |= UpdateRoot(oldPath, d); - break; - case Folder f: - { - var newRootPath = root.FullName(); - if (!string.Equals(oldPath, newRootPath, StringComparison.InvariantCultureIgnoreCase)) - { - changes = true; - foreach (var descendant in f.AllLeaves(SortMode.Lexicographical).Where(l => l is Design).Cast()) - UpdateChild(oldPath, newRootPath, descendant); - } - - break; - } - } - - if (changes) - SaveToFile(); - } - - public void SaveToFile() + private void BuildStructure() + { + FileSystem.Clear(); + var anyChanges = false; + foreach (var (path, save) in Designs.ToArray()) { try { - var data = JsonConvert.SerializeObject(Designs, Formatting.Indented); - File.WriteAllText(_saveFile.FullName, data); + var (folder, name) = FileSystem.CreateAllFolders(path); + var design = new Design(folder, name) { Data = save }; + folder.FindOrAddChild(design); + var fixedPath = design.FullName(); + if (string.Equals(fixedPath, path, StringComparison.InvariantCultureIgnoreCase)) + continue; + + Designs.Remove(path); + Designs[fixedPath] = save; + anyChanges = true; + PluginLog.Debug($"Problem loading saved designs, {path} was renamed to {fixedPath}."); } catch (Exception e) { - PluginLog.Error($"Could not write to save file {_saveFile.FullName}:\n{e}"); + PluginLog.Error($"Problem loading saved designs, {path} was removed because:\n{e}"); + Designs.Remove(path); } } - public void LoadFromFile() + if (anyChanges) + SaveToFile(); + } + + private bool UpdateRoot(string oldPath, Design child) + { + var newPath = child.FullName(); + if (string.Equals(newPath, oldPath, StringComparison.InvariantCultureIgnoreCase)) + return false; + + Designs.Remove(oldPath); + Designs[child.FullName()] = child.Data; + return true; + } + + private void UpdateChild(string oldRootPath, string newRootPath, Design child) + { + var newPath = child.FullName(); + var oldPath = $"{oldRootPath}{newPath.Remove(0, newRootPath.Length)}"; + Designs.Remove(oldPath); + Designs[newPath] = child.Data; + } + + public void DeleteAllChildren(IFileSystemBase root, bool deleteEmpty) + { + if (root is Folder f) + foreach (var child in f.AllLeaves(SortMode.Lexicographical)) + Designs.Remove(child.FullName()); + var fullPath = root.FullName(); + root.Parent.RemoveChild(root, deleteEmpty); + Designs.Remove(fullPath); + + SaveToFile(); + } + + public void UpdateAllChildren(string oldPath, IFileSystemBase root) + { + var changes = false; + switch (root) { - _saveFile.Refresh(); - SortedList? designs = null; - if (_saveFile.Exists) - try + case Design d: + changes |= UpdateRoot(oldPath, d); + break; + case Folder f: + { + var newRootPath = root.FullName(); + if (!string.Equals(oldPath, newRootPath, StringComparison.InvariantCultureIgnoreCase)) { - var data = File.ReadAllText(_saveFile.FullName); - designs = JsonConvert.DeserializeObject>(data); - } - catch (Exception e) - { - PluginLog.Error($"Could not load save file {_saveFile.FullName}:\n{e}"); + changes = true; + foreach (var descendant in f.AllLeaves(SortMode.Lexicographical).Where(l => l is Design).Cast()) + UpdateChild(oldPath, newRootPath, descendant); } - if (designs == null) - { - Designs = new SortedList(); - SaveToFile(); - } - else - { - Designs = designs; + break; } + } - BuildStructure(); + if (changes) + SaveToFile(); + } + + public void SaveToFile() + { + try + { + var data = JsonConvert.SerializeObject(Designs, Formatting.Indented); + File.WriteAllText(_saveFile.FullName, data); + } + catch (Exception e) + { + PluginLog.Error($"Could not write to save file {_saveFile.FullName}:\n{e}"); } } + + public void LoadFromFile() + { + _saveFile.Refresh(); + Designs = new SortedList(); + var changes = false; + if (_saveFile.Exists) + try + { + var data = File.ReadAllText(_saveFile.FullName); + var json = JsonConvert.DeserializeObject>(data); + if (json == null) + { + PluginLog.Error($"Save file {_saveFile.FullName} corrupted."); + json = new Dictionary(); + } + + foreach (var (name, saveString) in json) + { + try + { + var save = CharacterSave.FromString(saveString, out var oldVersion); + changes |= oldVersion; + changes |= !Designs.TryAdd(name, save); + } + catch (Exception e) + { + PluginLog.Error($"Character Save for {name} is invalid:\n{e}"); + changes = true; + } + } + } + catch (Exception e) + { + PluginLog.Error($"Could not load save file {_saveFile.FullName}:\n{e}"); + changes = true; + } + else + changes = true; + + if (changes) + SaveToFile(); + + BuildStructure(); + } } diff --git a/Glamourer/Gui/InterfaceDesigns.cs b/Glamourer/Gui/InterfaceDesigns.cs index c317b31..13c46dd 100644 --- a/Glamourer/Gui/InterfaceDesigns.cs +++ b/Glamourer/Gui/InterfaceDesigns.cs @@ -55,7 +55,7 @@ namespace Glamourer.Gui try { - _selection!.Data = CharacterSave.FromString(text); + _selection!.Data.Load(text, out _); _designs.SaveToFile(); } catch (Exception e)