Add some delayed saves and UI for that.

This commit is contained in:
Ottermandias 2023-05-09 17:15:19 +02:00
parent e8eff51d84
commit 5ba43c1b19
9 changed files with 58 additions and 20 deletions

@ -1 +1 @@
Subproject commit 4ef03980803cdf5a253c041d6ed1ef26d9a9b938 Subproject commit 6969f4c05b2fab57e0dc30ae249be7c23cd81fa4

View file

@ -170,7 +170,7 @@ public class ActiveCollections : ISavable, IDisposable
public void MoveIndividualCollection(int from, int to) public void MoveIndividualCollection(int from, int to)
{ {
if (Individuals.Move(from, to)) if (Individuals.Move(from, to))
_saveService.QueueSave(this); _saveService.DelaySave(this);
} }
/// <summary> Set and create an active collection, can be used to set Default, Current, Interface, Special, or Individual collections. </summary> /// <summary> Set and create an active collection, can be used to set Default, Current, Interface, Special, or Individual collections. </summary>
@ -318,7 +318,7 @@ public class ActiveCollections : ISavable, IDisposable
} }
else if (collectionType is not CollectionType.Temporary) else if (collectionType is not CollectionType.Temporary)
{ {
_saveService.QueueSave(this); _saveService.DelaySave(this);
} }
} }

View file

@ -205,7 +205,7 @@ public class CollectionEditor
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private void InvokeChange(ModCollection changedCollection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx) private void InvokeChange(ModCollection changedCollection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx)
{ {
_saveService.QueueSave(new ModCollectionSave(_modStorage, changedCollection)); _saveService.DelaySave(new ModCollectionSave(_modStorage, changedCollection));
_communicator.ModSettingChanged.Invoke(changedCollection, type, mod, oldValue, groupIdx, false); _communicator.ModSettingChanged.Invoke(changedCollection, type, mod, oldValue, groupIdx, false);
RecurseInheritors(changedCollection, type, mod, oldValue, groupIdx); RecurseInheritors(changedCollection, type, mod, oldValue, groupIdx);
} }

View file

@ -194,14 +194,14 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable
var any = collection.UnusedSettings.Count > 0; var any = collection.UnusedSettings.Count > 0;
((Dictionary<string, ModSettings.SavedSettings>)collection.UnusedSettings).Clear(); ((Dictionary<string, ModSettings.SavedSettings>)collection.UnusedSettings).Clear();
if (any) if (any)
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection)); _saveService.DelaySave(new ModCollectionSave(_modStorage, collection));
} }
/// <summary> Remove a specific setting for not currently-installed mods from the given collection. </summary> /// <summary> Remove a specific setting for not currently-installed mods from the given collection. </summary>
public void CleanUnavailableSetting(ModCollection collection, string? setting) public void CleanUnavailableSetting(ModCollection collection, string? setting)
{ {
if (setting != null && ((Dictionary<string, ModSettings.SavedSettings>)collection.UnusedSettings).Remove(setting)) if (setting != null && ((Dictionary<string, ModSettings.SavedSettings>)collection.UnusedSettings).Remove(setting))
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection)); _saveService.DelaySave(new ModCollectionSave(_modStorage, collection));
} }
/// <summary> /// <summary>
@ -292,7 +292,7 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
DirectoryInfo? newDirectory) DirectoryInfo? newDirectory)
{ {
switch (type) switch (type)
{ {
case ModPathChangeType.Added: case ModPathChangeType.Added:
foreach (var collection in this) foreach (var collection in this)
@ -304,7 +304,7 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable
break; break;
case ModPathChangeType.Moved: case ModPathChangeType.Moved:
foreach (var collection in this.Where(collection => collection.Settings[mod.Index] != null)) foreach (var collection in this.Where(collection => collection.Settings[mod.Index] != null))
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection)); _saveService.DelaySave(new ModCollectionSave(_modStorage, collection));
break; break;
} }
} }
@ -319,7 +319,7 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable
foreach (var collection in this) foreach (var collection in this)
{ {
if (collection.Settings[mod.Index]?.HandleChanges(type, mod, groupIdx, optionIdx, movedToIdx) ?? false) if (collection.Settings[mod.Index]?.HandleChanges(type, mod, groupIdx, optionIdx, movedToIdx) ?? false)
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection)); _saveService.DelaySave(new ModCollectionSave(_modStorage, collection));
} }
} }
} }

