Switch CharacterUtility to use linked lists of changes.

This commit is contained in:
Ottermandias 2022-09-16 18:47:19 +02:00
parent 9753c14b32
commit af3a07c227
2 changed files with 171 additions and 55 deletions

View file

@ -4,7 +4,7 @@ using Dalamud.Utility.Signatures;
namespace Penumbra.Interop;
public unsafe class CharacterUtility : IDisposable
public unsafe partial class CharacterUtility : IDisposable
{
public record struct InternalIndex( int Value );
@ -34,17 +34,15 @@ public unsafe class CharacterUtility : IDisposable
public static readonly InternalIndex[] ReverseIndices
= Enumerable.Range( 0, Structs.CharacterUtility.TotalNumResources )
.Select( i => new InternalIndex( Array.IndexOf( RelevantIndices, (Structs.CharacterUtility.Index) i ) ) )
.Select( i => new InternalIndex( Array.IndexOf( RelevantIndices, ( Structs.CharacterUtility.Index )i ) ) )
.ToArray();
private readonly (IntPtr Address, int Size)[] _defaultResources = new (IntPtr, int)[RelevantIndices.Length];
public (IntPtr Address, int Size) DefaultResource( Structs.CharacterUtility.Index idx )
=> _defaultResources[ ReverseIndices[ ( int )idx ].Value ];
private readonly List[] _lists = Enumerable.Range( 0, RelevantIndices.Length )
.Select( idx => new List( new InternalIndex( idx ) ) )
.ToArray();
public (IntPtr Address, int Size) DefaultResource( InternalIndex idx )
=> _defaultResources[ idx.Value ];
=> _lists[ idx.Value ].DefaultResource;
public CharacterUtility()
{
@ -60,30 +58,25 @@ public unsafe class CharacterUtility : IDisposable
// We store the default data of the resources so we can always restore them.
private void LoadDefaultResources( object _ )
{
var missingCount = 0;
if( Address == null )
{
return;
}
var anyMissing = false;
for( var i = 0; i < RelevantIndices.Length; ++i )
{
if( _defaultResources[ i ].Size == 0 )
var list = _lists[ i ];
if( !list.Ready )
{
var resource = Address->Resource( RelevantIndices[i] );
var data = resource->GetData();
if( data.Data != IntPtr.Zero && data.Length != 0 )
{
_defaultResources[ i ] = data;
}
else
{
++missingCount;
}
var resource = Address->Resource( RelevantIndices[ i ] );
var (data, length) = resource->GetData();
list.SetDefaultResource( data, length );
anyMissing |= !_lists[ i ].Ready;
}
}
if( missingCount == 0 )
if( !anyMissing )
{
Ready = true;
LoadingFinished.Invoke();
@ -91,51 +84,27 @@ public unsafe class CharacterUtility : IDisposable
}
}
// Set the data of one of the stored resources to a given pointer and length.
public bool SetResource( Structs.CharacterUtility.Index resourceIdx, IntPtr data, int length )
public List.MetaReverter SetResource( Structs.CharacterUtility.Index resourceIdx, IntPtr data, int length )
{
if( !Ready )
{
Penumbra.Log.Error( $"Can not set resource {resourceIdx}: CharacterUtility not ready yet." );
return false;
}
var resource = Address->Resource( resourceIdx );
var ret = resource->SetData( data, length );
Penumbra.Log.Verbose( $"Set resource {resourceIdx} to 0x{( ulong )data:X} ({length} bytes).");
return ret;
var idx = ReverseIndices[ ( int )resourceIdx ];
var list = _lists[ idx.Value ];
return list.SetResource( data, length );
}
// Reset the data of one of the stored resources to its default values.
public void ResetResource( Structs.CharacterUtility.Index resourceIdx )
public List.MetaReverter ResetResource( Structs.CharacterUtility.Index resourceIdx )
{
if( !Ready )
{
Penumbra.Log.Error( $"Can not reset {resourceIdx}: CharacterUtility not ready yet." );
return;
}
var (data, length) = DefaultResource( resourceIdx);
var resource = Address->Resource( resourceIdx );
Penumbra.Log.Verbose( $"Reset resource {resourceIdx} to default at 0x{(ulong)data:X} ({length} bytes).");
resource->SetData( data, length );
var idx = ReverseIndices[ ( int )resourceIdx ];
var list = _lists[ idx.Value ];
return list.ResetResource();
}
// Return all relevant resources to the default resource.
public void ResetAll()
{
if( !Ready )
foreach( var list in _lists )
{
Penumbra.Log.Error( "Can not reset all resources: CharacterUtility not ready yet." );
return;
list.Dispose();
}
foreach( var idx in RelevantIndices )
{
ResetResource( idx );
}
Penumbra.Log.Debug( "Reset all CharacterUtility resources to default." );
}
public void Dispose()