using System.Text.Json; using System.Text.Json.Serialization; using Dalamud.Plugin; using Dalamud.Plugin.Services; namespace PlayerNotes; /// /// Loads, saves, and validates the PlayerNotes.json data file. The file lives in this /// plugin's config directory (e.g. %APPDATA%\XIVLauncher\plugin_config\PlayerNotes\) /// and is also the export/import format for moving lists between PCs. /// public class Storage { private static readonly JsonSerializerOptions SerializerOptions = new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Users edit this file by hand to manage tags; allow (and ignore) comments. ReadCommentHandling = JsonCommentHandling.Skip, }; private readonly IPluginLog log; public PlayerNotesData Data { get; private set; } = new(); public string FilePath { get; } public Storage(IDalamudPluginInterface pluginInterface, IPluginLog log) { this.log = log; FilePath = Path.Combine(pluginInterface.ConfigFile.Directory!.FullName, "PlayerNotes.json"); Load(); } /// Reads the data file from disk, creating it with defaults if missing. public void Load() { try { if (File.Exists(FilePath)) { Data = Parse(File.ReadAllText(FilePath)); log.Debug($"Loaded player notes from {FilePath}"); } else { Data = new PlayerNotesData(); Save(); // create the file so users can find and edit it (tags etc.) log.Information($"Created new data file at {FilePath}"); } } catch (Exception e) { // Never let a corrupt file kill the plugin; fall back to empty lists. log.Error(e, "Failed to load PlayerNotes.json, starting with empty lists."); Data = new PlayerNotesData(); } } /// Writes the current data to disk. public void Save() { try { File.WriteAllText(FilePath, Serialize(Data)); } catch (Exception e) { log.Error(e, "Failed to save PlayerNotes.json."); } } /// Replaces the in-memory data and persists it (used by import). public void Replace(PlayerNotesData newData) { Data = newData; Save(); } /// Parses a JSON document into validated data. Throws on invalid input. internal static PlayerNotesData Parse(string json) { var data = JsonSerializer.Deserialize(json, SerializerOptions); if (data is null) throw new InvalidDataException("The file does not contain valid player notes data."); data.Normalize(); return data; } internal static string Serialize(PlayerNotesData data) => JsonSerializer.Serialize(data, SerializerOptions); }