View file

@ -88,7 +88,7 @@ public class InheritanceManager : IDisposable
var parent = inheritor.DirectlyInheritsFrom[idx]; var parent = inheritor.DirectlyInheritsFrom[idx];
((List<ModCollection>)inheritor.DirectlyInheritsFrom).RemoveAt(idx); ((List<ModCollection>)inheritor.DirectlyInheritsFrom).RemoveAt(idx);
((List<ModCollection>)parent.DirectParentOf).Remove(inheritor); ((List<ModCollection>)parent.DirectParentOf).Remove(inheritor);
_saveService.QueueSave(new ModCollectionSave(_modStorage, inheritor)); _saveService.DelaySave(new ModCollectionSave(_modStorage, inheritor));
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false); _communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
RecurseInheritanceChanges(inheritor); RecurseInheritanceChanges(inheritor);
Penumbra.Log.Debug($"Removed {parent.AnonymizedName} from {inheritor.AnonymizedName} inheritances."); Penumbra.Log.Debug($"Removed {parent.AnonymizedName} from {inheritor.AnonymizedName} inheritances.");
@ -100,7 +100,7 @@ public class InheritanceManager : IDisposable
if (!((List<ModCollection>)inheritor.DirectlyInheritsFrom).Move(from, to)) if (!((List<ModCollection>)inheritor.DirectlyInheritsFrom).Move(from, to))
return; return;
_saveService.QueueSave(new ModCollectionSave(_modStorage, inheritor)); _saveService.DelaySave(new ModCollectionSave(_modStorage, inheritor));
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false); _communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
RecurseInheritanceChanges(inheritor); RecurseInheritanceChanges(inheritor);
Penumbra.Log.Debug($"Moved {inheritor.AnonymizedName}s inheritance {from} to {to}."); Penumbra.Log.Debug($"Moved {inheritor.AnonymizedName}s inheritance {from} to {to}.");
@ -116,7 +116,7 @@ public class InheritanceManager : IDisposable
((List<ModCollection>)parent.DirectParentOf).Add(inheritor); ((List<ModCollection>)parent.DirectParentOf).Add(inheritor);
if (invokeEvent) if (invokeEvent)
{ {
_saveService.QueueSave(new ModCollectionSave(_modStorage, inheritor)); _saveService.DelaySave(new ModCollectionSave(_modStorage, inheritor));
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false); _communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
RecurseInheritanceChanges(inheritor); RecurseInheritanceChanges(inheritor);
} }

View file

@ -135,7 +135,7 @@ public class Configuration : IPluginConfiguration, ISavable
/// <summary> Save the current configuration. </summary> /// <summary> Save the current configuration. </summary>
public void Save() public void Save()
=> _saveService.QueueSave(this); => _saveService.DelaySave(this);
/// <summary> Contains some default values or boundaries for config values. </summary> /// <summary> Contains some default values or boundaries for config values. </summary>
public static class Constants public static class Constants

View file

@ -77,7 +77,7 @@ public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable
private void OnChange(FileSystemChangeType type, IPath _1, IPath? _2, IPath? _3) private void OnChange(FileSystemChangeType type, IPath _1, IPath? _2, IPath? _3)
{ {
if (type != FileSystemChangeType.Reload) if (type != FileSystemChangeType.Reload)
_saveService.QueueSave(this); _saveService.DelaySave(this);
} }
// Update sort order when defaulted mod names change. // Update sort order when defaulted mod names change.
@ -112,7 +112,7 @@ public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable
break; break;
case ModPathChangeType.Moved: case ModPathChangeType.Moved:
_saveService.QueueSave(this); _saveService.DelaySave(this);
break; break;
case ModPathChangeType.Reloaded: case ModPathChangeType.Reloaded:
// Nothing // Nothing

View file

