diff --git a/Penumbra/Collections/Cache/CollectionCache.cs b/Penumbra/Collections/Cache/CollectionCache.cs index 6daa78f3..3477fdf0 100644 --- a/Penumbra/Collections/Cache/CollectionCache.cs +++ b/Penumbra/Collections/Cache/CollectionCache.cs @@ -165,7 +165,7 @@ public class CollectionCache : IDisposable var (paths, manipulations) = ModData.RemoveMod(mod); if (addMetaChanges) - ++_collection.ChangeCounter; + _collection.IncrementCounter(); foreach (var path in paths) { @@ -240,7 +240,7 @@ public class CollectionCache : IDisposable if (addMetaChanges) { - ++_collection.ChangeCounter; + _collection.IncrementCounter(); if (mod.TotalManipulations > 0) AddMetaFiles(false); diff --git a/Penumbra/Collections/Cache/CollectionCacheManager.cs b/Penumbra/Collections/Cache/CollectionCacheManager.cs index 5ac1ab7f..f2223849 100644 --- a/Penumbra/Collections/Cache/CollectionCacheManager.cs +++ b/Penumbra/Collections/Cache/CollectionCacheManager.cs @@ -174,7 +174,7 @@ public class CollectionCacheManager : IDisposable cache.AddMetaFiles(true); - ++collection.ChangeCounter; + collection.IncrementCounter(); MetaFileManager.ApplyDefaultFiles(collection); } @@ -280,7 +280,7 @@ public class CollectionCacheManager : IDisposable private void IncrementCounters() { foreach (var collection in _storage.Where(c => c.HasCache)) - ++collection.ChangeCounter; + collection.IncrementCounter(); MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters; } diff --git a/Penumbra/Collections/Cache/ImcCache.cs b/Penumbra/Collections/Cache/ImcCache.cs index 896e3078..3d097b7b 100644 --- a/Penumbra/Collections/Cache/ImcCache.cs +++ b/Penumbra/Collections/Cache/ImcCache.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using OtterGui.Filesystem; +using System.Linq; using Penumbra.Meta; using Penumbra.Meta.Files; using Penumbra.Meta.Manipulations; @@ -11,113 +11,117 @@ namespace Penumbra.Collections.Cache; public readonly struct ImcCache : IDisposable { - private readonly Dictionary< Utf8GamePath, ImcFile > _imcFiles = new(); - private readonly List< ImcManipulation > _imcManipulations = new(); + private readonly Dictionary _imcFiles = new(); + private readonly List<(ImcManipulation, ImcFile)> _imcManipulations = new(); public ImcCache() - { } + { } public void SetFiles(ModCollection collection, bool fromFullCompute) { if (fromFullCompute) - { foreach (var path in _imcFiles.Keys) collection._cache!.ForceFileSync(path, CreateImcPath(collection, path)); - } else - { foreach (var path in _imcFiles.Keys) collection._cache!.ForceFile(path, CreateImcPath(collection, path)); - } } public void Reset(ModCollection collection) { - foreach( var (path, file) in _imcFiles ) + foreach (var (path, file) in _imcFiles) { - collection._cache!.RemovePath( path ); + collection._cache!.RemovePath(path); file.Reset(); } _imcManipulations.Clear(); } - public bool ApplyMod( MetaFileManager manager, ModCollection collection, ImcManipulation manip ) + public bool ApplyMod(MetaFileManager manager, ModCollection collection, ImcManipulation manip) { - if( !manip.Validate() ) - { + if (!manip.Validate()) return false; - } - _imcManipulations.AddOrReplace( manip ); + var idx = _imcManipulations.FindIndex(p => p.Item1.Equals(manip)); + if (idx < 0) + { + idx = _imcManipulations.Count; + _imcManipulations.Add((manip, null!)); + } + var path = manip.GamePath(); try { - if( !_imcFiles.TryGetValue( path, out var file ) ) - { - file = new ImcFile( manager, manip ); - } + if (!_imcFiles.TryGetValue(path, out var file)) + file = new ImcFile(manager, manip); - if( !manip.Apply( file ) ) - { + _imcManipulations[idx] = (manip, file); + if (!manip.Apply(file)) return false; - } - _imcFiles[ path ] = file; - var fullPath = CreateImcPath( collection, path ); - collection._cache!.ForceFile( path, fullPath ); + _imcFiles[path] = file; + var fullPath = CreateImcPath(collection, path); + collection._cache!.ForceFile(path, fullPath); return true; } - catch( ImcException e ) + catch (ImcException e) { - manager.ValidityChecker.ImcExceptions.Add( e ); - Penumbra.Log.Error( e.ToString() ); + manager.ValidityChecker.ImcExceptions.Add(e); + Penumbra.Log.Error(e.ToString()); } - catch( Exception e ) + catch (Exception e) { - Penumbra.Log.Error( $"Could not apply IMC Manipulation {manip}:\n{e}" ); + Penumbra.Log.Error($"Could not apply IMC Manipulation {manip}:\n{e}"); } return false; } - public bool RevertMod( MetaFileManager manager, ModCollection collection, ImcManipulation m ) + public bool RevertMod(MetaFileManager manager, ModCollection collection, ImcManipulation m) { - if( !m.Validate() || !_imcManipulations.Remove( m ) ) + if (!m.Validate()) + return false; + + var idx = _imcManipulations.FindIndex(p => p.Item1.Equals(m)); + if (idx < 0) + return false; + + var (_, file) = _imcManipulations[idx]; + _imcManipulations.RemoveAt(idx); + + if (_imcManipulations.All(p => !ReferenceEquals(p.Item2, file))) { - return false; - } - - var path = m.GamePath(); - if( !_imcFiles.TryGetValue( path, out var file ) ) - { - return false; - } - - var def = ImcFile.GetDefault( manager, path, m.EquipSlot, m.Variant, out _ ); - var manip = m.Copy( def ); - if( !manip.Apply( file ) ) + _imcFiles.Remove(file.Path); + collection._cache!.ForceFile(file.Path, FullPath.Empty); + file.Dispose(); + return true; + } + + var def = ImcFile.GetDefault(manager, file.Path, m.EquipSlot, m.Variant, out _); + var manip = m.Copy(def); + if (!manip.Apply(file)) return false; - var fullPath = CreateImcPath( collection, path ); - collection._cache!.ForceFile( path, fullPath ); + var fullPath = CreateImcPath(collection, file.Path); + collection._cache!.ForceFile(file.Path, fullPath); return true; } public void Dispose() { - foreach( var file in _imcFiles.Values ) + foreach (var file in _imcFiles.Values) file.Dispose(); _imcFiles.Clear(); _imcManipulations.Clear(); } - private static FullPath CreateImcPath( ModCollection collection, Utf8GamePath path ) + private static FullPath CreateImcPath(ModCollection collection, Utf8GamePath path) => new($"|{collection.Name}_{collection.ChangeCounter}|{path}"); public bool GetImcFile(Utf8GamePath path, [NotNullWhen(true)] out ImcFile? file) => _imcFiles.TryGetValue(path, out file); -} \ No newline at end of file +} diff --git a/Penumbra/Collections/ModCollection.cs b/Penumbra/Collections/ModCollection.cs index fc333747..ca20f371 100644 --- a/Penumbra/Collections/ModCollection.cs +++ b/Penumbra/Collections/ModCollection.cs @@ -47,7 +47,11 @@ public partial class ModCollection /// Count the number of changes of the effective file list. /// This is used for material and imc changes. /// - public int ChangeCounter { get; internal set; } + public int ChangeCounter { get; private set; } + + /// Increment the number of changes in the effective file list. + public int IncrementCounter() + => ++ChangeCounter; /// /// If a ModSetting is null, it can be inherited from other collections.