From 0186f176d0cbd7b3940933ca487009565cb1c621 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 15 Apr 2023 20:40:00 +0200 Subject: [PATCH] meta tmp --- Penumbra/Collections/Cache/CmpCache.cs | 49 +++++ .../Cache/CollectionCacheManager.cs | 44 ++-- Penumbra/Collections/Cache/EqdpCache.cs | 82 +++++++ Penumbra/Collections/Cache/EqpCache.cs | 53 +++++ .../Cache/{MetaCache.Est.cs => EstCache.cs} | 66 +++--- .../Cache/{MetaCache.Gmp.cs => GmpCache.cs} | 39 ++-- .../Cache/{MetaCache.Imc.cs => ImcCache.cs} | 64 ++---- Penumbra/Collections/Cache/MetaCache.Cmp.cs | 61 ------ Penumbra/Collections/Cache/MetaCache.Eqdp.cs | 97 --------- Penumbra/Collections/Cache/MetaCache.Eqp.cs | 62 ------ Penumbra/Collections/Cache/MetaCache.cs | 200 +++++++----------- 11 files changed, 356 insertions(+), 461 deletions(-) create mode 100644 Penumbra/Collections/Cache/CmpCache.cs create mode 100644 Penumbra/Collections/Cache/EqdpCache.cs create mode 100644 Penumbra/Collections/Cache/EqpCache.cs rename Penumbra/Collections/Cache/{MetaCache.Est.cs => EstCache.cs} (60%) rename Penumbra/Collections/Cache/{MetaCache.Gmp.cs => GmpCache.cs} (53%) rename Penumbra/Collections/Cache/{MetaCache.Imc.cs => ImcCache.cs} (61%) delete mode 100644 Penumbra/Collections/Cache/MetaCache.Cmp.cs delete mode 100644 Penumbra/Collections/Cache/MetaCache.Eqdp.cs delete mode 100644 Penumbra/Collections/Cache/MetaCache.Eqp.cs diff --git a/Penumbra/Collections/Cache/CmpCache.cs b/Penumbra/Collections/Cache/CmpCache.cs new file mode 100644 index 00000000..bb87aa88 --- /dev/null +++ b/Penumbra/Collections/Cache/CmpCache.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using OtterGui.Filesystem; +using Penumbra.Interop.Services; +using Penumbra.Interop.Structs; +using Penumbra.Meta.Files; +using Penumbra.Meta.Manipulations; + +namespace Penumbra.Collections.Cache; + +public struct CmpCache : IDisposable +{ + private CmpFile? _cmpFile = null; + private readonly List< RspManipulation > _cmpManipulations = new(); + + public CmpCache() + {} + + public void SetFiles(CollectionCacheManager manager) + => manager.SetFile( _cmpFile, MetaIndex.HumanCmp ); + + public CharacterUtility.MetaList.MetaReverter TemporarilySetFiles(CollectionCacheManager manager) + => manager.TemporarilySetFile( _cmpFile, MetaIndex.HumanCmp ); + + public bool ApplyMod( CollectionCacheManager manager, RspManipulation manip ) + { + _cmpManipulations.AddOrReplace( manip ); + _cmpFile ??= new CmpFile(); + return manip.Apply( _cmpFile ); + } + + public bool RevertMod( CollectionCacheManager manager, RspManipulation manip ) + { + if (!_cmpManipulations.Remove(manip)) + return false; + + var def = CmpFile.GetDefault( manip.SubRace, manip.Attribute ); + manip = new RspManipulation( manip.SubRace, manip.Attribute, def ); + return manip.Apply( _cmpFile! ); + + } + + public void Dispose() + { + _cmpFile?.Dispose(); + _cmpFile = null; + _cmpManipulations.Clear(); + } +} \ No newline at end of file diff --git a/Penumbra/Collections/Cache/CollectionCacheManager.cs b/Penumbra/Collections/Cache/CollectionCacheManager.cs index aa24d208..326b5918 100644 --- a/Penumbra/Collections/Cache/CollectionCacheManager.cs +++ b/Penumbra/Collections/Cache/CollectionCacheManager.cs @@ -17,15 +17,17 @@ namespace Penumbra.Collections.Cache; public class CollectionCacheManager : IDisposable { - private readonly FrameworkManager _framework; - private readonly ActiveCollections _active; - private readonly CommunicatorService _communicator; - private readonly CharacterUtility _characterUtility; - private readonly TempModManager _tempMods; - private readonly ModStorage _modStorage; - private readonly ModCacheManager _modCaches; - private readonly Configuration _config; - private readonly ResidentResourceManager _resources; + private readonly FrameworkManager _framework; + private readonly ActiveCollections _active; + private readonly CommunicatorService _communicator; + private readonly TempModManager _tempMods; + private readonly ModStorage _modStorage; + private readonly ModCacheManager _modCaches; + private readonly Configuration _config; + + internal readonly ValidityChecker ValidityChecker; + internal readonly CharacterUtility CharacterUtility; + internal readonly ResidentResourceManager ResidentResources; private readonly Dictionary _caches = new(); @@ -37,17 +39,18 @@ public class CollectionCacheManager : IDisposable public CollectionCacheManager(FrameworkManager framework, ActiveCollections active, CommunicatorService communicator, CharacterUtility characterUtility, TempModManager tempMods, ModStorage modStorage, Configuration config, - ResidentResourceManager resources, ModCacheManager modCaches) + ResidentResourceManager residentResources, ModCacheManager modCaches, ValidityChecker validityChecker) { _framework = framework; _active = active; _communicator = communicator; - _characterUtility = characterUtility; + CharacterUtility = characterUtility; _tempMods = tempMods; _modStorage = modStorage; _config = config; - _resources = resources; + ResidentResources = residentResources; _modCaches = modCaches; + ValidityChecker = validityChecker; _communicator.CollectionChange.Subscribe(OnCollectionChange); _communicator.ModPathChanged.Subscribe(OnModChangeAddition, -100); @@ -58,8 +61,8 @@ public class CollectionCacheManager : IDisposable _communicator.CollectionInheritanceChanged.Subscribe(OnCollectionInheritanceChange); CreateNecessaryCaches(); - if (!_characterUtility.Ready) - _characterUtility.LoadingFinished += IncrementCounters; + if (!CharacterUtility.Ready) + CharacterUtility.LoadingFinished += IncrementCounters; } public void Dispose() @@ -71,7 +74,7 @@ public class CollectionCacheManager : IDisposable _communicator.ModOptionChanged.Unsubscribe(OnModOptionChange); _communicator.ModSettingChanged.Unsubscribe(OnModSettingChange); _communicator.CollectionInheritanceChanged.Unsubscribe(OnCollectionInheritanceChange); - _characterUtility.LoadingFinished -= IncrementCounters; + CharacterUtility.LoadingFinished -= IncrementCounters; } /// Only creates a new cache, does not update an existing one. @@ -80,7 +83,7 @@ public class CollectionCacheManager : IDisposable if (_caches.ContainsKey(collection) || collection.Index == ModCollection.Empty.Index) return false; - var cache = new CollectionCache(collection); + var cache = new CollectionCache(this, collection); _caches.Add(collection, cache); collection._cache = cache; Penumbra.Log.Verbose($"Created new cache for collection {collection.AnonymizedName}."); @@ -95,6 +98,9 @@ public class CollectionCacheManager : IDisposable => _framework.RegisterImportant(nameof(CalculateEffectiveFileList) + collection.Name, () => CalculateEffectiveFileListInternal(collection)); + public bool IsDefault(ModCollection collection) + => _active.Default == collection; + private void CalculateEffectiveFileListInternal(ModCollection collection) { // Skip the empty collection. @@ -133,10 +139,10 @@ public class CollectionCacheManager : IDisposable ++collection.ChangeCounter; - if (_active.Default != collection || !_characterUtility.Ready || !_config.EnableMods) + if (_active.Default != collection || !CharacterUtility.Ready || !_config.EnableMods) return; - _resources.Reload(); + ResidentResources.Reload(); cache.MetaManipulations.SetFiles(); } @@ -232,7 +238,7 @@ public class CollectionCacheManager : IDisposable { foreach (var (collection, _) in _caches) ++collection.ChangeCounter; - _characterUtility.LoadingFinished -= IncrementCounters; + CharacterUtility.LoadingFinished -= IncrementCounters; } private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx, bool _) diff --git a/Penumbra/Collections/Cache/EqdpCache.cs b/Penumbra/Collections/Cache/EqdpCache.cs new file mode 100644 index 00000000..aa882ac4 --- /dev/null +++ b/Penumbra/Collections/Cache/EqdpCache.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OtterGui; +using OtterGui.Filesystem; +using Penumbra.GameData.Enums; +using Penumbra.Interop.Services; +using Penumbra.Interop.Structs; +using Penumbra.Meta.Files; +using Penumbra.Meta.Manipulations; + +namespace Penumbra.Collections.Cache; + +public readonly struct EqdpCache : IDisposable +{ + private readonly ExpandedEqdpFile?[] _eqdpFiles = new ExpandedEqdpFile[CharacterUtilityData.EqdpIndices.Length]; // TODO: female Hrothgar + private readonly List _eqdpManipulations = new(); + + public EqdpCache() + { } + + public void SetFiles(CollectionCacheManager manager) + { + for (var i = 0; i < CharacterUtilityData.EqdpIndices.Length; ++i) + manager.SetFile(_eqdpFiles[i], CharacterUtilityData.EqdpIndices[i]); + } + + public CharacterUtility.MetaList.MetaReverter? TemporarilySetEqdpFile(CollectionCacheManager manager, GenderRace genderRace, bool accessory) + { + var idx = CharacterUtilityData.EqdpIdx(genderRace, accessory); + if ((int)idx == -1) + return null; + + var i = CharacterUtilityData.EqdpIndices.IndexOf(idx); + return i != -1 ? manager.TemporarilySetFile(_eqdpFiles[i], idx) : null; + } + + public void Reset(CollectionCacheManager manager) + { + foreach (var file in _eqdpFiles.OfType()) + { + var relevant = CharacterUtility.RelevantIndices[file.Index.Value]; + file.Reset(_eqdpManipulations.Where(m => m.FileIndex() == relevant).Select(m => (int)m.SetId)); + } + + _eqdpManipulations.Clear(); + } + + public bool ApplyMod(CollectionCacheManager manager, EqdpManipulation manip) + { + _eqdpManipulations.AddOrReplace(manip); + var file = _eqdpFiles[Array.IndexOf(CharacterUtilityData.EqdpIndices, manip.FileIndex())] ??= + new ExpandedEqdpFile(Names.CombinedRace(manip.Gender, manip.Race), manip.Slot.IsAccessory()); // TODO: female Hrothgar + return manip.Apply(file); + } + + public bool RevertMod(CollectionCacheManager manager, EqdpManipulation manip) + { + if (!_eqdpManipulations.Remove(manip)) + return false; + + var def = ExpandedEqdpFile.GetDefault(Names.CombinedRace(manip.Gender, manip.Race), manip.Slot.IsAccessory(), manip.SetId); + var file = _eqdpFiles[Array.IndexOf(CharacterUtilityData.EqdpIndices, manip.FileIndex())]!; + manip = new EqdpManipulation(def, manip.Slot, manip.Gender, manip.Race, manip.SetId); + return manip.Apply(file); + } + + public ExpandedEqdpFile? EqdpFile(GenderRace race, bool accessory) + => _eqdpFiles + [Array.IndexOf(CharacterUtilityData.EqdpIndices, CharacterUtilityData.EqdpIdx(race, accessory))]; // TODO: female Hrothgar + + public void Dispose() + { + for (var i = 0; i < _eqdpFiles.Length; ++i) + { + _eqdpFiles[i]?.Dispose(); + _eqdpFiles[i] = null; + } + + _eqdpManipulations.Clear(); + } +} diff --git a/Penumbra/Collections/Cache/EqpCache.cs b/Penumbra/Collections/Cache/EqpCache.cs new file mode 100644 index 00000000..8cf19386 --- /dev/null +++ b/Penumbra/Collections/Cache/EqpCache.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using OtterGui.Filesystem; +using Penumbra.Interop.Services; +using Penumbra.Interop.Structs; +using Penumbra.Meta.Files; +using Penumbra.Meta.Manipulations; + +namespace Penumbra.Collections.Cache; + +public struct EqpCache : IDisposable +{ + private ExpandedEqpFile? _eqpFile = null; + private readonly List< EqpManipulation > _eqpManipulations = new(); + + public EqpCache() + {} + + public void SetFiles(CollectionCacheManager manager) + => manager.SetFile( _eqpFile, MetaIndex.Eqp ); + + public static void ResetFiles(CollectionCacheManager manager) + => manager.SetFile( null, MetaIndex.Eqp ); + + public CharacterUtility.MetaList.MetaReverter TemporarilySetFiles(CollectionCacheManager manager) + => manager.TemporarilySetFile( _eqpFile, MetaIndex.Eqp ); + + public bool ApplyMod( CollectionCacheManager manager, EqpManipulation manip ) + { + _eqpManipulations.AddOrReplace( manip ); + _eqpFile ??= new ExpandedEqpFile(); + return manip.Apply( _eqpFile ); + } + + public bool RevertMod( CollectionCacheManager manager, EqpManipulation manip ) + { + var idx = _eqpManipulations.FindIndex( manip.Equals ); + if (idx < 0) + return false; + + var def = ExpandedEqpFile.GetDefault( manip.SetId ); + manip = new EqpManipulation( def, manip.Slot, manip.SetId ); + return manip.Apply( _eqpFile! ); + + } + + public void Dispose() + { + _eqpFile?.Dispose(); + _eqpFile = null; + _eqpManipulations.Clear(); + } +} \ No newline at end of file diff --git a/Penumbra/Collections/Cache/MetaCache.Est.cs b/Penumbra/Collections/Cache/EstCache.cs similarity index 60% rename from Penumbra/Collections/Cache/MetaCache.Est.cs rename to Penumbra/Collections/Cache/EstCache.cs index 6815be30..76470d87 100644 --- a/Penumbra/Collections/Cache/MetaCache.Est.cs +++ b/Penumbra/Collections/Cache/EstCache.cs @@ -9,32 +9,27 @@ using Penumbra.Meta.Manipulations; namespace Penumbra.Collections.Cache; -public partial class MetaCache +public struct EstCache : IDisposable { private EstFile? _estFaceFile = null; private EstFile? _estHairFile = null; private EstFile? _estBodyFile = null; private EstFile? _estHeadFile = null; - private readonly List< EstManipulation > _estManipulations = new(); + private readonly List< EstManipulation > _estManipulations = new(); + + public EstCache() + {} - public void SetEstFiles() + public void SetFiles(CollectionCacheManager manager) { - SetFile( _estFaceFile, MetaIndex.FaceEst ); - SetFile( _estHairFile, MetaIndex.HairEst ); - SetFile( _estBodyFile, MetaIndex.BodyEst ); - SetFile( _estHeadFile, MetaIndex.HeadEst ); + manager.SetFile( _estFaceFile, MetaIndex.FaceEst ); + manager.SetFile( _estHairFile, MetaIndex.HairEst ); + manager.SetFile( _estBodyFile, MetaIndex.BodyEst ); + manager.SetFile( _estHeadFile, MetaIndex.HeadEst ); } - public static void ResetEstFiles() - { - SetFile( null, MetaIndex.FaceEst ); - SetFile( null, MetaIndex.HairEst ); - SetFile( null, MetaIndex.BodyEst ); - SetFile( null, MetaIndex.HeadEst ); - } - - public CharacterUtility.MetaList.MetaReverter? TemporarilySetEstFile(EstManipulation.EstType type) + public CharacterUtility.MetaList.MetaReverter? TemporarilySetFiles(CollectionCacheManager manager, EstManipulation.EstType type) { var (file, idx) = type switch { @@ -45,10 +40,10 @@ public partial class MetaCache _ => ( null, 0 ), }; - return idx != 0 ? TemporarilySetFile( file, idx ) : null; + return idx != 0 ? manager.TemporarilySetFile( file, idx ) : null; } - public void ResetEst() + public void Reset() { _estFaceFile?.Reset(); _estHairFile?.Reset(); @@ -57,7 +52,7 @@ public partial class MetaCache _estManipulations.Clear(); } - public bool ApplyMod( EstManipulation m ) + public bool ApplyMod( CollectionCacheManager manager, EstManipulation m ) { _estManipulations.AddOrReplace( m ); var file = m.Slot switch @@ -71,27 +66,26 @@ public partial class MetaCache return m.Apply( file ); } - public bool RevertMod( EstManipulation m ) + public bool RevertMod( CollectionCacheManager manager, EstManipulation m ) { - if( _estManipulations.Remove( m ) ) - { - var def = EstFile.GetDefault( m.Slot, Names.CombinedRace( m.Gender, m.Race ), m.SetId ); - var manip = new EstManipulation( m.Gender, m.Race, m.Slot, m.SetId, def ); - var file = m.Slot switch - { - EstManipulation.EstType.Hair => _estHairFile!, - EstManipulation.EstType.Face => _estFaceFile!, - EstManipulation.EstType.Body => _estBodyFile!, - EstManipulation.EstType.Head => _estHeadFile!, - _ => throw new ArgumentOutOfRangeException(), - }; - return manip.Apply( file ); - } + if (!_estManipulations.Remove(m)) + return false; + + var def = EstFile.GetDefault( m.Slot, Names.CombinedRace( m.Gender, m.Race ), m.SetId ); + var manip = new EstManipulation( m.Gender, m.Race, m.Slot, m.SetId, def ); + var file = m.Slot switch + { + EstManipulation.EstType.Hair => _estHairFile!, + EstManipulation.EstType.Face => _estFaceFile!, + EstManipulation.EstType.Body => _estBodyFile!, + EstManipulation.EstType.Head => _estHeadFile!, + _ => throw new ArgumentOutOfRangeException(), + }; + return manip.Apply( file ); - return false; } - public void DisposeEst() + public void Dispose() { _estFaceFile?.Dispose(); _estHairFile?.Dispose(); diff --git a/Penumbra/Collections/Cache/MetaCache.Gmp.cs b/Penumbra/Collections/Cache/GmpCache.cs similarity index 53% rename from Penumbra/Collections/Cache/MetaCache.Gmp.cs rename to Penumbra/Collections/Cache/GmpCache.cs index f83efe77..436dfdbf 100644 --- a/Penumbra/Collections/Cache/MetaCache.Gmp.cs +++ b/Penumbra/Collections/Cache/GmpCache.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using OtterGui.Filesystem; @@ -8,51 +9,47 @@ using Penumbra.Meta.Manipulations; namespace Penumbra.Collections.Cache; -public partial class MetaCache +public struct GmpCache : IDisposable { private ExpandedGmpFile? _gmpFile = null; private readonly List< GmpManipulation > _gmpManipulations = new(); + + public GmpCache() + {} - public void SetGmpFiles() - => SetFile( _gmpFile, MetaIndex.Gmp ); + public void SetFiles(CollectionCacheManager manager) + => manager.SetFile( _gmpFile, MetaIndex.Gmp ); - public static void ResetGmpFiles() - => SetFile( null, MetaIndex.Gmp ); + public CharacterUtility.MetaList.MetaReverter TemporarilySetFiles(CollectionCacheManager manager) + => manager.TemporarilySetFile( _gmpFile, MetaIndex.Gmp ); - public CharacterUtility.MetaList.MetaReverter TemporarilySetGmpFile() - => TemporarilySetFile( _gmpFile, MetaIndex.Gmp ); - - public void ResetGmp() + public void ResetGmp(CollectionCacheManager manager) { if( _gmpFile == null ) - { return; - } _gmpFile.Reset( _gmpManipulations.Select( m => ( int )m.SetId ) ); _gmpManipulations.Clear(); } - public bool ApplyMod( GmpManipulation manip ) + public bool ApplyMod( CollectionCacheManager manager, GmpManipulation manip ) { _gmpManipulations.AddOrReplace( manip ); _gmpFile ??= new ExpandedGmpFile(); return manip.Apply( _gmpFile ); } - public bool RevertMod( GmpManipulation manip ) + public bool RevertMod( CollectionCacheManager manager, GmpManipulation manip ) { - if( _gmpManipulations.Remove( manip ) ) - { - var def = ExpandedGmpFile.GetDefault( manip.SetId ); - manip = new GmpManipulation( def, manip.SetId ); - return manip.Apply( _gmpFile! ); - } + if (!_gmpManipulations.Remove(manip)) + return false; - return false; + var def = ExpandedGmpFile.GetDefault( manip.SetId ); + manip = new GmpManipulation( def, manip.SetId ); + return manip.Apply( _gmpFile! ); } - public void DisposeGmp() + public void Dispose() { _gmpFile?.Dispose(); _gmpFile = null; diff --git a/Penumbra/Collections/Cache/MetaCache.Imc.cs b/Penumbra/Collections/Cache/ImcCache.cs similarity index 61% rename from Penumbra/Collections/Cache/MetaCache.Imc.cs rename to Penumbra/Collections/Cache/ImcCache.cs index 89e55b1b..43dc73e5 100644 --- a/Penumbra/Collections/Cache/MetaCache.Imc.cs +++ b/Penumbra/Collections/Cache/ImcCache.cs @@ -8,46 +8,32 @@ using Penumbra.String.Classes; namespace Penumbra.Collections.Cache; -public partial class MetaCache +public readonly struct ImcCache : IDisposable { private readonly Dictionary< Utf8GamePath, ImcFile > _imcFiles = new(); private readonly List< ImcManipulation > _imcManipulations = new(); - public void SetImcFiles() - { - if( !_collection.HasCache ) - { - return; - } + public ImcCache() + { } + public void SetFiles(CollectionCacheManager manager, ModCollection collection) + { foreach( var path in _imcFiles.Keys ) - { - _collection.ForceFile( path, CreateImcPath( path ) ); - } + collection._cache!.ForceFile( path, CreateImcPath( collection, path ) ); } - public void ResetImc() + public void Reset(CollectionCacheManager manager, ModCollection collection) { - if( _collection.HasCache ) + foreach( var (path, file) in _imcFiles ) { - foreach( var (path, file) in _imcFiles ) - { - _collection.RemoveFile( path ); - file.Reset(); - } - } - else - { - foreach( var (_, file) in _imcFiles ) - { - file.Reset(); - } + collection._cache!.RemoveFile( path ); + file.Reset(); } _imcManipulations.Clear(); } - public bool ApplyMod( ImcManipulation manip ) + public bool ApplyMod( CollectionCacheManager manager, ModCollection collection, ImcManipulation manip ) { if( !manip.Valid ) { @@ -69,17 +55,14 @@ public partial class MetaCache } _imcFiles[ path ] = file; - var fullPath = CreateImcPath( path ); - if( _collection.HasCache ) - { - _collection.ForceFile( path, fullPath ); - } + var fullPath = CreateImcPath( collection, path ); + collection._cache!.ForceFile( path, fullPath ); return true; } catch( ImcException e ) { - Penumbra.ValidityChecker.ImcExceptions.Add( e ); + manager.ValidityChecker.ImcExceptions.Add( e ); Penumbra.Log.Error( e.ToString() ); } catch( Exception e ) @@ -90,7 +73,7 @@ public partial class MetaCache return false; } - public bool RevertMod( ImcManipulation m ) + public bool RevertMod( CollectionCacheManager manager, ModCollection collection, ImcManipulation m ) { if( !m.Valid || !_imcManipulations.Remove( m ) ) { @@ -106,32 +89,25 @@ public partial class MetaCache var def = ImcFile.GetDefault( path, m.EquipSlot, m.Variant, out _ ); var manip = m.Copy( def ); if( !manip.Apply( file ) ) - { return false; - } - var fullPath = CreateImcPath( path ); - if( _collection.HasCache ) - { - _collection.ForceFile( path, fullPath ); - } + var fullPath = CreateImcPath( collection, path ); + collection._cache!.ForceFile( path, fullPath ); return true; } - public void DisposeImc() + public void Dispose() { foreach( var file in _imcFiles.Values ) - { file.Dispose(); - } _imcFiles.Clear(); _imcManipulations.Clear(); } - private FullPath CreateImcPath( Utf8GamePath path ) - => new($"|{_collection.Name}_{_collection.ChangeCounter}|{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); diff --git a/Penumbra/Collections/Cache/MetaCache.Cmp.cs b/Penumbra/Collections/Cache/MetaCache.Cmp.cs deleted file mode 100644 index 35d97eee..00000000 --- a/Penumbra/Collections/Cache/MetaCache.Cmp.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using OtterGui.Filesystem; -using Penumbra.Interop.Services; -using Penumbra.Interop.Structs; -using Penumbra.Meta.Files; -using Penumbra.Meta.Manipulations; - -namespace Penumbra.Collections.Cache; - -public partial class MetaCache -{ - private CmpFile? _cmpFile = null; - private readonly List< RspManipulation > _cmpManipulations = new(); - - public void SetCmpFiles() - => SetFile( _cmpFile, MetaIndex.HumanCmp ); - - public static void ResetCmpFiles() - => SetFile( null, MetaIndex.HumanCmp ); - - public CharacterUtility.MetaList.MetaReverter TemporarilySetCmpFile() - => TemporarilySetFile( _cmpFile, MetaIndex.HumanCmp ); - - public void ResetCmp() - { - if( _cmpFile == null ) - { - return; - } - - _cmpFile.Reset( _cmpManipulations.Select( m => ( m.SubRace, m.Attribute ) ) ); - _cmpManipulations.Clear(); - } - - public bool ApplyMod( RspManipulation manip ) - { - _cmpManipulations.AddOrReplace( manip ); - _cmpFile ??= new CmpFile(); - return manip.Apply( _cmpFile ); - } - - public bool RevertMod( RspManipulation manip ) - { - if( _cmpManipulations.Remove( manip ) ) - { - var def = CmpFile.GetDefault( manip.SubRace, manip.Attribute ); - manip = new RspManipulation( manip.SubRace, manip.Attribute, def ); - return manip.Apply( _cmpFile! ); - } - - return false; - } - - public void DisposeCmp() - { - _cmpFile?.Dispose(); - _cmpFile = null; - _cmpManipulations.Clear(); - } -} \ No newline at end of file diff --git a/Penumbra/Collections/Cache/MetaCache.Eqdp.cs b/Penumbra/Collections/Cache/MetaCache.Eqdp.cs deleted file mode 100644 index 5bac9169..00000000 --- a/Penumbra/Collections/Cache/MetaCache.Eqdp.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using OtterGui; -using OtterGui.Filesystem; -using Penumbra.GameData.Enums; -using Penumbra.Interop.Services; -using Penumbra.Interop.Structs; -using Penumbra.Meta.Files; -using Penumbra.Meta.Manipulations; - -namespace Penumbra.Collections.Cache; - -public partial class MetaCache -{ - private readonly ExpandedEqdpFile?[] _eqdpFiles = new ExpandedEqdpFile[CharacterUtilityData.EqdpIndices.Length]; // TODO: female Hrothgar - - private readonly List< EqdpManipulation > _eqdpManipulations = new(); - - public void SetEqdpFiles() - { - for( var i = 0; i < CharacterUtilityData.EqdpIndices.Length; ++i ) - { - SetFile( _eqdpFiles[ i ], CharacterUtilityData.EqdpIndices[ i ] ); - } - } - - public CharacterUtility.MetaList.MetaReverter? TemporarilySetEqdpFile( GenderRace genderRace, bool accessory ) - { - var idx = CharacterUtilityData.EqdpIdx( genderRace, accessory ); - if( ( int )idx != -1 ) - { - var i = CharacterUtilityData.EqdpIndices.IndexOf( idx ); - if( i != -1 ) - { - return TemporarilySetFile( _eqdpFiles[ i ], idx ); - } - } - - return null; - } - - public static void ResetEqdpFiles() - { - foreach( var idx in CharacterUtilityData.EqdpIndices ) - { - SetFile( null, idx ); - } - } - - public void ResetEqdp() - { - foreach( var file in _eqdpFiles.OfType< ExpandedEqdpFile >() ) - { - var relevant = CharacterUtility.RelevantIndices[ file.Index.Value ]; - file.Reset( _eqdpManipulations.Where( m => m.FileIndex() == relevant ).Select( m => ( int )m.SetId ) ); - } - - _eqdpManipulations.Clear(); - } - - public bool ApplyMod( EqdpManipulation manip ) - { - _eqdpManipulations.AddOrReplace( manip ); - var file = _eqdpFiles[ Array.IndexOf( CharacterUtilityData.EqdpIndices, manip.FileIndex() ) ] ??= - new ExpandedEqdpFile( Names.CombinedRace( manip.Gender, manip.Race ), manip.Slot.IsAccessory() ); // TODO: female Hrothgar - return manip.Apply( file ); - } - - public bool RevertMod( EqdpManipulation manip ) - { - if( _eqdpManipulations.Remove( manip ) ) - { - var def = ExpandedEqdpFile.GetDefault( Names.CombinedRace( manip.Gender, manip.Race ), manip.Slot.IsAccessory(), manip.SetId ); - var file = _eqdpFiles[ Array.IndexOf( CharacterUtilityData.EqdpIndices, manip.FileIndex() ) ]!; - manip = new EqdpManipulation( def, manip.Slot, manip.Gender, manip.Race, manip.SetId ); - return manip.Apply( file ); - } - - return false; - } - - public ExpandedEqdpFile? EqdpFile( GenderRace race, bool accessory ) - => _eqdpFiles - [ Array.IndexOf( CharacterUtilityData.EqdpIndices, CharacterUtilityData.EqdpIdx( race, accessory ) ) ]; // TODO: female Hrothgar - - public void DisposeEqdp() - { - for( var i = 0; i < _eqdpFiles.Length; ++i ) - { - _eqdpFiles[ i ]?.Dispose(); - _eqdpFiles[ i ] = null; - } - - _eqdpManipulations.Clear(); - } -} \ No newline at end of file diff --git a/Penumbra/Collections/Cache/MetaCache.Eqp.cs b/Penumbra/Collections/Cache/MetaCache.Eqp.cs deleted file mode 100644 index ce0829a0..00000000 --- a/Penumbra/Collections/Cache/MetaCache.Eqp.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using OtterGui.Filesystem; -using Penumbra.Interop.Services; -using Penumbra.Interop.Structs; -using Penumbra.Meta.Files; -using Penumbra.Meta.Manipulations; - -namespace Penumbra.Collections.Cache; - -public partial class MetaCache -{ - private ExpandedEqpFile? _eqpFile = null; - private readonly List< EqpManipulation > _eqpManipulations = new(); - - public void SetEqpFiles() - => SetFile( _eqpFile, MetaIndex.Eqp ); - - public static void ResetEqpFiles() - => SetFile( null, MetaIndex.Eqp ); - - public CharacterUtility.MetaList.MetaReverter TemporarilySetEqpFile() - => TemporarilySetFile( _eqpFile, MetaIndex.Eqp ); - - public void ResetEqp() - { - if( _eqpFile == null ) - { - return; - } - - _eqpFile.Reset( _eqpManipulations.Select( m => ( int )m.SetId ) ); - _eqpManipulations.Clear(); - } - - public bool ApplyMod( EqpManipulation manip ) - { - _eqpManipulations.AddOrReplace( manip ); - _eqpFile ??= new ExpandedEqpFile(); - return manip.Apply( _eqpFile ); - } - - public bool RevertMod( EqpManipulation manip ) - { - var idx = _eqpManipulations.FindIndex( manip.Equals ); - if( idx >= 0 ) - { - var def = ExpandedEqpFile.GetDefault( manip.SetId ); - manip = new EqpManipulation( def, manip.Slot, manip.SetId ); - return manip.Apply( _eqpFile! ); - } - - return false; - } - - public void DisposeEqp() - { - _eqpFile?.Dispose(); - _eqpFile = null; - _eqpManipulations.Clear(); - } -} \ No newline at end of file diff --git a/Penumbra/Collections/Cache/MetaCache.cs b/Penumbra/Collections/Cache/MetaCache.cs index 0b6fa942..bee01714 100644 --- a/Penumbra/Collections/Cache/MetaCache.cs +++ b/Penumbra/Collections/Cache/MetaCache.cs @@ -12,115 +12,115 @@ using Penumbra.Mods; namespace Penumbra.Collections.Cache; -public partial class MetaCache : IDisposable, IEnumerable< KeyValuePair< MetaManipulation, IMod > > +public struct MetaCache : IDisposable, IEnumerable> { - private readonly Dictionary< MetaManipulation, IMod > _manipulations = new(); - private readonly ModCollection _collection; + private readonly CollectionCacheManager _manager; + private readonly ModCollection _collection; + private readonly Dictionary _manipulations = new(); + private EqpCache _eqpCache = new(); + private readonly EqdpCache _eqdpCache = new(); + private EstCache _estCache = new(); + private GmpCache _gmpCache = new(); + private CmpCache _cmpCache = new(); + private readonly ImcCache _imcCache; - public bool TryGetValue( MetaManipulation manip, [NotNullWhen( true )] out IMod? mod ) - => _manipulations.TryGetValue( manip, out mod ); + public bool TryGetValue(MetaManipulation manip, [NotNullWhen(true)] out IMod? mod) + => _manipulations.TryGetValue(manip, out mod); public int Count => _manipulations.Count; - public IReadOnlyCollection< MetaManipulation > Manipulations + public IReadOnlyCollection Manipulations => _manipulations.Keys; - public IEnumerator< KeyValuePair< MetaManipulation, IMod > > GetEnumerator() + public IEnumerator> GetEnumerator() => _manipulations.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public MetaCache( ModCollection collection ) + public MetaCache(CollectionCacheManager manager, ModCollection collection) { - _collection = collection; - if( !Penumbra.CharacterUtility.Ready ) - { - Penumbra.CharacterUtility.LoadingFinished += ApplyStoredManipulations; - } + _manager = manager; + _imcCache = new ImcCache(collection); + if (!_manager.CharacterUtility.Ready) + _manager.CharacterUtility.LoadingFinished += ApplyStoredManipulations; } public void SetFiles() { - SetEqpFiles(); - SetEqdpFiles(); - SetGmpFiles(); - SetEstFiles(); - SetCmpFiles(); - SetImcFiles(); + _eqpCache.SetFiles(_manager); + _eqdpCache.SetFiles(_manager); + _estCache.SetFiles(_manager); + _gmpCache.SetFiles(_manager); + _cmpCache.SetFiles(_manager); + _imcCache.SetFiles(_manager, _collection); } public void Reset() { - ResetEqp(); - ResetEqdp(); - ResetGmp(); - ResetEst(); - ResetCmp(); - ResetImc(); + _eqpCache.Reset(_manager); + _eqdpCache.Reset(_manager); + _estCache.Reset(_manager); + _gmpCache.Reset(_manager); + _cmpCache.Reset(_manager); + _imcCache.Reset(_manager, _collection); _manipulations.Clear(); } public void Dispose() { + _manager.CharacterUtility.LoadingFinished -= ApplyStoredManipulations; + _eqpCache.Dispose(); + _eqdpCache.Dispose(); + _estCache.Dispose(); + _gmpCache.Dispose(); + _cmpCache.Dispose(); + _imcCache.Dispose(); _manipulations.Clear(); - Penumbra.CharacterUtility.LoadingFinished -= ApplyStoredManipulations; - DisposeEqp(); - DisposeEqdp(); - DisposeCmp(); - DisposeGmp(); - DisposeEst(); - DisposeImc(); } - public bool ApplyMod( MetaManipulation manip, IMod mod ) + public bool ApplyMod(MetaManipulation manip, IMod mod) { - if( _manipulations.ContainsKey( manip ) ) - { - _manipulations.Remove( manip ); - } + if (_manipulations.ContainsKey(manip)) + _manipulations.Remove(manip); - _manipulations[ manip ] = mod; + _manipulations[manip] = mod; - if( !Penumbra.CharacterUtility.Ready ) - { + if (!_manager.CharacterUtility.Ready) return true; - } // Imc manipulations do not require character utility, // but they do require the file space to be ready. return manip.ManipulationType switch { - MetaManipulation.Type.Eqp => ApplyMod( manip.Eqp ), - MetaManipulation.Type.Gmp => ApplyMod( manip.Gmp ), - MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ), - MetaManipulation.Type.Est => ApplyMod( manip.Est ), - MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ), - MetaManipulation.Type.Imc => ApplyMod( manip.Imc ), + MetaManipulation.Type.Eqp => _eqpCache.ApplyMod(_manager, manip.Eqp), + MetaManipulation.Type.Eqdp => _eqdpCache.ApplyMod(_manager, manip.Eqdp), + MetaManipulation.Type.Est => _estCache.ApplyMod(_manager, manip.Est), + MetaManipulation.Type.Gmp => _gmpCache.ApplyMod(_manager, manip.Gmp), + MetaManipulation.Type.Rsp => _cmpCache.ApplyMod(_manager, manip.Rsp), + MetaManipulation.Type.Imc => _imcCache.ApplyMod(_manager, _collection, manip.Imc), MetaManipulation.Type.Unknown => false, _ => false, }; } - public bool RevertMod( MetaManipulation manip ) + public bool RevertMod(MetaManipulation manip) { - var ret = _manipulations.Remove( manip ); - if( !Penumbra.CharacterUtility.Ready ) - { + var ret = _manipulations.Remove(manip); + if (!Penumbra.CharacterUtility.Ready) return ret; - } // Imc manipulations do not require character utility, // but they do require the file space to be ready. return manip.ManipulationType switch { - MetaManipulation.Type.Eqp => RevertMod( (MetaManipulation)manip.Eqp ), - MetaManipulation.Type.Gmp => RevertMod( (MetaManipulation)manip.Gmp ), - MetaManipulation.Type.Eqdp => RevertMod( (MetaManipulation)manip.Eqdp ), - MetaManipulation.Type.Est => RevertMod( (MetaManipulation)manip.Est ), - MetaManipulation.Type.Rsp => RevertMod( (MetaManipulation)manip.Rsp ), - MetaManipulation.Type.Imc => RevertMod( (MetaManipulation)manip.Imc ), + MetaManipulation.Type.Eqp => _eqpCache.RevertMod(_manager, manip.Eqp), + MetaManipulation.Type.Eqdp => _eqdpCache.RevertMod(_manager, manip.Eqdp), + MetaManipulation.Type.Est => _estCache.RevertMod(_manager, manip.Est), + MetaManipulation.Type.Gmp => _gmpCache.RevertMod(_manager, manip.Gmp), + MetaManipulation.Type.Rsp => _cmpCache.RevertMod(_manager, manip.Rsp), + MetaManipulation.Type.Imc => _imcCache.RevertMod(_manager, _collection, manip.Imc), MetaManipulation.Type.Unknown => false, _ => false, }; @@ -129,22 +129,20 @@ public partial class MetaCache : IDisposable, IEnumerable< KeyValuePair< MetaMan // Use this when CharacterUtility becomes ready. private void ApplyStoredManipulations() { - if( !Penumbra.CharacterUtility.Ready ) - { + if (!Penumbra.CharacterUtility.Ready) return; - } var loaded = 0; - foreach( var manip in Manipulations ) + foreach (var manip in Manipulations) { loaded += manip.ManipulationType switch { - MetaManipulation.Type.Eqp => ApplyMod( manip.Eqp ), - MetaManipulation.Type.Gmp => ApplyMod( manip.Gmp ), - MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ), - MetaManipulation.Type.Est => ApplyMod( manip.Est ), - MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ), - MetaManipulation.Type.Imc => ApplyMod( manip.Imc ), + MetaManipulation.Type.Eqp => _eqpCache.ApplyMod(_manager, manip.Eqp), + MetaManipulation.Type.Eqdp => _eqdpCache.ApplyMod(_manager, manip.Eqdp), + MetaManipulation.Type.Est => _estCache.ApplyMod(_manager, manip.Est), + MetaManipulation.Type.Gmp => _gmpCache.ApplyMod(_manager, manip.Gmp), + MetaManipulation.Type.Rsp => _cmpCache.ApplyMod(_manager, manip.Rsp), + MetaManipulation.Type.Imc => _imcCache.ApplyMod(_manager, _collection, manip.Imc), MetaManipulation.Type.Unknown => false, _ => false, } @@ -152,68 +150,28 @@ public partial class MetaCache : IDisposable, IEnumerable< KeyValuePair< MetaMan : 0; } - if( Penumbra.CollectionManager.Active.Default == _collection ) + if (_manager.IsDefault(_collection)) { SetFiles(); - Penumbra.ResidentResources.Reload(); + _manager.ResidentResources.Reload(); } - Penumbra.CharacterUtility.LoadingFinished -= ApplyStoredManipulations; - Penumbra.Log.Debug( $"{_collection.AnonymizedName}: Loaded {loaded} delayed meta manipulations." ); + _manager.CharacterUtility.LoadingFinished -= ApplyStoredManipulations; + Penumbra.Log.Debug($"{_collection.AnonymizedName}: Loaded {loaded} delayed meta manipulations."); } - public void SetFile( MetaIndex metaIndex ) + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public unsafe void SetFile(MetaBaseFile? file, MetaIndex metaIndex) { - switch( metaIndex ) - { - case MetaIndex.Eqp: - SetFile( _eqpFile, metaIndex ); - break; - case MetaIndex.Gmp: - SetFile( _gmpFile, metaIndex ); - break; - case MetaIndex.HumanCmp: - SetFile( _cmpFile, metaIndex ); - break; - case MetaIndex.FaceEst: - SetFile( _estFaceFile, metaIndex ); - break; - case MetaIndex.HairEst: - SetFile( _estHairFile, metaIndex ); - break; - case MetaIndex.HeadEst: - SetFile( _estHeadFile, metaIndex ); - break; - case MetaIndex.BodyEst: - SetFile( _estBodyFile, metaIndex ); - break; - default: - var i = CharacterUtilityData.EqdpIndices.IndexOf( metaIndex ); - if( i != -1 ) - { - SetFile( _eqdpFiles[ i ], metaIndex ); - } - - break; - } - } - - [MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )] - private static unsafe void SetFile( MetaBaseFile? file, MetaIndex metaIndex ) - { - if( file == null ) - { - Penumbra.CharacterUtility.ResetResource( metaIndex ); - } + if (file == null) + _manager.CharacterUtility.ResetResource(metaIndex); else - { - Penumbra.CharacterUtility.SetResource( metaIndex, ( IntPtr )file.Data, file.Length ); - } + _manager.CharacterUtility.SetResource(metaIndex, (IntPtr)file.Data, file.Length); } - [MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )] - private static unsafe CharacterUtility.MetaList.MetaReverter TemporarilySetFile( MetaBaseFile? file, MetaIndex metaIndex ) + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public unsafe CharacterUtility.MetaList.MetaReverter TemporarilySetFile(MetaBaseFile? file, MetaIndex metaIndex) => file == null - ? Penumbra.CharacterUtility.TemporarilyResetResource( metaIndex ) - : Penumbra.CharacterUtility.TemporarilySetResource( metaIndex, ( IntPtr )file.Data, file.Length ); + ? _manager.CharacterUtility.TemporarilyResetResource(metaIndex) + : _manager.CharacterUtility.TemporarilySetResource(metaIndex, (IntPtr)file.Data, file.Length); } \ No newline at end of file