This commit is contained in:
Ottermandias 2023-06-16 16:13:26 +02:00
parent 7463aafa13
commit 27f151c55a
32 changed files with 1744 additions and 151 deletions

View file

@ -1,13 +1,106 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using Dalamud.Configuration;
using Dalamud.Interface.Internal.Notifications;
using Glamourer.Services;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
namespace Glamourer;
public class Configuration : IPluginConfiguration, ISavable
{
public bool UseRestrictedGearProtection = true;
public int Version { get; set; } = 2;
public Dictionary<ColorId, uint> Colors { get; set; }
= Enum.GetValues<ColorId>().ToDictionary(c => c, c => c.Data().DefaultColor);
[JsonIgnore]
private readonly SaveService _saveService;
public Configuration(SaveService saveService, ConfigMigrationService migrator)
{
_saveService = saveService;
Load(migrator);
}
public void Save()
=> _saveService.QueueSave(this);
public void Load(ConfigMigrationService migrator)
{
static void HandleDeserializationError(object? sender, ErrorEventArgs errorArgs)
{
Glamourer.Log.Error(
$"Error parsing Configuration at {errorArgs.ErrorContext.Path}, using default or migrating:\n{errorArgs.ErrorContext.Error}");
errorArgs.ErrorContext.Handled = true;
}
if (!File.Exists(_saveService.FileNames.ConfigFile))
return;
if (File.Exists(_saveService.FileNames.ConfigFile))
try
{
var text = File.ReadAllText(_saveService.FileNames.ConfigFile);
JsonConvert.PopulateObject(text, this, new JsonSerializerSettings
{
Error = HandleDeserializationError,
});
}
catch (Exception ex)
{
Glamourer.ChatService.NotificationMessage(ex,
"Error reading Configuration, reverting to default.\nYou may be able to restore your configuration using the rolling backups in the XIVLauncher/backups/Glamourer directory.",
"Error reading Configuration", "Error", NotificationType.Error);
}
migrator.Migrate(this);
}
public string ToFilename(FilenameService fileNames)
=> fileNames.ConfigFile;
public void Save(StreamWriter writer)
{
using var jWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented };
var serializer = new JsonSerializer { Formatting = Formatting.Indented };
serializer.Serialize(jWriter, this);
}
}
public class ConfigMigrationService
{
private readonly SaveService _saveService;
private Configuration _config = null!;
private JObject _data = null!;
public ConfigMigrationService(SaveService saveService)
=> _saveService = saveService;
public void Migrate(Configuration config)
{
_config = config;
_data = JObject.Parse(File.ReadAllText(_saveService.FileNames.ConfigFile));
MigrateV1To2();
}
private void MigrateV1To2()
{
if (_config.Version > 1)
return;
_config.Version = 2;
}
}
public class ConfigurationOld : IPluginConfiguration, ISavable
{
[JsonIgnore]
private readonly SaveService _saveService;
@ -42,7 +135,7 @@ public class Configuration : IPluginConfiguration, ISavable
public void Save()
=> _saveService.QueueSave(this);
public Configuration(SaveService saveService)
public ConfigurationOld(SaveService saveService)
{
_saveService = saveService;
Load();

View file

@ -75,10 +75,10 @@ public partial class Interface
ImGui.Dummy(_spacing);
DrawColorPicker("Customization Color", "The color for designs that only apply their character customization.",
_config.CustomizationColor, Configuration.DefaultCustomizationColor, c => _config.CustomizationColor = c);
_config.CustomizationColor, ConfigurationOld.DefaultCustomizationColor, c => _config.CustomizationColor = c);
DrawColorPicker("Equipment Color", "The color for designs that only apply some or all of their equipment slots and stains.",
_config.EquipmentColor, Configuration.DefaultEquipmentColor, c => _config.EquipmentColor = c);
_config.EquipmentColor, ConfigurationOld.DefaultEquipmentColor, c => _config.EquipmentColor = c);
DrawColorPicker("State Color", "The color for designs that only apply some state modification.",
_config.StateColor, Configuration.DefaultStateColor, c => _config.StateColor = c);
_config.StateColor, ConfigurationOld.DefaultStateColor, c => _config.StateColor = c);
}
}

View file

