diff --git a/Penumbra/Collections/Cache/CollectionCacheManager.cs b/Penumbra/Collections/Cache/CollectionCacheManager.cs index 001ea952..fc43f654 100644 --- a/Penumbra/Collections/Cache/CollectionCacheManager.cs +++ b/Penumbra/Collections/Cache/CollectionCacheManager.cs @@ -51,6 +51,8 @@ public class CollectionCacheManager : IDisposable _communicator.ModOptionChanged.Subscribe(OnModOptionChange, -100); _communicator.ModSettingChanged.Subscribe(OnModSettingChange); _communicator.CollectionInheritanceChanged.Subscribe(OnCollectionInheritanceChange); + _communicator.ModDiscoveryStarted.Subscribe(OnModDiscoveryStarted); + _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, -100); if (!MetaFileManager.CharacterUtility.Ready) MetaFileManager.CharacterUtility.LoadingFinished += IncrementCounters; @@ -308,4 +310,20 @@ public class CollectionCacheManager : IDisposable Penumbra.Log.Debug($"Creating {tasks.Length} necessary caches."); Task.WaitAll(tasks); } + + private void OnModDiscoveryStarted() + { + foreach (var collection in Active) + { + collection._cache!.ResolvedFiles.Clear(); + collection._cache!.Meta.Reset(); + collection._cache!._conflicts.Clear(); + } + } + + private void OnModDiscoveryFinished() + { + var tasks = Active.Select(c => Task.Run(() => CalculateEffectiveFileListInternal(c))).ToArray(); + Task.WaitAll(tasks); + } } diff --git a/Penumbra/Mods/Manager/ModCacheManager.cs b/Penumbra/Mods/Manager/ModCacheManager.cs index 86a26960..1015e4ed 100644 --- a/Penumbra/Mods/Manager/ModCacheManager.cs +++ b/Penumbra/Mods/Manager/ModCacheManager.cs @@ -168,10 +168,10 @@ public class ModCacheManager : IDisposable => mod.TotalFileCount = mod.AllSubMods.Sum(s => s.Files.Count); private static void UpdateSwapCount(Mod mod) - => mod.TotalFileCount = mod.AllSubMods.Sum(s => s.FileSwaps.Count); + => mod.TotalSwapCount = mod.AllSubMods.Sum(s => s.FileSwaps.Count); private static void UpdateMetaCount(Mod mod) - => mod.TotalFileCount = mod.AllSubMods.Sum(s => s.Manipulations.Count); + => mod.TotalManipulations = mod.AllSubMods.Sum(s => s.Manipulations.Count); private static void UpdateHasOptions(Mod mod) => mod.HasOptions = mod.Groups.Any(o => o.IsOption); diff --git a/Penumbra/Mods/Manager/ModManager.cs b/Penumbra/Mods/Manager/ModManager.cs index 2ef1c890..8b25f763 100644 --- a/Penumbra/Mods/Manager/ModManager.cs +++ b/Penumbra/Mods/Manager/ModManager.cs @@ -29,7 +29,7 @@ public enum ModPathChangeType StartingReload, } -public sealed class ModManager : ModStorage +public sealed class ModManager : ModStorage, IDisposable { private readonly Configuration _config; private readonly CommunicatorService _communicator; @@ -49,7 +49,8 @@ public sealed class ModManager : ModStorage DataEditor = dataEditor; OptionEditor = optionEditor; Creator = creator; - SetBaseDirectory(config.ModDirectory, true); + SetBaseDirectory(config.ModDirectory, true); + _communicator.ModPathChanged.Subscribe(OnModPathChange); DiscoverMods(); } @@ -66,7 +67,7 @@ public sealed class ModManager : ModStorage public void DiscoverMods() { _communicator.ModDiscoveryStarted.Invoke(); - NewMods.Clear(); + ClearNewMods(); Mods.Clear(); BasePath.Refresh(); @@ -243,11 +244,11 @@ public sealed class ModManager : ModStorage { switch (type) { - case ModPathChangeType.Added: - NewMods.Add(mod); + case ModPathChangeType.Added: + SetNew(mod); break; case ModPathChangeType.Deleted: - NewMods.Remove(mod); + SetKnown(mod); break; case ModPathChangeType.Moved: if (oldDirectory != null && newDirectory != null) @@ -258,7 +259,7 @@ public sealed class ModManager : ModStorage } public void Dispose() - { } + => _communicator.ModPathChanged.Unsubscribe(OnModPathChange); /// /// Set the mod base directory. diff --git a/Penumbra/Mods/Manager/ModOptionEditor.cs b/Penumbra/Mods/Manager/ModOptionEditor.cs index ed978000..c30d90c3 100644 --- a/Penumbra/Mods/Manager/ModOptionEditor.cs +++ b/Penumbra/Mods/Manager/ModOptionEditor.cs @@ -314,7 +314,7 @@ public class ModOptionEditor return; _communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1); - subMod.ManipulationData = manipulations; + subMod.ManipulationData.SetTo(manipulations); _saveService.QueueSave(new ModSaveGroup(mod, groupIdx)); _communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, mod, groupIdx, optionIdx, -1); } @@ -327,7 +327,7 @@ public class ModOptionEditor return; _communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1); - subMod.FileData = replacements; + subMod.FileData.SetTo(replacements); _saveService.QueueSave(new ModSaveGroup(mod, groupIdx)); _communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionFilesChanged, mod, groupIdx, optionIdx, -1); } @@ -353,7 +353,7 @@ public class ModOptionEditor return; _communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1); - subMod.FileSwapData = swaps; + subMod.FileSwapData.SetTo(swaps); _saveService.QueueSave(new ModSaveGroup(mod, groupIdx)); _communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionSwapsChanged, mod, groupIdx, optionIdx, -1); } diff --git a/Penumbra/Mods/Manager/ModStorage.cs b/Penumbra/Mods/Manager/ModStorage.cs index 3aa6d31f..5e8999d7 100644 --- a/Penumbra/Mods/Manager/ModStorage.cs +++ b/Penumbra/Mods/Manager/ModStorage.cs @@ -53,14 +53,17 @@ public class ModStorage : IReadOnlyList /// Mods are removed when they are deleted or when they are toggled in any collection. /// Also gets cleared on mod rediscovery. /// - protected readonly HashSet NewMods = new(); + private readonly HashSet _newMods = new(); public bool IsNew(Mod mod) - => NewMods.Contains(mod); + => _newMods.Contains(mod); public void SetNew(Mod mod) - => NewMods.Add(mod); + => _newMods.Add(mod); public void SetKnown(Mod mod) - => NewMods.Remove(mod); + => _newMods.Remove(mod); + + public void ClearNewMods() + => _newMods.Clear(); } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs index d9bebeaf..211acc85 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs @@ -414,7 +414,7 @@ public partial class ModEditWindow : Window, IDisposable if (ImGuiUtil.DrawDisabledButton("Revert Changes", Vector2.Zero, tt, setsEqual)) _editor.SwapEditor.Revert(_editor.Option!); - var otherSwaps = _editor.Mod!.TotalSwapCount - _editor.SwapEditor.Swaps.Count; + var otherSwaps = _editor.Mod!.TotalSwapCount - _editor.Option!.FileSwaps.Count; if (otherSwaps > 0) { ImGui.SameLine(); diff --git a/Penumbra/Util/DictionaryExtensions.cs b/Penumbra/Util/DictionaryExtensions.cs index ad832457..31931fe7 100644 --- a/Penumbra/Util/DictionaryExtensions.cs +++ b/Penumbra/Util/DictionaryExtensions.cs @@ -6,7 +6,7 @@ namespace Penumbra.Util; public static class DictionaryExtensions { - // Returns whether two dictionaries contain equal keys and values. + /// Returns whether two dictionaries contain equal keys and values. public static bool SetEquals< TKey, TValue >( this IReadOnlyDictionary< TKey, TValue > lhs, IReadOnlyDictionary< TKey, TValue > rhs ) { if( ReferenceEquals( lhs, rhs ) ) @@ -46,24 +46,32 @@ public static class DictionaryExtensions return true; } - // Set one dictionary to the other, deleting previous entries and ensuring capacity beforehand. + /// Set one dictionary to the other, deleting previous entries and ensuring capacity beforehand. public static void SetTo< TKey, TValue >( this Dictionary< TKey, TValue > lhs, IReadOnlyDictionary< TKey, TValue > rhs ) where TKey : notnull { if( ReferenceEquals( lhs, rhs ) ) - { return; - } lhs.Clear(); lhs.EnsureCapacity( rhs.Count ); foreach( var (key, value) in rhs ) - { lhs.Add( key, value ); - } } - // Add all entries from the other dictionary that would not overwrite current keys. + /// Set one set to the other, deleting previous entries and ensuring capacity beforehand. + public static void SetTo(this HashSet lhs, IReadOnlySet rhs) + { + if (ReferenceEquals(lhs, rhs)) + return; + + lhs.Clear(); + lhs.EnsureCapacity(rhs.Count); + foreach (var value in rhs) + lhs.Add(value); + } + + /// Add all entries from the other dictionary that would not overwrite current keys. public static void AddFrom< TKey, TValue >( this Dictionary< TKey, TValue > lhs, IReadOnlyDictionary< TKey, TValue > rhs ) where TKey : notnull {