Restructure save format to be more expandable if needed
This commit is contained in:
parent
8ec3e5b5b0
commit
2adf030ec5
100
Pal.Client/LocalState.cs
Normal file
100
Pal.Client/LocalState.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
using Pal.Common;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace Pal.Client
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// JSON for a single floor set (e.g. 51-60).
|
||||||
|
/// </summary>
|
||||||
|
internal class LocalState
|
||||||
|
{
|
||||||
|
private static readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions { IncludeFields = true };
|
||||||
|
private static readonly int _currentVersion = 2;
|
||||||
|
|
||||||
|
public uint TerritoryType { get; set; }
|
||||||
|
public ConcurrentBag<Marker> Markers { get; set; } = new();
|
||||||
|
|
||||||
|
public LocalState(uint territoryType)
|
||||||
|
{
|
||||||
|
TerritoryType = territoryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyFilters()
|
||||||
|
{
|
||||||
|
if (Service.Configuration.Mode == Configuration.EMode.Offline)
|
||||||
|
Markers = new ConcurrentBag<Marker>(Markers.Where(x => x.Seen));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalState Load(uint territoryType)
|
||||||
|
{
|
||||||
|
string path = GetSaveLocation(territoryType);
|
||||||
|
if (!File.Exists(path))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
string content = File.ReadAllText(path);
|
||||||
|
if (content.Length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
LocalState localState;
|
||||||
|
int version = 1;
|
||||||
|
if (content[0] == '[')
|
||||||
|
{
|
||||||
|
// v1 only had a list of markers, not a JSON object as root
|
||||||
|
localState = new LocalState(territoryType)
|
||||||
|
{
|
||||||
|
Markers = new ConcurrentBag<Marker>(JsonSerializer.Deserialize<HashSet<Marker>>(content, _jsonSerializerOptions)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var save = JsonSerializer.Deserialize<SaveFile>(content, _jsonSerializerOptions);
|
||||||
|
localState = new LocalState(territoryType)
|
||||||
|
{
|
||||||
|
Markers = new ConcurrentBag<Marker>(save.Markers),
|
||||||
|
};
|
||||||
|
version = save.Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
localState.ApplyFilters();
|
||||||
|
|
||||||
|
if (version < _currentVersion)
|
||||||
|
localState.Save();
|
||||||
|
|
||||||
|
return localState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
string path = GetSaveLocation(TerritoryType);
|
||||||
|
|
||||||
|
ApplyFilters();
|
||||||
|
File.WriteAllText(path, JsonSerializer.Serialize(new SaveFile
|
||||||
|
{
|
||||||
|
Version = _currentVersion,
|
||||||
|
Markers = new HashSet<Marker>(Markers)
|
||||||
|
}, _jsonSerializerOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetSaveLocation(uint territoryType) => Path.Join(Service.PluginInterface.GetPluginConfigDirectory(), $"{territoryType}.json");
|
||||||
|
|
||||||
|
public static void UpdateAll()
|
||||||
|
{
|
||||||
|
foreach (ETerritoryType territory in typeof(ETerritoryType).GetEnumValues())
|
||||||
|
{
|
||||||
|
LocalState localState = Load((ushort)territory);
|
||||||
|
if (localState != null)
|
||||||
|
localState.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SaveFile
|
||||||
|
{
|
||||||
|
public int Version { get; set; }
|
||||||
|
public HashSet<Marker> Markers { get; set; } = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<LangVersion>9.0</LangVersion>
|
<LangVersion>9.0</LangVersion>
|
||||||
<Version>1.8.0.0</Version>
|
<Version>1.9.0.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -16,11 +16,9 @@ using Pal.Client.Windows;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -43,7 +41,7 @@ namespace Pal.Client
|
|||||||
private bool _configUpdated = false;
|
private bool _configUpdated = false;
|
||||||
private LocalizedChatMessages _localizedChatMessages = new();
|
private LocalizedChatMessages _localizedChatMessages = new();
|
||||||
|
|
||||||
internal ConcurrentDictionary<ushort, ConcurrentBag<Marker>> FloorMarkers { get; } = new();
|
internal ConcurrentDictionary<ushort, LocalState> FloorMarkers { get; } = new();
|
||||||
internal ConcurrentBag<Marker> EphemeralMarkers { get; set; } = new();
|
internal ConcurrentBag<Marker> EphemeralMarkers { get; set; } = new();
|
||||||
internal ushort LastTerritory { get; private set; }
|
internal ushort LastTerritory { get; private set; }
|
||||||
public SyncState TerritorySyncState { get; set; }
|
public SyncState TerritorySyncState { get; set; }
|
||||||
@ -114,17 +112,31 @@ namespace Pal.Client
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
switch (arguments)
|
switch (arguments)
|
||||||
{
|
{
|
||||||
case "stats":
|
case "stats":
|
||||||
Task.Run(async () => await FetchFloorStatistics());
|
Task.Run(async () => await FetchFloorStatistics());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
case "update-saves":
|
||||||
|
LocalState.UpdateAll();
|
||||||
|
Service.Chat.Print("Updated all locally cached marker files to latest version.");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Service.WindowSystem.GetWindow<ConfigWindow>()?.Toggle();
|
Service.WindowSystem.GetWindow<ConfigWindow>()?.Toggle();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Service.Chat.PrintError($"[Palace Pal] {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
@ -210,15 +222,7 @@ namespace Pal.Client
|
|||||||
{
|
{
|
||||||
if (Service.Configuration.Mode == Configuration.EMode.Offline)
|
if (Service.Configuration.Mode == Configuration.EMode.Offline)
|
||||||
{
|
{
|
||||||
foreach (var path in Directory.GetFiles(Service.PluginInterface.GetPluginConfigDirectory()))
|
LocalState.UpdateAll();
|
||||||
{
|
|
||||||
if (path.EndsWith(".json"))
|
|
||||||
{
|
|
||||||
var markers = JsonSerializer.Deserialize<List<Marker>>(File.ReadAllText(path), new JsonSerializerOptions { IncludeFields = true }).Where(x => x.Seen).ToList();
|
|
||||||
File.WriteAllText(path, JsonSerializer.Serialize(markers, new JsonSerializerOptions { IncludeFields = true }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FloorMarkers.Clear();
|
FloorMarkers.Clear();
|
||||||
EphemeralMarkers.Clear();
|
EphemeralMarkers.Clear();
|
||||||
LastTerritory = 0;
|
LastTerritory = 0;
|
||||||
@ -234,7 +238,7 @@ namespace Pal.Client
|
|||||||
TerritorySyncState = SyncState.NotAttempted;
|
TerritorySyncState = SyncState.NotAttempted;
|
||||||
|
|
||||||
if (IsInPotdOrHoh())
|
if (IsInPotdOrHoh())
|
||||||
FloorMarkers[LastTerritory] = new ConcurrentBag<Marker>(LoadSavedMarkers());
|
FloorMarkers[LastTerritory] = LocalState.Load(LastTerritory) ?? new LocalState(LastTerritory);
|
||||||
EphemeralMarkers.Clear();
|
EphemeralMarkers.Clear();
|
||||||
PomanderOfSight = PomanderState.Inactive;
|
PomanderOfSight = PomanderState.Inactive;
|
||||||
PomanderOfIntuition = PomanderState.Inactive;
|
PomanderOfIntuition = PomanderState.Inactive;
|
||||||
@ -258,11 +262,11 @@ namespace Pal.Client
|
|||||||
saveMarkers = true;
|
saveMarkers = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FloorMarkers.TryGetValue(LastTerritory, out var currentFloorMarkers))
|
if (!FloorMarkers.TryGetValue(LastTerritory, out var currentFloor))
|
||||||
FloorMarkers[LastTerritory] = currentFloorMarkers = new ConcurrentBag<Marker>();
|
FloorMarkers[LastTerritory] = currentFloor = new LocalState(LastTerritory);
|
||||||
|
|
||||||
IList<Marker> visibleMarkers = GetRelevantGameObjects();
|
IList<Marker> visibleMarkers = GetRelevantGameObjects();
|
||||||
HandlePersistentMarkers(currentFloorMarkers, visibleMarkers.Where(x => x.IsPermanent()).ToList(), saveMarkers, recreateLayout);
|
HandlePersistentMarkers(currentFloor, visibleMarkers.Where(x => x.IsPermanent()).ToList(), saveMarkers, recreateLayout);
|
||||||
HandleEphemeralMarkers(visibleMarkers.Where(x => !x.IsPermanent()).ToList(), recreateLayout);
|
HandleEphemeralMarkers(visibleMarkers.Where(x => !x.IsPermanent()).ToList(), recreateLayout);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -271,9 +275,10 @@ namespace Pal.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePersistentMarkers(ConcurrentBag<Marker> currentFloorMarkers, IList<Marker> visibleMarkers, bool saveMarkers, bool recreateLayout)
|
private void HandlePersistentMarkers(LocalState currentFloor, IList<Marker> visibleMarkers, bool saveMarkers, bool recreateLayout)
|
||||||
{
|
{
|
||||||
var config = Service.Configuration;
|
var config = Service.Configuration;
|
||||||
|
var currentFloorMarkers = currentFloor.Markers;
|
||||||
|
|
||||||
foreach (var visibleMarker in visibleMarkers)
|
foreach (var visibleMarker in visibleMarkers)
|
||||||
{
|
{
|
||||||
@ -320,7 +325,7 @@ namespace Pal.Client
|
|||||||
|
|
||||||
if (saveMarkers)
|
if (saveMarkers)
|
||||||
{
|
{
|
||||||
SaveMarkers();
|
currentFloor.Save();
|
||||||
|
|
||||||
if (TerritorySyncState == SyncState.Complete)
|
if (TerritorySyncState == SyncState.Complete)
|
||||||
{
|
{
|
||||||
@ -431,23 +436,6 @@ namespace Pal.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetSaveForCurrentTerritory() => Path.Join(Service.PluginInterface.GetPluginConfigDirectory(), $"{LastTerritory}.json");
|
|
||||||
|
|
||||||
private List<Marker> LoadSavedMarkers()
|
|
||||||
{
|
|
||||||
string path = GetSaveForCurrentTerritory();
|
|
||||||
if (File.Exists(path))
|
|
||||||
return JsonSerializer.Deserialize<List<Marker>>(File.ReadAllText(path), new JsonSerializerOptions { IncludeFields = true }).Where(x => x.Seen || Service.Configuration.Mode == Configuration.EMode.Online).ToList();
|
|
||||||
else
|
|
||||||
return new List<Marker>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveMarkers()
|
|
||||||
{
|
|
||||||
string path = GetSaveForCurrentTerritory();
|
|
||||||
File.WriteAllText(path, JsonSerializer.Serialize(FloorMarkers[LastTerritory], new JsonSerializerOptions { IncludeFields = true }));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DownloadMarkersForTerritory(ushort territoryId)
|
private async Task DownloadMarkersForTerritory(ushort territoryId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -498,18 +486,18 @@ namespace Pal.Client
|
|||||||
while (_remoteDownloads.TryDequeue(out var download))
|
while (_remoteDownloads.TryDequeue(out var download))
|
||||||
{
|
{
|
||||||
var (territoryId, success, downloadedMarkers) = download;
|
var (territoryId, success, downloadedMarkers) = download;
|
||||||
if (Service.Configuration.Mode == Configuration.EMode.Online && success && FloorMarkers.TryGetValue(territoryId, out var currentFloorMarkers) && downloadedMarkers.Count > 0)
|
if (Service.Configuration.Mode == Configuration.EMode.Online && success && FloorMarkers.TryGetValue(territoryId, out var currentFloor) && downloadedMarkers.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var downloadedMarker in downloadedMarkers)
|
foreach (var downloadedMarker in downloadedMarkers)
|
||||||
{
|
{
|
||||||
Marker seenMarker = currentFloorMarkers.SingleOrDefault(x => x == downloadedMarker);
|
Marker seenMarker = currentFloor.Markers.SingleOrDefault(x => x == downloadedMarker);
|
||||||
if (seenMarker != null)
|
if (seenMarker != null)
|
||||||
{
|
{
|
||||||
seenMarker.RemoteSeen = true;
|
seenMarker.RemoteSeen = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentFloorMarkers.Add(downloadedMarker);
|
currentFloor.Markers.Add(downloadedMarker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,16 +149,16 @@ namespace Pal.Client.Windows
|
|||||||
ImGui.Text($"{plugin.DebugMessage}");
|
ImGui.Text($"{plugin.DebugMessage}");
|
||||||
|
|
||||||
ImGui.Indent();
|
ImGui.Indent();
|
||||||
if (plugin.FloorMarkers.TryGetValue(plugin.LastTerritory, out var currentFloorMarkers))
|
if (plugin.FloorMarkers.TryGetValue(plugin.LastTerritory, out var currentFloor))
|
||||||
{
|
{
|
||||||
if (_showTraps)
|
if (_showTraps)
|
||||||
{
|
{
|
||||||
int traps = currentFloorMarkers.Count(x => x != null && x.Type == Marker.EType.Trap);
|
int traps = currentFloor.Markers.Count(x => x != null && x.Type == Marker.EType.Trap);
|
||||||
ImGui.Text($"{traps} known trap{(traps == 1 ? "" : "s")}");
|
ImGui.Text($"{traps} known trap{(traps == 1 ? "" : "s")}");
|
||||||
}
|
}
|
||||||
if (_showHoard)
|
if (_showHoard)
|
||||||
{
|
{
|
||||||
int hoardCoffers = currentFloorMarkers.Count(x => x != null && x.Type == Marker.EType.Hoard);
|
int hoardCoffers = currentFloor.Markers.Count(x => x != null && x.Type == Marker.EType.Hoard);
|
||||||
ImGui.Text($"{hoardCoffers} known hoard coffer{(hoardCoffers == 1 ? "" : "s")}");
|
ImGui.Text($"{hoardCoffers} known hoard coffer{(hoardCoffers == 1 ? "" : "s")}");
|
||||||
}
|
}
|
||||||
if (_showSilverCoffers)
|
if (_showSilverCoffers)
|
||||||
|
Loading…
Reference in New Issue
Block a user