diff --git a/Penumbra/Collections/ModCollection.Cache.cs b/Penumbra/Collections/ModCollection.Cache.cs index e25f65bf..576652ed 100644 --- a/Penumbra/Collections/ModCollection.Cache.cs +++ b/Penumbra/Collections/ModCollection.Cache.cs @@ -321,7 +321,7 @@ internal class ModCollectionCache : IDisposable if( addMetaChanges ) { ++_collection.ChangeCounter; - if( mod.TotalManipulations > 0 ) + if(Penumbra.ModCaches[mod.Index].TotalManipulations > 0 ) { AddMetaFiles(); } @@ -533,7 +533,7 @@ internal class ModCollectionCache : IDisposable foreach( var (manip, mod) in MetaManipulations ) { - Mod.ComputeChangedItems( items, manip ); + ModCacheManager.ComputeChangedItems(identifier, items, manip ); AddItems( mod ); } } diff --git a/Penumbra/Mods/Editor/IMod.cs b/Penumbra/Mods/Editor/IMod.cs index 5b7b0f20..658922cf 100644 --- a/Penumbra/Mods/Editor/IMod.cs +++ b/Penumbra/Mods/Editor/IMod.cs @@ -10,8 +10,6 @@ public interface IMod public int Index { get; } public int Priority { get; } - public int TotalManipulations { get; } - public ISubMod Default { get; } public IReadOnlyList< IModGroup > Groups { get; } diff --git a/Penumbra/Mods/Editor/ModNormalizer.cs b/Penumbra/Mods/Editor/ModNormalizer.cs index bdd968cd..604fc9e5 100644 --- a/Penumbra/Mods/Editor/ModNormalizer.cs +++ b/Penumbra/Mods/Editor/ModNormalizer.cs @@ -12,6 +12,7 @@ namespace Penumbra.Mods; public class ModNormalizer { private readonly ModManager _modManager; + private readonly ModCacheManager _modCacheManager; private readonly List>> _redirections = new(); public Mod Mod { get; private set; } = null!; @@ -24,8 +25,11 @@ public class ModNormalizer public bool Running => Step < TotalSteps; - public ModNormalizer(ModManager modManager) - => _modManager = modManager; + public ModNormalizer(ModManager modManager, ModCacheManager modCacheManager) + { + _modManager = modManager; + _modCacheManager = modCacheManager; + } public void Normalize(Mod mod) { @@ -36,7 +40,7 @@ public class ModNormalizer _normalizationDirName = Path.Combine(Mod.ModPath.FullName, "TmpNormalization"); _oldDirName = Path.Combine(Mod.ModPath.FullName, "TmpNormalizationOld"); Step = 0; - TotalSteps = mod.TotalFileCount + 5; + TotalSteps = _modCacheManager[mod].TotalFileCount + 5; Task.Run(NormalizeSync); } diff --git a/Penumbra/Mods/Manager/ModOptionEditor.cs b/Penumbra/Mods/Manager/ModOptionEditor.cs index 88cc9e75..8e96b3e2 100644 --- a/Penumbra/Mods/Manager/ModOptionEditor.cs +++ b/Penumbra/Mods/Manager/ModOptionEditor.cs @@ -32,7 +32,6 @@ public class ModOptionEditor mod._groups[groupIdx] = group.Convert(type); _saveService.QueueSave(new ModSaveGroup(mod, groupIdx)); - mod.HasOptions = mod.Groups.Any(o => o.IsOption); _communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupTypeChanged, mod, groupIdx, -1, -1); } diff --git a/Penumbra/Mods/Mod.BasePath.cs b/Penumbra/Mods/Mod.BasePath.cs index 41da763b..e7f1da0b 100644 --- a/Penumbra/Mods/Mod.BasePath.cs +++ b/Penumbra/Mods/Mod.BasePath.cs @@ -76,8 +76,6 @@ public partial class Mod IncorporateAllMetaChanges(true); } - ComputeChangedItems(); - SetCounts(); return true; } diff --git a/Penumbra/Mods/Mod.ChangedItems.cs b/Penumbra/Mods/Mod.ChangedItems.cs deleted file mode 100644 index cdffcee9..00000000 --- a/Penumbra/Mods/Mod.ChangedItems.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Penumbra.GameData.Data; -using Penumbra.GameData.Enums; -using Penumbra.Meta.Manipulations; - -namespace Penumbra.Mods; - -public sealed partial class Mod -{ - public SortedList< string, object? > ChangedItems { get; } = new(); - public string LowerChangedItemsString { get; private set; } = string.Empty; - - internal void ComputeChangedItems() - { - ChangedItems.Clear(); - foreach( var gamePath in AllRedirects ) - { - Penumbra.Identifier.Identify( ChangedItems, gamePath.ToString() ); - } - - foreach( var manip in AllManipulations ) - { - ComputeChangedItems( ChangedItems, manip ); - } - - LowerChangedItemsString = string.Join( "\0", ChangedItems.Keys.Select( k => k.ToLowerInvariant() ) ); - } - - public static void ComputeChangedItems( SortedList< string, object? > changedItems, MetaManipulation manip ) - { - switch( manip.ManipulationType ) - { - case MetaManipulation.Type.Imc: - switch( manip.Imc.ObjectType ) - { - case ObjectType.Equipment: - case ObjectType.Accessory: - Penumbra.Identifier.Identify( changedItems, - GamePaths.Equipment.Mtrl.Path( manip.Imc.PrimaryId, GenderRace.MidlanderMale, manip.Imc.EquipSlot, manip.Imc.Variant, "a" ) ); - break; - case ObjectType.Weapon: - Penumbra.Identifier.Identify( changedItems, GamePaths.Weapon.Mtrl.Path( manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.Variant, "a" ) ); - break; - case ObjectType.DemiHuman: - Penumbra.Identifier.Identify( changedItems, - GamePaths.DemiHuman.Mtrl.Path( manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.EquipSlot, manip.Imc.Variant, "a" ) ); - break; - case ObjectType.Monster: - Penumbra.Identifier.Identify( changedItems, GamePaths.Monster.Mtrl.Path( manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.Variant, "a" ) ); - break; - } - - break; - case MetaManipulation.Type.Eqdp: - Penumbra.Identifier.Identify( changedItems, - GamePaths.Equipment.Mdl.Path( manip.Eqdp.SetId, Names.CombinedRace( manip.Eqdp.Gender, manip.Eqdp.Race ), manip.Eqdp.Slot ) ); - break; - case MetaManipulation.Type.Eqp: - Penumbra.Identifier.Identify( changedItems, GamePaths.Equipment.Mdl.Path( manip.Eqp.SetId, GenderRace.MidlanderMale, manip.Eqp.Slot ) ); - break; - case MetaManipulation.Type.Est: - switch( manip.Est.Slot ) - { - case EstManipulation.EstType.Hair: - changedItems.TryAdd( $"Customization: {manip.Est.Race} {manip.Est.Gender} Hair (Hair) {manip.Est.SetId}", null ); - break; - case EstManipulation.EstType.Face: - changedItems.TryAdd( $"Customization: {manip.Est.Race} {manip.Est.Gender} Face (Face) {manip.Est.SetId}", null ); - break; - case EstManipulation.EstType.Body: - Penumbra.Identifier.Identify( changedItems, - GamePaths.Equipment.Mdl.Path( manip.Est.SetId, Names.CombinedRace( manip.Est.Gender, manip.Est.Race ), EquipSlot.Body ) ); - break; - case EstManipulation.EstType.Head: - Penumbra.Identifier.Identify( changedItems, - GamePaths.Equipment.Mdl.Path( manip.Est.SetId, Names.CombinedRace( manip.Est.Gender, manip.Est.Race ), EquipSlot.Head ) ); - break; - } - - break; - case MetaManipulation.Type.Gmp: - Penumbra.Identifier.Identify( changedItems, GamePaths.Equipment.Mdl.Path( manip.Gmp.SetId, GenderRace.MidlanderMale, EquipSlot.Head ) ); - break; - case MetaManipulation.Type.Rsp: - changedItems.TryAdd( $"{manip.Rsp.SubRace.ToName()} {manip.Rsp.Attribute.ToFullString()}", null ); - break; - } - } -} \ No newline at end of file diff --git a/Penumbra/Mods/Mod.Files.cs b/Penumbra/Mods/Mod.Files.cs index bd11d477..078e5a95 100644 --- a/Penumbra/Mods/Mod.Files.cs +++ b/Penumbra/Mods/Mod.Files.cs @@ -20,29 +20,6 @@ public partial class Mod internal readonly SubMod _default; internal readonly List _groups = new(); - public int TotalFileCount { get; internal set; } - public int TotalSwapCount { get; internal set; } - public int TotalManipulations { get; internal set; } - public bool HasOptions { get; internal set; } - - internal bool SetCounts() - { - TotalFileCount = 0; - TotalSwapCount = 0; - TotalManipulations = 0; - foreach (var s in AllSubMods) - { - TotalFileCount += s.Files.Count; - TotalSwapCount += s.FileSwaps.Count; - TotalManipulations += s.Manipulations.Count; - } - - HasOptions = _groups.Any(o - => o is MultiModGroup m && m.PrioritizedOptions.Count > 0 - || o is SingleModGroup s && s.OptionData.Count > 1); - return true; - } - public IEnumerable AllSubMods => _groups.SelectMany(o => o).Prepend(_default); diff --git a/Penumbra/Mods/Mod.LocalData.cs b/Penumbra/Mods/Mod.LocalData.cs index 1c0ae1e0..af79191f 100644 --- a/Penumbra/Mods/Mod.LocalData.cs +++ b/Penumbra/Mods/Mod.LocalData.cs @@ -15,7 +15,6 @@ public sealed partial class Mod public IReadOnlyList LocalTags { get; private set; } = Array.Empty(); - public string AllTagsLower { get; private set; } = string.Empty; public string Note { get; internal set; } = string.Empty; public bool Favorite { get; internal set; } = false; @@ -46,9 +45,6 @@ public sealed partial class Mod } } - if (type != 0) - AllTagsLower = string.Join('\0', ModTags.Concat(LocalTags).Select(s => s.ToLowerInvariant())); - return type; } diff --git a/Penumbra/Mods/ModCacheManager.cs b/Penumbra/Mods/ModCacheManager.cs index 632c5a31..365ac52e 100644 --- a/Penumbra/Mods/ModCacheManager.cs +++ b/Penumbra/Mods/ModCacheManager.cs @@ -36,7 +36,7 @@ public class ModCacheManager : IDisposable, IReadOnlyList } public IEnumerator GetEnumerator() - => _cache.GetEnumerator(); + => _cache.Take(Count).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 283de2bb..dc7f78a6 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -49,6 +49,7 @@ public class Penumbra : IDalamudPlugin public static GameEventManager GameEvents { get; private set; } = null!; public static MetaFileManager MetaFileManager { get; private set; } = null!; public static ModManager ModManager { get; private set; } = null!; + public static ModCacheManager ModCaches { get; private set; } = null!; public static CollectionManager CollectionManager { get; private set; } = null!; public static TempCollectionManager TempCollections { get; private set; } = null!; public static TempModManager TempMods { get; private set; } = null!; @@ -105,7 +106,7 @@ public class Penumbra : IDalamudPlugin RedrawService = _tmp.Services.GetRequiredService(); _tmp.Services.GetRequiredService(); ResourceLoader = _tmp.Services.GetRequiredService(); - _tmp.Services.GetRequiredService(); + ModCaches = _tmp.Services.GetRequiredService(); using (var t = _tmp.Services.GetRequiredService().Measure(StartTimeType.PathResolver)) { PathResolver = _tmp.Services.GetRequiredService(); @@ -238,13 +239,13 @@ public class Penumbra : IDalamudPlugin sb.Append($"> **`Use Ownership: `** {Config.UseOwnerNameForCharacterCollection}\n"); sb.AppendLine("**Mods**"); sb.Append($"> **`Installed Mods: `** {ModManager.Count}\n"); - sb.Append($"> **`Mods with Config: `** {ModManager.Count(m => m.HasOptions)}\n"); + sb.Append($"> **`Mods with Config: `** {ModCaches.Count(m => m.HasOptions)}\n"); sb.Append( - $"> **`Mods with File Redirections: `** {ModManager.Count(m => m.TotalFileCount > 0)}, Total: {ModManager.Sum(m => m.TotalFileCount)}\n"); + $"> **`Mods with File Redirections: `** {ModCaches.Count(m => m.TotalFileCount > 0)}, Total: {ModCaches.Sum(m => m.TotalFileCount)}\n"); sb.Append( - $"> **`Mods with FileSwaps: `** {ModManager.Count(m => m.TotalSwapCount > 0)}, Total: {ModManager.Sum(m => m.TotalSwapCount)}\n"); + $"> **`Mods with FileSwaps: `** {ModCaches.Count(m => m.TotalSwapCount > 0)}, Total: {ModCaches.Sum(m => m.TotalSwapCount)}\n"); sb.Append( - $"> **`Mods with Meta Manipulations:`** {ModManager.Count(m => m.TotalManipulations > 0)}, Total {ModManager.Sum(m => m.TotalManipulations)}\n"); + $"> **`Mods with Meta Manipulations:`** {ModCaches.Count(m => m.TotalManipulations > 0)}, Total {ModCaches.Sum(m => m.TotalManipulations)}\n"); sb.Append($"> **`IMC Exceptions Thrown: `** {ValidityChecker.ImcExceptions.Count}\n"); sb.Append( $"> **`#Temp Mods: `** {TempMods.Mods.Sum(kvp => kvp.Value.Count) + TempMods.ModsForAllCollections.Count}\n"); @@ -265,7 +266,7 @@ public class Penumbra : IDalamudPlugin => sb.Append($"**Collection {c.AnonymizedName}**\n" + $"> **`Inheritances: `** {c.Inheritance.Count}\n" + $"> **`Enabled Mods: `** {c.ActualSettings.Count(s => s is { Enabled: true })}\n" - + $"> **`Conflicts (Solved/Total): `** {c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority ? 0 : x.Conflicts.Count)}/{c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority || !x.Solved ? 0 : x.Conflicts.Count)}\n"); + + $"> **`Conflicts (Solved/Total): `** {c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority && x.Solved ? x.Conflicts.Count : 0)}/{c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority ? x.Conflicts.Count : 0)}\n"); sb.AppendLine("**Collections**"); sb.Append($"> **`#Collections: `** {CollectionManager.Count - 1}\n"); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs index ad0e7fa2..8cc1060b 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs @@ -82,7 +82,7 @@ public partial class ModEditWindow return f.SubModUsage.Count == 0 ? Enumerable.Repeat((file, "Unused", string.Empty, 0x40000080u), 1) : f.SubModUsage.Select(s => (file, s.Item2.ToString(), s.Item1.FullName, - _editor.Option! == s.Item1 && _mod!.HasOptions ? 0x40008000u : 0u)); + _editor.Option! == s.Item1 && _modCaches[_mod!].HasOptions ? 0x40008000u : 0u)); }); void DrawLine((string, string, string, uint) data) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs index bcc8022e..c59d4784 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs @@ -24,10 +24,11 @@ public partial class ModEditWindow : Window, IDisposable { private const string WindowBaseLabel = "###SubModEdit"; - private readonly ModEditor _editor; - private readonly Configuration _config; - private readonly ItemSwapTab _itemSwapTab; - private readonly DataManager _gameData; + private readonly ModEditor _editor; + private readonly ModCacheManager _modCaches; + private readonly Configuration _config; + private readonly ItemSwapTab _itemSwapTab; + private readonly DataManager _gameData; private Mod? _mod; private Vector2 _iconSize = Vector2.Zero; @@ -490,12 +491,13 @@ public partial class ModEditWindow : Window, IDisposable } public ModEditWindow(FileDialogService fileDialog, ItemSwapTab itemSwapTab, DataManager gameData, - Configuration config, ModEditor editor, ResourceTreeFactory resourceTreeFactory) + Configuration config, ModEditor editor, ResourceTreeFactory resourceTreeFactory, ModCacheManager modCaches) : base(WindowBaseLabel) { _itemSwapTab = itemSwapTab; _config = config; _editor = editor; + _modCaches = modCaches; _gameData = gameData; _fileDialog = fileDialog; _materialTab = new FileEditor(this, gameData, config, _fileDialog, "Materials", ".mtrl", diff --git a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs index 0ea3b734..d03cfab2 100644 --- a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs +++ b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs @@ -30,6 +30,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector !(leaf.FullName().Contains(_modFilter.Lower, IgnoreCase) || mod.Name.Contains(_modFilter)), 1 => !mod.Name.Contains(_modFilter), 2 => !mod.Author.Contains(_modFilter), - 3 => !mod.LowerChangedItemsString.Contains(_modFilter.Lower), - 4 => !mod.AllTagsLower.Contains(_modFilter.Lower), + 3 => !_modCaches[mod].LowerChangedItemsString.Contains(_modFilter.Lower), + 4 => !_modCaches[mod].AllTagsLower.Contains(_modFilter.Lower), _ => false, // Should never happen }; } @@ -639,12 +641,13 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector Label => "Changed Items"u8; - public ModPanelChangedItemsTab(PenumbraApi api, ModFileSystemSelector selector) + public ModPanelChangedItemsTab(PenumbraApi api, ModFileSystemSelector selector, ModCacheManager modCaches) { - _api = api; - _selector = selector; + _api = api; + _selector = selector; + _modCaches = modCaches; } public bool IsVisible - => _selector.Selected!.ChangedItems.Count > 0; + => _modCaches[_selector.Selected!].ChangedItems.Count > 0; public void DrawContent() { @@ -33,7 +35,7 @@ public class ModPanelChangedItemsTab : ITab if (!list) return; - var zipList = ZipList.FromSortedList(_selector.Selected!.ChangedItems); + var zipList = ZipList.FromSortedList(_modCaches[_selector.Selected!].ChangedItems); var height = ImGui.GetTextLineHeight(); ImGuiClip.ClippedDraw(zipList, kvp => UiHelpers.DrawChangedItem(_api, kvp.Item1, kvp.Item2, true), height); }