From 5567134a568782b683313f68e3b25f3fd2a3fe37 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 19 May 2023 21:50:01 +0200 Subject: [PATCH] Fix inheritance save issues and sort mod settings on collection save. --- .../Collections/Manager/CollectionStorage.cs | 43 +------------------ .../Collections/Manager/InheritanceManager.cs | 35 ++++++++++----- Penumbra/Collections/ModCollection.cs | 11 +++-- Penumbra/Collections/ModCollectionSave.cs | 15 ++++--- Penumbra/Services/ConfigMigrationService.cs | 2 +- 5 files changed, 43 insertions(+), 63 deletions(-) diff --git a/Penumbra/Collections/Manager/CollectionStorage.cs b/Penumbra/Collections/Manager/CollectionStorage.cs index 2c2b9f24..0a6b95a8 100644 --- a/Penumbra/Collections/Manager/CollectionStorage.cs +++ b/Penumbra/Collections/Manager/CollectionStorage.cs @@ -11,7 +11,6 @@ using Penumbra.Communication; using Penumbra.Mods; using Penumbra.Mods.Manager; using Penumbra.Services; -using Penumbra.Util; namespace Penumbra.Collections.Manager; @@ -153,41 +152,6 @@ public class CollectionStorage : IReadOnlyList, IDisposable return true; } - /// Stored after loading to be consumed and passed to the inheritance manager later. - private List>? _inheritancesByName = new(); - - /// Return an enumerable of collections and the collections they should inherit. - public IEnumerable<(ModCollection Collection, IReadOnlyList Inheritance, bool LoadChanges)> ConsumeInheritanceNames() - { - if (_inheritancesByName == null) - throw new Exception("Inheritances were already consumed. This method can not be called twice."); - - var inheritances = _inheritancesByName; - _inheritancesByName = null; - var list = new List(); - foreach (var (collection, inheritance) in _collections.Zip(inheritances)) - { - list.Clear(); - var changes = false; - foreach (var subCollectionName in inheritance) - { - if (ByName(subCollectionName, out var subCollection)) - { - list.Add(subCollection); - } - else - { - Penumbra.ChatService.NotificationMessage( - $"Inherited collection {subCollectionName} for {collection.AnonymizedName} does not exist, it was removed.", "Warning", - NotificationType.Warning); - changes = true; - } - } - - yield return (collection, list, changes); - } - } - /// Remove all settings for not currently-installed mods from the given collection. public void CleanUnavailableSettings(ModCollection collection) { @@ -218,9 +182,6 @@ public class CollectionStorage : IReadOnlyList, IDisposable /// private void ReadCollections(out ModCollection defaultNamedCollection) { - _inheritancesByName?.Clear(); - _inheritancesByName?.Add(Array.Empty()); // None. - foreach (var file in _saveService.FileNames.CollectionFiles) { if (!ModCollectionSave.LoadFromFile(file, out var name, out var version, out var settings, out var inheritance)) @@ -241,13 +202,11 @@ public class CollectionStorage : IReadOnlyList, IDisposable continue; } - var collection = ModCollection.CreateFromData(_saveService, _modStorage, name, version, Count, settings); + var collection = ModCollection.CreateFromData(_saveService, _modStorage, name, version, Count, settings, inheritance); var correctName = _saveService.FileNames.CollectionFile(collection); if (file.FullName != correctName) Penumbra.ChatService.NotificationMessage($"Collection {file.Name} does not correspond to {collection.Name}.", "Warning", NotificationType.Warning); - - _inheritancesByName?.Add(inheritance); _collections.Add(collection); } diff --git a/Penumbra/Collections/Manager/InheritanceManager.cs b/Penumbra/Collections/Manager/InheritanceManager.cs index 93dee89f..ca17a87d 100644 --- a/Penumbra/Collections/Manager/InheritanceManager.cs +++ b/Penumbra/Collections/Manager/InheritanceManager.cs @@ -7,6 +7,7 @@ using OtterGui.Filesystem; using Penumbra.Communication; using Penumbra.Mods.Manager; using Penumbra.Services; +using Penumbra.UI.CollectionTab; using Penumbra.Util; namespace Penumbra.Collections.Manager; @@ -131,20 +132,34 @@ public class InheritanceManager : IDisposable /// private void ApplyInheritances() { - foreach (var (collection, directParents, changes) in _storage.ConsumeInheritanceNames()) + foreach (var collection in _storage) { - var localChanges = changes; - foreach (var parent in directParents) - { - if (AddInheritance(collection, parent, false)) - continue; + if (collection.InheritanceByName == null) + continue; - localChanges = true; - Penumbra.ChatService.NotificationMessage($"{collection.Name} can not inherit from {parent.Name}, removed.", "Warning", - NotificationType.Warning); + var changes = false; + foreach (var subCollectionName in collection.InheritanceByName) + { + if (_storage.ByName(subCollectionName, out var subCollection)) + { + if (AddInheritance(collection, subCollection, false)) + continue; + + changes = true; + Penumbra.ChatService.NotificationMessage($"{collection.Name} can not inherit from {subCollection.Name}, removed.", "Warning", + NotificationType.Warning); + } + else + { + Penumbra.ChatService.NotificationMessage( + $"Inherited collection {subCollectionName} for {collection.AnonymizedName} does not exist, it was removed.", "Warning", + NotificationType.Warning); + changes = true; + } } - if (localChanges) + collection.InheritanceByName = null; + if (changes) _saveService.ImmediateSave(new ModCollectionSave(_modStorage, collection)); } } diff --git a/Penumbra/Collections/ModCollection.cs b/Penumbra/Collections/ModCollection.cs index 32e7b0b3..fc333747 100644 --- a/Penumbra/Collections/ModCollection.cs +++ b/Penumbra/Collections/ModCollection.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Penumbra.Mods.Manager; -using Penumbra.Util; using Penumbra.Collections.Manager; using Penumbra.Services; @@ -58,6 +57,9 @@ public partial class ModCollection /// Settings for deleted mods will be kept via the mods identifier (directory name). public readonly IReadOnlyDictionary UnusedSettings; + + /// Inheritances stored before they can be applied. + public IReadOnlyList? InheritanceByName; /// Contains all direct parent collections this collection inherits settings from. public readonly IReadOnlyList DirectlyInheritsFrom; @@ -115,10 +117,13 @@ public partial class ModCollection /// Constructor for reading from files. public static ModCollection CreateFromData(SaveService saver, ModStorage mods, string name, int version, int index, - Dictionary allSettings) + Dictionary allSettings, IReadOnlyList inheritances) { Debug.Assert(index > 0, "Collection read with non-positive index."); - var ret = new ModCollection(name, index, 0, version, new List(), new List(), allSettings); + var ret = new ModCollection(name, index, 0, version, new List(), new List(), allSettings) + { + InheritanceByName = inheritances, + }; ret.ApplyModSettings(saver, mods); ModCollectionMigration.Migrate(saver, mods, version, ret); return ret; diff --git a/Penumbra/Collections/ModCollectionSave.cs b/Penumbra/Collections/ModCollectionSave.cs index 6bb1a5af..72b2e94c 100644 --- a/Penumbra/Collections/ModCollectionSave.cs +++ b/Penumbra/Collections/ModCollectionSave.cs @@ -48,17 +48,18 @@ internal readonly struct ModCollectionSave : ISavable // Write all used and unused settings by mod directory name. j.WriteStartObject(); + var list = new List<(string, ModSettings.SavedSettings)>(_modCollection.Settings.Count + _modCollection.UnusedSettings.Count); for (var i = 0; i < _modCollection.Settings.Count; ++i) { var settings = _modCollection.Settings[i]; if (settings != null) - { - j.WritePropertyName(_modStorage[i].ModPath.Name); - x.Serialize(j, new ModSettings.SavedSettings(settings, _modStorage[i])); - } + list.Add((_modStorage[i].ModPath.Name, new ModSettings.SavedSettings(settings, _modStorage[i]))); } - foreach (var (modDir, settings) in _modCollection.UnusedSettings) + list.AddRange(_modCollection.UnusedSettings.Select(kvp => (kvp.Key, kvp.Value))); + list.Sort((a, b) => string.Compare(a.Item1, b.Item1, StringComparison.OrdinalIgnoreCase)); + + foreach (var (modDir, settings) in list) { j.WritePropertyName(modDir); x.Serialize(j, settings); @@ -67,8 +68,8 @@ internal readonly struct ModCollectionSave : ISavable j.WriteEndObject(); // Inherit by collection name. - j.WritePropertyName("Inheritance"); - x.Serialize(j, _modCollection.DirectlyInheritsFrom.Select(c => c.Name)); + j.WritePropertyName("Inheritance"); + x.Serialize(j, _modCollection.InheritanceByName ?? _modCollection.DirectlyInheritsFrom.Select(c => c.Name)); j.WriteEndObject(); } diff --git a/Penumbra/Services/ConfigMigrationService.cs b/Penumbra/Services/ConfigMigrationService.cs index 33f41deb..8c0a60f1 100644 --- a/Penumbra/Services/ConfigMigrationService.cs +++ b/Penumbra/Services/ConfigMigrationService.cs @@ -333,7 +333,7 @@ public class ConfigMigrationService dict = dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value with { Priority = maxPriority - kvp.Value.Priority }); var emptyStorage = new ModStorage(); - var collection = ModCollection.CreateFromData(_saveService, emptyStorage, ModCollection.DefaultCollectionName, 0, 1, dict); + var collection = ModCollection.CreateFromData(_saveService, emptyStorage, ModCollection.DefaultCollectionName, 0, 1, dict, Array.Empty()); _saveService.ImmediateSave(new ModCollectionSave(emptyStorage, collection)); } catch (Exception e)