diff --git a/Pal.Client/Configuration.cs b/Pal.Client/Configuration.cs index 03f982f..0e60483 100644 --- a/Pal.Client/Configuration.cs +++ b/Pal.Client/Configuration.cs @@ -1,9 +1,12 @@ using Dalamud.Configuration; using Dalamud.Logging; +using ECommons.Schedulers; using Newtonsoft.Json; using Pal.Client.Scheduled; using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Numerics; using System.Security.Cryptography; @@ -84,6 +87,48 @@ namespace Pal.Client Version = 4; Save(); } + + if (Version == 4) + { + // 2.2 had a bug that would mark chests as traps, there's no easy way to detect this -- or clean this up. + // Not a problem for online players, but offline players might be fucked. + bool changedAnyFile = false; + LocalState.ForEach(s => + { + foreach (var marker in s.Markers) + marker.SinceVersion = "0.0"; + + var lastModified = File.GetLastWriteTimeUtc(s.GetSaveLocation()); + if (lastModified >= new DateTime(2023, 2, 3, 0, 0, 0, DateTimeKind.Utc)) + { + s.Backup(suffix: "bak"); + + s.Markers = new ConcurrentBag(s.Markers.Where(m => m.SinceVersion != "0.0" || m.Type == Marker.EType.Hoard || m.WasImported)); + s.Save(); + + changedAnyFile = true; + } + else + { + // just add version information, nothing else + s.Save(); + } + }); + + // Only notify offline users - we can just re-download the backup markers from the server seamlessly. + if (Mode == EMode.Offline && changedAnyFile) + { + new TickScheduler(delegate + { + Service.Chat.PrintError("[Palace Pal] Due to a bug, some coffers were accidentally saved as traps. To fix the related display issue, locally cached data was cleaned up."); + Service.Chat.PrintError($"If you have any backup tools installed, please restore the contents of '{Service.PluginInterface.GetPluginConfigDirectory()}' to any backup from February 2, 2023 or before."); + Service.Chat.PrintError("You can also manually restore .json.bak files (by removing the '.bak') if you have not been in any deep dungeon since February 2, 2023."); + }, 2500); + } + + Version = 5; + Save(); + } } #pragma warning restore CS0612 // Type or member is obsolete diff --git a/Pal.Client/LocalState.cs b/Pal.Client/LocalState.cs index 8929b12..d2bff21 100644 --- a/Pal.Client/LocalState.cs +++ b/Pal.Client/LocalState.cs @@ -80,6 +80,26 @@ namespace Pal.Client string path = GetSaveLocation(TerritoryType); ApplyFilters(); + SaveImpl(path); + } + + public void Backup(string suffix) + { + string path = $"{GetSaveLocation(TerritoryType)}.{suffix}"; + if (!File.Exists(path)) + { + SaveImpl(path); + } + } + + private void SaveImpl(string path) + { + foreach (var marker in Markers) + { + if (string.IsNullOrEmpty(marker.SinceVersion)) + marker.SinceVersion = typeof(Plugin).Assembly.GetName().Version!.ToString(2); + } + if (Markers.Count == 0) File.Delete(path); else @@ -92,18 +112,25 @@ namespace Pal.Client } } + public string GetSaveLocation() => GetSaveLocation(TerritoryType); + private static string GetSaveLocation(uint territoryType) => Path.Join(Service.PluginInterface.GetPluginConfigDirectory(), $"{territoryType}.json"); - public static void UpdateAll() + public static void ForEach(Action action) { foreach (ETerritoryType territory in typeof(ETerritoryType).GetEnumValues()) { LocalState? localState = Load((ushort)territory); if (localState != null) - localState.Save(); + action(localState); } } + public static void UpdateAll() + { + ForEach(s => s.Save()); + } + public void UndoImport(List importIds) { // When saving a floor state, any markers not seen, not remote seen, and not having an import id are removed; diff --git a/Pal.Client/Marker.cs b/Pal.Client/Marker.cs index 12bb253..41f5b8f 100644 --- a/Pal.Client/Marker.cs +++ b/Pal.Client/Marker.cs @@ -50,6 +50,11 @@ namespace Pal.Client public bool WasImported { get; set; } + /// + /// To make rollbacks of local data easier, keep track of the version which was used to write the marker initially. + /// + public string SinceVersion { get; set; } + [JsonIgnore] public Element? SplatoonElement { get; set; }