@ -29,6 +29,8 @@ public interface ISavable
public class SaveService public class SaveService
{ {
private static readonly TimeSpan StandardDelay = TimeSpan.FromSeconds(30);
private readonly Logger _log; private readonly Logger _log;
private readonly FrameworkManager _framework; private readonly FrameworkManager _framework;
@ -47,7 +49,18 @@ public class SaveService
public void QueueSave(ISavable value) public void QueueSave(ISavable value)
{ {
var file = value.ToFilename(FileNames); var file = value.ToFilename(FileNames);
_framework.RegisterDelayed(value.GetType().Name + file, () => { ImmediateSave(value); }); _framework.RegisterOnTick($"{value.GetType().Name} ## {file}", () => { ImmediateSave(value); });
}
/// <summary> Queue a delayed save with the standard delay for after the delay is over. </summary>
public void DelaySave(ISavable value)
=> DelaySave(value, StandardDelay);
/// <summary> Queue a delayed save for after the delay is over. </summary>
public void DelaySave(ISavable value, TimeSpan delay)
{
var file = value.ToFilename(FileNames);
_framework.RegisterDelayed($"{value.GetType().Name} ## {file}", () => { ImmediateSave(value); }, delay);
} }
/// <summary> Immediately trigger a save. </summary> /// <summary> Immediately trigger a save. </summary>

View file

@ -10,6 +10,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Classes;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.Api; using Penumbra.Api;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
@ -55,13 +56,14 @@ public class DebugTab : Window, ITab
private readonly CutsceneService _cutsceneService; private readonly CutsceneService _cutsceneService;
private readonly ModImportManager _modImporter; private readonly ModImportManager _modImporter;
private readonly ImportPopup _importPopup; private readonly ImportPopup _importPopup;
private readonly FrameworkManager _framework;
public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager, public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager,
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService, ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService,
DalamudServices dalamud, StainService stains, CharacterUtility characterUtility, ResidentResourceManager residentResources, DalamudServices dalamud, StainService stains, CharacterUtility characterUtility, ResidentResourceManager residentResources,
ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver, ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver,
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache, DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup) CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework)
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse, false) : base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse, false)
{ {
IsOpen = true; IsOpen = true;
@ -92,6 +94,7 @@ public class DebugTab : Window, ITab
_cutsceneService = cutsceneService; _cutsceneService = cutsceneService;
_modImporter = modImporter; _modImporter = modImporter;
_importPopup = importPopup; _importPopup = importPopup;
_framework = framework;
} }
public ReadOnlySpan<byte> Label public ReadOnlySpan<byte> Label
@ -209,10 +212,10 @@ public class DebugTab : Window, ITab
if (table) if (table)
{ {
var importing = _modImporter.IsImporting(out var importer); var importing = _modImporter.IsImporting(out var importer);
PrintValue("Is Importing", importing.ToString()); PrintValue("Is Importing", importing.ToString());
PrintValue("Importer State", (importer?.State ?? ImporterState.None).ToString()); PrintValue("Importer State", (importer?.State ?? ImporterState.None).ToString());
PrintValue("Import Window Was Drawn", _importPopup.WasDrawn.ToString()); PrintValue("Import Window Was Drawn", _importPopup.WasDrawn.ToString());
PrintValue("Import Popup Was Drawn", _importPopup.PopupWasDrawn.ToString()); PrintValue("Import Popup Was Drawn", _importPopup.PopupWasDrawn.ToString());
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextUnformatted("Import Batches"); ImGui.TextUnformatted("Import Batches");
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@ -234,6 +237,28 @@ public class DebugTab : Window, ITab
} }
} }
} }
using (var tree = TreeNode("Framework"))
{
if (tree)
{
using var table = Table("##DebugFramework", 2, ImGuiTableFlags.SizingFixedFit);
if (table)
{
foreach(var important in _framework.Important)
PrintValue(important, "Immediate");
foreach (var (onTick, idx) in _framework.OnTick.WithIndex())
PrintValue(onTick, $"{idx + 1} Tick(s) From Now");
foreach (var (time, name) in _framework.Delayed)
{
var span = time - DateTime.UtcNow;
PrintValue(name, $"After {span.Minutes:D2}:{span.Seconds:D2}.{span.Milliseconds / 10:D2} (+ Ticks)");
}
}
}
}
} }
private void DrawPerformanceTab() private void DrawPerformanceTab()