Actually clear cache and restore imc files.

This commit is contained in:
Ottermandias 2022-07-11 14:08:52 +02:00
parent 4030487472
commit b09a736a85
7 changed files with 50 additions and 15 deletions

View file

@ -153,6 +153,7 @@ public class TempModManager
if( _collections.Remove( characterName, out var c ) ) if( _collections.Remove( characterName, out var c ) )
{ {
_mods.Remove( c ); _mods.Remove( c );
c.ClearCache();
return true; return true;
} }

View file

@ -87,7 +87,6 @@ public partial class ModCollection
newCollection.CreateCache(); newCollection.CreateCache();
} }
RemoveCache( oldCollectionIdx );
switch( collectionType ) switch( collectionType )
{ {
case CollectionType.Default: case CollectionType.Default:
@ -110,6 +109,7 @@ public partial class ModCollection
break; break;
} }
RemoveCache( oldCollectionIdx );
UpdateCurrentCollectionInUse(); UpdateCurrentCollectionInUse();
CollectionChanged.Invoke( collectionType, this[ oldCollectionIdx ], newCollection, characterName ); CollectionChanged.Invoke( collectionType, this[ oldCollectionIdx ], newCollection, characterName );
@ -136,7 +136,6 @@ public partial class ModCollection
_specialCollections[ ( int )collectionType ] = Empty; _specialCollections[ ( int )collectionType ] = Empty;
CollectionChanged.Invoke( collectionType, null, Empty, null ); CollectionChanged.Invoke( collectionType, null, Empty, null );
return true; return true;
} }
// Remove a special collection if it exists // Remove a special collection if it exists
@ -361,7 +360,8 @@ public partial class ModCollection
private void RemoveCache( int idx ) private void RemoveCache( int idx )
{ {
if( idx != Default.Index if( idx != Empty.Index
&& idx != Default.Index
&& idx != Current.Index && idx != Current.Index
&& _specialCollections.All( c => c == null || c.Index != idx ) && _specialCollections.All( c => c == null || c.Index != idx )
&& _characters.Values.All( c => c.Index != idx ) ) && _characters.Values.All( c => c.Index != idx ) )

View file

@ -56,7 +56,7 @@ public partial class ModCollection
// Clear the current cache. // Clear the current cache.
private void ClearCache() internal void ClearCache()
{ {
_cache?.Dispose(); _cache?.Dispose();
_cache = null; _cache = null;

View file

@ -59,6 +59,7 @@ public partial class ModCollection
public void Dispose() public void Dispose()
{ {
MetaManipulations.Dispose();
_collection.ModSettingChanged -= OnModSettingChange; _collection.ModSettingChanged -= OnModSettingChange;
_collection.InheritanceChanged -= OnInheritanceChange; _collection.InheritanceChanged -= OnInheritanceChange;
Penumbra.CharacterUtility.LoadingFinished -= IncrementCounter; Penumbra.CharacterUtility.LoadingFinished -= IncrementCounter;

View file

@ -1,12 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using Dalamud.Hooking; using Dalamud.Hooking;
using Dalamud.Logging; using Dalamud.Logging;
using Dalamud.Utility.Signatures; using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Client.System.Memory;
using Penumbra.GameData.ByteString; using Penumbra.GameData.ByteString;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using Penumbra.Meta.Files;
namespace Penumbra.Interop; namespace Penumbra.Interop;
@ -28,6 +30,7 @@ public unsafe class MetaFileManager : IDisposable
// We only need this if using any meta file. // We only need this if using any meta file.
[Signature( "E8 ?? ?? ?? ?? 41 B9 ?? ?? ?? ?? 4C 8B C0" )] [Signature( "E8 ?? ?? ?? ?? 41 B9 ?? ?? ?? ?? 4C 8B C0" )]
public IntPtr GetFileSpaceAddress; public IntPtr GetFileSpaceAddress;
public IMemorySpace* GetFileSpace() public IMemorySpace* GetFileSpace()
=> ( ( delegate* unmanaged< IMemorySpace* > )GetFileSpaceAddress )(); => ( ( delegate* unmanaged< IMemorySpace* > )GetFileSpaceAddress )();
@ -45,7 +48,8 @@ public unsafe class MetaFileManager : IDisposable
public delegate void ClearResource( ResourceHandle* resource ); public delegate void ClearResource( ResourceHandle* resource );
public Hook< ClearResource > ClearDefaultResourceHook = null!; 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, // 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. // 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 ) ) 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.", ClearImcData( resource, data.Item1, data.Item2, data.Item3);
Utf8String.FromSpanUnsafe( resource->FileNameSpan(), true, null, null ), ( ulong )resource, ( ulong )data.Item1, data.Item2 );
resource->SetData( data.Item1, data.Item2 );
_originalImcData.Remove( ( IntPtr )resource );
} }
ClearDefaultResourceHook.Original( resource ); 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. // 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, 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 ); 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. // 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(); ClearDefaultResourceHook.Dispose();
// Restore all IMCs to their default values on dispose. // Restore all IMCs to their default values on dispose.
// This should only be relevant when testing/disabling/reenabling penumbra. // 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; var resource = ( ResourceHandle* )resourcePtr;
resource->SetData( data, length ); resource->SetData( data, length );
} }
_originalImcData.Clear(); _originalImcData.Clear();
_currentUse.Clear();
} }
} }

View file

@ -229,7 +229,7 @@ public unsafe class ImcFile : MetaBaseFile
resource->SetData( ( IntPtr )Data, Length ); resource->SetData( ( IntPtr )Data, Length );
if( firstTime ) if( firstTime )
{ {
Penumbra.MetaFileManager.AddImcFile( resource, data, length ); Penumbra.MetaFileManager.AddImcFile( resource, this, data, length );
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Dalamud.Logging; using Dalamud.Logging;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using OtterGui.Filesystem; using OtterGui.Filesystem;
@ -118,9 +119,9 @@ public partial class MetaManager
{ {
foreach( var file in _imcFiles.Values ) foreach( var file in _imcFiles.Values )
{ {
Penumbra.MetaFileManager.ResetByFile( file );
file.Dispose(); file.Dispose();
} }
_imcFiles.Clear(); _imcFiles.Clear();
_imcManipulations.Clear(); _imcManipulations.Clear();
RestoreImcDelegate(); RestoreImcDelegate();