Fix inheritance save issues and sort mod settings on collection save.

This commit is contained in:
Ottermandias 2023-05-19 21:50:01 +02:00
parent 4298b46130
commit 5567134a56
5 changed files with 43 additions and 63 deletions

View file

@ -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<ModCollection>, IDisposable
return true;
}
/// <summary> Stored after loading to be consumed and passed to the inheritance manager later. </summary>
private List<IReadOnlyList<string>>? _inheritancesByName = new();
/// <summary> Return an enumerable of collections and the collections they should inherit. </summary>
public IEnumerable<(ModCollection Collection, IReadOnlyList<ModCollection> 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<ModCollection>();
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);
}
}
/// <summary> Remove all settings for not currently-installed mods from the given collection. </summary>
public void CleanUnavailableSettings(ModCollection collection)
{
@ -218,9 +182,6 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable
/// </summary>
private void ReadCollections(out ModCollection defaultNamedCollection)
{
_inheritancesByName?.Clear();
_inheritancesByName?.Add(Array.Empty<string>()); // 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<ModCollection>, 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);
}

View file

@ -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
/// </summary>
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));
}
}

View file

@ -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
/// <summary> Settings for deleted mods will be kept via the mods identifier (directory name). </summary>
public readonly IReadOnlyDictionary<string, ModSettings.SavedSettings> UnusedSettings;
/// <summary> Inheritances stored before they can be applied. </summary>
public IReadOnlyList<string>? InheritanceByName;
/// <summary> Contains all direct parent collections this collection inherits settings from. </summary>
public readonly IReadOnlyList<ModCollection> DirectlyInheritsFrom;
@ -115,10 +117,13 @@ public partial class ModCollection
/// <summary> Constructor for reading from files. </summary>
public static ModCollection CreateFromData(SaveService saver, ModStorage mods, string name, int version, int index,
Dictionary<string, ModSettings.SavedSettings> allSettings)
Dictionary<string, ModSettings.SavedSettings> allSettings, IReadOnlyList<string> inheritances)
{
Debug.Assert(index > 0, "Collection read with non-positive index.");
var ret = new ModCollection(name, index, 0, version, new List<ModSettings?>(), new List<ModCollection>(), allSettings);
var ret = new ModCollection(name, index, 0, version, new List<ModSettings?>(), new List<ModCollection>(), allSettings)
{
InheritanceByName = inheritances,
};
ret.ApplyModSettings(saver, mods);
ModCollectionMigration.Migrate(saver, mods, version, ret);
return ret;

View file

@ -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();
}

View file

@ -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<string>());
_saveService.ImmediateSave(new ModCollectionSave(emptyStorage, collection));
}
catch (Exception e)