@ -23,14 +23,14 @@ public partial class Interface : Window, IDisposable
private readonly EquipmentDrawer _equipmentDrawer;
private readonly CustomizationDrawer _customizationDrawer;
private readonly Configuration _config;
private readonly ConfigurationOld _config;
private readonly ActorTab _actorTab;
private readonly DesignTab _designTab;
private readonly DebugStateTab _debugStateTab;
private readonly DebugDataTab _debugDataTab;
public Interface(DalamudPluginInterface pi, ItemManager items, ActiveDesign.Manager activeDesigns, DesignManager designManager,
DesignFileSystem fileSystem, ObjectManager objects, CustomizationService customization, Configuration config, DataManager gameData, TargetManager targets, ActorService actors, KeyState keyState)
DesignFileSystem fileSystem, ObjectManager objects, CustomizationService customization, ConfigurationOld config, DataManager gameData, TargetManager targets, ActorService actors, KeyState keyState)
: base(GetLabel())
{
_pi = pi;

View file

@ -67,7 +67,7 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
=> Pointer != null;
public int Index
=> Pointer->GameObject.ObjectIndex;
=> Valid ? Pointer->GameObject.ObjectIndex : -1;
public uint ModelId
{

View file

@ -20,14 +20,14 @@ public class ItemManager : IDisposable
public const string SmallClothesNpc = "Smallclothes (NPC)";
public const ushort SmallClothesNpcModel = 9903;
private readonly Configuration _config;
private readonly ConfigurationOld _config;
public readonly IdentifierService IdentifierService;
public readonly ExcelSheet<Item> ItemSheet;
public readonly StainData Stains;
public readonly ItemService ItemService;
public readonly RestrictedGear RestrictedGear;
public ItemManager(DalamudPluginInterface pi, DataManager gameData, IdentifierService identifierService, ItemService itemService, Configuration config)
public ItemManager(DalamudPluginInterface pi, DataManager gameData, IdentifierService identifierService, ItemService itemService, ConfigurationOld config)
{
_config = config;
ItemSheet = gameData.GetExcelSheet<Item>()!;

View file

@ -9,89 +9,12 @@ namespace Glamourer.Services;
/// <summary>
/// Any file type that we want to save via SaveService.
/// </summary>
public interface ISavable
public interface ISavable : ISavable<FilenameService>
{ }
public sealed class SaveService : SaveServiceBase<FilenameService>
{
/// <summary> The full file name of a given object. </summary>
public string ToFilename(FilenameService fileNames);
/// <summary> Write the objects data to the given stream writer. </summary>
public void Save(StreamWriter writer);
/// <summary> An arbitrary message printed to Debug before saving. </summary>
public string LogName(string fileName)
=> fileName;
public string TypeName
=> GetType().Name;
}
public class SaveService
{
private readonly Logger _log;
private readonly FrameworkManager _framework;
public readonly FilenameService FileNames;
public SaveService(Logger log, FrameworkManager framework, FilenameService fileNames)
{
_log = log;
_framework = framework;
FileNames = fileNames;
}
/// <summary> Queue a save for the next framework tick. </summary>
public void QueueSave(ISavable value)
{
var file = value.ToFilename(FileNames);
_framework.RegisterOnTick(value.GetType().Name + file, () =>
{
ImmediateSave(value);
});
}
/// <summary> Immediately trigger a save. </summary>
public void ImmediateSave(ISavable value)
{
var name = value.ToFilename(FileNames);
try
{
if (name.Length == 0)
{
throw new Exception("Invalid object returned empty filename.");
}
_log.Debug($"Saving {value.TypeName} {value.LogName(name)}...");
var file = new FileInfo(name);
file.Directory?.Create();
using var s = file.Exists ? file.Open(FileMode.Truncate) : file.Open(FileMode.CreateNew);
using var w = new StreamWriter(s, Encoding.UTF8);
value.Save(w);
}
catch (Exception ex)
{
_log.Error($"Could not save {value.GetType().Name} {value.LogName(name)}:\n{ex}");
}
}
public void ImmediateDelete(ISavable value)
{
var name = value.ToFilename(FileNames);
try
{
if (name.Length == 0)
{
throw new Exception("Invalid object returned empty filename.");
}
if (!File.Exists(name))
return;
_log.Information($"Deleting {value.GetType().Name} {value.LogName(name)}...");
File.Delete(name);
}
catch (Exception ex)
{
_log.Error($"Could not delete {value.GetType().Name} {value.LogName(name)}:\n{ex}");
}
}
: base(log, framework, fileNames)
{ }
}

View file

@ -42,7 +42,7 @@ public static class ServiceManager
.AddSingleton<ChatService>();
private static IServiceCollection AddConfig(this IServiceCollection services)
=> services.AddSingleton<Configuration>()
=> services.AddSingleton<ConfigurationOld>()
.AddSingleton<BackupService>();
private static IServiceCollection AddPenumbra(this IServiceCollection services)