From b09a736a852457889a51b5457670d9e7fcb50fde Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 11 Jul 2022 14:08:52 +0200 Subject: [PATCH] Actually clear cache and restore imc files. --- Penumbra/Api/TempModManager.cs | 1 + .../Collections/CollectionManager.Active.cs | 8 ++-- .../Collections/ModCollection.Cache.Access.cs | 2 +- Penumbra/Collections/ModCollection.Cache.cs | 1 + Penumbra/Interop/MetaFileManager.cs | 48 +++++++++++++++---- Penumbra/Meta/Files/ImcFile.cs | 2 +- Penumbra/Meta/Manager/MetaManager.Imc.cs | 3 +- 7 files changed, 50 insertions(+), 15 deletions(-) diff --git a/Penumbra/Api/TempModManager.cs b/Penumbra/Api/TempModManager.cs index cebc6de9..996306e8 100644 --- a/Penumbra/Api/TempModManager.cs +++ b/Penumbra/Api/TempModManager.cs @@ -153,6 +153,7 @@ public class TempModManager if( _collections.Remove( characterName, out var c ) ) { _mods.Remove( c ); + c.ClearCache(); return true; } diff --git a/Penumbra/Collections/CollectionManager.Active.cs b/Penumbra/Collections/CollectionManager.Active.cs index 392a5a9f..486080a5 100644 --- a/Penumbra/Collections/CollectionManager.Active.cs +++ b/Penumbra/Collections/CollectionManager.Active.cs @@ -87,7 +87,6 @@ public partial class ModCollection newCollection.CreateCache(); } - RemoveCache( oldCollectionIdx ); switch( collectionType ) { case CollectionType.Default: @@ -110,6 +109,7 @@ public partial class ModCollection break; } + RemoveCache( oldCollectionIdx ); UpdateCurrentCollectionInUse(); CollectionChanged.Invoke( collectionType, this[ oldCollectionIdx ], newCollection, characterName ); @@ -128,7 +128,7 @@ public partial class ModCollection // Create a special collection if it does not exist and set it to Empty. public bool CreateSpecialCollection( CollectionType collectionType ) { - if( !collectionType.IsSpecial() || _specialCollections[( int )collectionType] != null ) + if( !collectionType.IsSpecial() || _specialCollections[ ( int )collectionType ] != null ) { return false; } @@ -136,7 +136,6 @@ public partial class ModCollection _specialCollections[ ( int )collectionType ] = Empty; CollectionChanged.Invoke( collectionType, null, Empty, null ); return true; - } // Remove a special collection if it exists @@ -361,7 +360,8 @@ public partial class ModCollection private void RemoveCache( int idx ) { - if( idx != Default.Index + if( idx != Empty.Index + && idx != Default.Index && idx != Current.Index && _specialCollections.All( c => c == null || c.Index != idx ) && _characters.Values.All( c => c.Index != idx ) ) diff --git a/Penumbra/Collections/ModCollection.Cache.Access.cs b/Penumbra/Collections/ModCollection.Cache.Access.cs index e289096b..73d2c7ca 100644 --- a/Penumbra/Collections/ModCollection.Cache.Access.cs +++ b/Penumbra/Collections/ModCollection.Cache.Access.cs @@ -56,7 +56,7 @@ public partial class ModCollection // Clear the current cache. - private void ClearCache() + internal void ClearCache() { _cache?.Dispose(); _cache = null; diff --git a/Penumbra/Collections/ModCollection.Cache.cs b/Penumbra/Collections/ModCollection.Cache.cs index 332d0fa5..a3654608 100644 --- a/Penumbra/Collections/ModCollection.Cache.cs +++ b/Penumbra/Collections/ModCollection.Cache.cs @@ -59,6 +59,7 @@ public partial class ModCollection public void Dispose() { + MetaManipulations.Dispose(); _collection.ModSettingChanged -= OnModSettingChange; _collection.InheritanceChanged -= OnInheritanceChange; Penumbra.CharacterUtility.LoadingFinished -= IncrementCounter; diff --git a/Penumbra/Interop/MetaFileManager.cs b/Penumbra/Interop/MetaFileManager.cs index 51a6dc19..38413124 100644 --- a/Penumbra/Interop/MetaFileManager.cs +++ b/Penumbra/Interop/MetaFileManager.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using Dalamud.Hooking; using Dalamud.Logging; using Dalamud.Utility.Signatures; using FFXIVClientStructs.FFXIV.Client.System.Memory; using Penumbra.GameData.ByteString; using Penumbra.Interop.Structs; +using Penumbra.Meta.Files; namespace Penumbra.Interop; @@ -28,6 +30,7 @@ public unsafe class MetaFileManager : IDisposable // We only need this if using any meta file. [Signature( "E8 ?? ?? ?? ?? 41 B9 ?? ?? ?? ?? 4C 8B C0" )] public IntPtr GetFileSpaceAddress; + public IMemorySpace* GetFileSpace() => ( ( delegate* unmanaged< IMemorySpace* > )GetFileSpaceAddress )(); @@ -45,7 +48,8 @@ public unsafe class MetaFileManager : IDisposable public delegate void ClearResource( ResourceHandle* resource ); public Hook< ClearResource > ClearDefaultResourceHook = null!; - private readonly Dictionary< IntPtr, (IntPtr, int) > _originalImcData = new(); + private readonly Dictionary< IntPtr, (ImcFile, IntPtr, int) > _originalImcData = new(); + private readonly Dictionary< ImcFile, IntPtr > _currentUse = new(); // We store the original data of loaded IMCs so that we can restore it before they get destroyed, // similar to the other meta files, just with arbitrary destruction. @@ -53,21 +57,48 @@ public unsafe class MetaFileManager : IDisposable { if( _originalImcData.TryGetValue( ( IntPtr )resource, out var data ) ) { - PluginLog.Debug( "Restoring data of {$Name:l} (0x{Resource}) to 0x{Data:X} and Length {Length} before deletion.", - Utf8String.FromSpanUnsafe( resource->FileNameSpan(), true, null, null ), ( ulong )resource, ( ulong )data.Item1, data.Item2 ); - resource->SetData( data.Item1, data.Item2 ); - _originalImcData.Remove( ( IntPtr )resource ); + ClearImcData( resource, data.Item1, data.Item2, data.Item3); } ClearDefaultResourceHook.Original( resource ); } + // Reset all files from a given IMC cache if they exist. + public void ResetByFile( ImcFile file ) + { + if( !_currentUse.TryGetValue( file, out var resource ) ) + { + return; + } + + if( _originalImcData.TryGetValue( resource, out var data ) ) + { + ClearImcData((ResourceHandle*) resource, file, data.Item2, data.Item3 ); + } + else + { + _currentUse.Remove( file ); + } + } + + // Clear a single IMC resource and reset it to its original data. + private void ClearImcData( ResourceHandle* resource, ImcFile file, IntPtr data, int length) + { + var name = new FullPath( Utf8String.FromSpanUnsafe( resource->FileNameSpan(), true ).ToString() ); + PluginLog.Debug( "Restoring data of {$Name:l} (0x{Resource}) to 0x{Data:X} and Length {Length} before deletion.", name, + ( ulong )resource, ( ulong )data, length ); + resource->SetData( data, length ); + _originalImcData.Remove( ( IntPtr )resource ); + _currentUse.Remove( file ); + } + // Called when a new IMC is manipulated to store its data. - public void AddImcFile( ResourceHandle* resource, IntPtr data, int length ) + public void AddImcFile( ResourceHandle* resource, ImcFile file, IntPtr data, int length) { PluginLog.Debug( "Storing data 0x{Data:X} of Length {Length} for {$Name:l} (0x{Resource:X}).", ( ulong )data, length, Utf8String.FromSpanUnsafe( resource->FileNameSpan(), true, null, null ), ( ulong )resource ); - _originalImcData[ ( IntPtr )resource ] = ( data, length ); + _originalImcData[ ( IntPtr )resource ] = ( file, data, length ); + _currentUse[ file ] = ( IntPtr )resource; } // Initialize the hook at VFunc 25, which is called when default resources (and IMC resources do not overwrite it) destroy their data. @@ -83,12 +114,13 @@ public unsafe class MetaFileManager : IDisposable ClearDefaultResourceHook.Dispose(); // Restore all IMCs to their default values on dispose. // This should only be relevant when testing/disabling/reenabling penumbra. - foreach( var (resourcePtr, (data, length)) in _originalImcData ) + foreach( var (resourcePtr, (file, data, length)) in _originalImcData ) { var resource = ( ResourceHandle* )resourcePtr; resource->SetData( data, length ); } _originalImcData.Clear(); + _currentUse.Clear(); } } \ No newline at end of file diff --git a/Penumbra/Meta/Files/ImcFile.cs b/Penumbra/Meta/Files/ImcFile.cs index 965df0f9..17ced337 100644 --- a/Penumbra/Meta/Files/ImcFile.cs +++ b/Penumbra/Meta/Files/ImcFile.cs @@ -229,7 +229,7 @@ public unsafe class ImcFile : MetaBaseFile resource->SetData( ( IntPtr )Data, Length ); if( firstTime ) { - Penumbra.MetaFileManager.AddImcFile( resource, data, length ); + Penumbra.MetaFileManager.AddImcFile( resource, this, data, length ); } } } \ No newline at end of file diff --git a/Penumbra/Meta/Manager/MetaManager.Imc.cs b/Penumbra/Meta/Manager/MetaManager.Imc.cs index 2c6f656c..3dd7752c 100644 --- a/Penumbra/Meta/Manager/MetaManager.Imc.cs +++ b/Penumbra/Meta/Manager/MetaManager.Imc.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Dalamud.Logging; using FFXIVClientStructs.FFXIV.Client.System.Resource; using OtterGui.Filesystem; @@ -118,9 +119,9 @@ public partial class MetaManager { foreach( var file in _imcFiles.Values ) { + Penumbra.MetaFileManager.ResetByFile( file ); file.Dispose(); } - _imcFiles.Clear(); _imcManipulations.Clear(); RestoreImcDelegate();