mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-02-20 14:57:50 +01:00
Metamanipulations seemingly working.
This commit is contained in:
parent
707570615c
commit
6f527a1dbc
26 changed files with 1637 additions and 1237 deletions
|
|
@ -47,7 +47,8 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
return *( EqdpEntry* )( Data + DataOffset + EqdpEntrySize * idx );
|
||||
var x = new ReadOnlySpan< ushort >( ( ushort* )Data, Length / 2 );
|
||||
return ( EqdpEntry )( *( ushort* )( Data + DataOffset + EqdpEntrySize * idx ) );
|
||||
}
|
||||
set
|
||||
{
|
||||
|
|
@ -56,7 +57,7 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
*( EqdpEntry* )( Data + DataOffset + EqdpEntrySize * idx ) = value;
|
||||
*( ushort* )( Data + DataOffset + EqdpEntrySize * idx ) = ( ushort )value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,9 +66,12 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
var def = ( byte* )DefaultData.Data;
|
||||
Functions.MemCpyUnchecked( Data, def, IdentifierSize + PreambleSize );
|
||||
|
||||
var controlPtr = ( ushort* )( def + IdentifierSize + PreambleSize );
|
||||
var dataBasePtr = ( byte* )( controlPtr + BlockCount );
|
||||
var myDataPtr = ( ushort* )( Data + IdentifierSize + PreambleSize + 2 * BlockCount );
|
||||
var controlPtr = ( ushort* )( def + IdentifierSize + PreambleSize );
|
||||
var dataBasePtr = controlPtr + BlockCount;
|
||||
var myDataPtrStart = ( ushort* )( Data + IdentifierSize + PreambleSize + 2 * BlockCount );
|
||||
var myDataPtr = myDataPtrStart;
|
||||
var myControlPtr = ( ushort* )( Data + IdentifierSize + PreambleSize );
|
||||
var x = new ReadOnlySpan< ushort >( ( ushort* )Data, Length / 2 );
|
||||
for( var i = 0; i < BlockCount; ++i )
|
||||
{
|
||||
if( controlPtr[ i ] == CollapsedBlock )
|
||||
|
|
@ -76,11 +80,16 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
}
|
||||
else
|
||||
{
|
||||
var y = new ReadOnlySpan< ushort >( dataBasePtr + controlPtr[ i ], BlockSize );
|
||||
var z = new ReadOnlySpan< ushort >( myDataPtr, BlockSize );
|
||||
Functions.MemCpyUnchecked( myDataPtr, dataBasePtr + controlPtr[ i ], BlockSize * EqdpEntrySize );
|
||||
}
|
||||
|
||||
myDataPtr += BlockSize;
|
||||
myControlPtr[ i ] = ( ushort )( i * BlockSize );
|
||||
myDataPtr += BlockSize;
|
||||
}
|
||||
|
||||
Functions.MemSet( myDataPtr, 0, Length - ( int )( ( byte* )myDataPtr - Data ) );
|
||||
}
|
||||
|
||||
public void Reset( IEnumerable< int > entries )
|
||||
|
|
@ -102,7 +111,7 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
DataOffset = IdentifierSize + PreambleSize + totalBlockCount * BlockHeaderSize;
|
||||
|
||||
var fullLength = DataOffset + totalBlockCount * totalBlockSize;
|
||||
fullLength += ( FileAlignment - ( Length & ( FileAlignment - 1 ) ) ) & ( FileAlignment - 1 );
|
||||
fullLength += ( FileAlignment - ( fullLength & ( FileAlignment - 1 ) ) ) & ( FileAlignment - 1 );
|
||||
AllocateData( fullLength );
|
||||
Reset();
|
||||
}
|
||||
|
|
@ -128,8 +137,9 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
return 0;
|
||||
}
|
||||
|
||||
var blockData = ( EqdpEntry* )( data + IdentifierSize + PreambleSize + totalBlockCount * 2 + block );
|
||||
return *( blockData + blockIdx % blockSize );
|
||||
var blockData = ( ushort* )( data + IdentifierSize + PreambleSize + totalBlockCount * 2 + block * 2 );
|
||||
var x = new ReadOnlySpan< ushort >( blockData, blockSize );
|
||||
return (EqdpEntry) (*( blockData + setIdx % blockSize ));
|
||||
}
|
||||
|
||||
public static EqdpEntry GetDefault( GenderRace raceCode, bool accessory, int setIdx )
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
|
@ -24,17 +25,17 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
public ulong ControlBlock
|
||||
=> *( ulong* )Data;
|
||||
|
||||
protected T Get< T >( int idx ) where T : unmanaged
|
||||
protected ulong GetInternal( int idx )
|
||||
{
|
||||
return idx switch
|
||||
{
|
||||
>= Count => throw new IndexOutOfRangeException(),
|
||||
<= 1 => *( ( T* )Data + 1 ),
|
||||
_ => *( ( T* )Data + idx ),
|
||||
<= 1 => *( ( ulong* )Data + 1 ),
|
||||
_ => *( ( ulong* )Data + idx ),
|
||||
};
|
||||
}
|
||||
|
||||
protected void Set< T >( int idx, T value ) where T : unmanaged
|
||||
protected void SetInternal( int idx, ulong value )
|
||||
{
|
||||
idx = idx switch
|
||||
{
|
||||
|
|
@ -43,7 +44,7 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
_ => idx,
|
||||
};
|
||||
|
||||
*( ( T* )Data + idx ) = value;
|
||||
*( ( ulong* )Data + idx ) = value;
|
||||
}
|
||||
|
||||
protected virtual void SetEmptyBlock( int idx )
|
||||
|
|
@ -53,21 +54,24 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
|
||||
public sealed override void Reset()
|
||||
{
|
||||
var ptr = ( byte* )DefaultData.Data;
|
||||
var controlBlock = *( ulong* )ptr;
|
||||
*( ulong* )Data = ulong.MaxValue;
|
||||
for( var i = 0; i < 64; ++i )
|
||||
var ptr = ( byte* )DefaultData.Data;
|
||||
var controlBlock = *( ulong* )ptr;
|
||||
var expandedBlocks = 0;
|
||||
for( var i = 0; i < NumBlocks; ++i )
|
||||
{
|
||||
var collapsed = ( ( controlBlock >> i ) & 1 ) == 0;
|
||||
if( !collapsed )
|
||||
{
|
||||
Functions.MemCpyUnchecked( Data + i * BlockSize * EntrySize, ptr + i * BlockSize * EntrySize, BlockSize * EntrySize );
|
||||
Functions.MemCpyUnchecked( Data + i * BlockSize * EntrySize, ptr + expandedBlocks * BlockSize * EntrySize, BlockSize * EntrySize );
|
||||
expandedBlocks++;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEmptyBlock( i );
|
||||
}
|
||||
}
|
||||
|
||||
*( ulong* )Data = ulong.MaxValue;
|
||||
}
|
||||
|
||||
public ExpandedEqpGmpBase( bool gmp )
|
||||
|
|
@ -77,7 +81,7 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
Reset();
|
||||
}
|
||||
|
||||
protected static T GetDefault< T >( int fileIdx, int setIdx, T def ) where T : unmanaged
|
||||
protected static ulong GetDefaultInternal( int fileIdx, int setIdx, ulong def )
|
||||
{
|
||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResources[ fileIdx ].Address;
|
||||
if( setIdx == 0 )
|
||||
|
|
@ -100,7 +104,7 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
|
||||
var count = BitOperations.PopCount( control & ( blockBit - 1 ) );
|
||||
var idx = setIdx % BlockSize;
|
||||
var ptr = ( T* )data + BlockSize * count + idx;
|
||||
var ptr = ( ulong* )data + BlockSize * count + idx;
|
||||
return *ptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -113,12 +117,12 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase
|
|||
|
||||
public EqpEntry this[ int idx ]
|
||||
{
|
||||
get => Get< EqpEntry >( idx );
|
||||
set => Set( idx, value );
|
||||
get => ( EqpEntry )GetInternal( idx );
|
||||
set => SetInternal( idx, ( ulong )value );
|
||||
}
|
||||
|
||||
public static EqpEntry GetDefault( int setIdx )
|
||||
=> GetDefault( CharacterUtility.EqpIdx, setIdx, Eqp.DefaultEntry );
|
||||
=> ( EqpEntry )GetDefaultInternal( CharacterUtility.EqpIdx, setIdx, ( ulong )Eqp.DefaultEntry );
|
||||
|
||||
protected override unsafe void SetEmptyBlock( int idx )
|
||||
{
|
||||
|
|
@ -147,12 +151,12 @@ public sealed class ExpandedGmpFile : ExpandedEqpGmpBase
|
|||
|
||||
public GmpEntry this[ int idx ]
|
||||
{
|
||||
get => Get< GmpEntry >( idx );
|
||||
set => Set( idx, value );
|
||||
get => ( GmpEntry )GetInternal( idx );
|
||||
set => SetInternal( idx, ( ulong )value );
|
||||
}
|
||||
|
||||
public static GmpEntry GetDefault( int setIdx )
|
||||
=> GetDefault( CharacterUtility.GmpIdx, setIdx, GmpEntry.Default );
|
||||
=> ( GmpEntry )GetDefaultInternal( CharacterUtility.GmpIdx, setIdx, ( ulong )GmpEntry.Default );
|
||||
|
||||
public void Reset( IEnumerable< int > entries )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Numerics;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Memory;
|
||||
|
|
@ -7,6 +8,7 @@ using Penumbra.GameData.ByteString;
|
|||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
||||
namespace Penumbra.Meta.Files;
|
||||
|
||||
|
|
@ -64,41 +66,57 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
=> NumParts * sizeof( ImcEntry ) * ( Count + 1 ) + PreambleSize;
|
||||
|
||||
public int Count
|
||||
=> *( ushort* )Data;
|
||||
|
||||
public ushort PartMask
|
||||
=> *( ushort* )( Data + 2 );
|
||||
=> CountInternal( Data );
|
||||
|
||||
public readonly int NumParts;
|
||||
public readonly Utf8GamePath Path;
|
||||
|
||||
public ImcEntry* DefaultPartPtr( int partIdx )
|
||||
private static int CountInternal( byte* data )
|
||||
=> *( ushort* )data;
|
||||
|
||||
private static ushort PartMask( byte* data )
|
||||
=> *( ushort* )( data + 2 );
|
||||
|
||||
private static ImcEntry* DefaultPartPtr( byte* data, int partIdx )
|
||||
{
|
||||
var flag = 1 << partIdx;
|
||||
if( ( PartMask & flag ) == 0 )
|
||||
if( ( PartMask( data ) & flag ) == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ( ImcEntry* )( Data + PreambleSize ) + partIdx;
|
||||
return ( ImcEntry* )( data + PreambleSize ) + partIdx;
|
||||
}
|
||||
|
||||
public ImcEntry* VariantPtr( int partIdx, int variantIdx )
|
||||
private static ImcEntry* VariantPtr( byte* data, int partIdx, int variantIdx )
|
||||
{
|
||||
if( variantIdx == 0 )
|
||||
{
|
||||
return DefaultPartPtr( data, partIdx );
|
||||
}
|
||||
|
||||
--variantIdx;
|
||||
var flag = 1 << partIdx;
|
||||
if( ( PartMask & flag ) == 0 || variantIdx >= Count )
|
||||
|
||||
if( ( PartMask( data ) & flag ) == 0 || variantIdx >= CountInternal( data ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var numParts = NumParts;
|
||||
var ptr = ( ImcEntry* )( Data + PreambleSize );
|
||||
var numParts = BitOperations.PopCount( PartMask( data ) );
|
||||
var ptr = ( ImcEntry* )( data + PreambleSize );
|
||||
ptr += numParts;
|
||||
ptr += variantIdx * numParts;
|
||||
ptr += partIdx;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public ImcEntry GetEntry( int partIdx, int variantIdx )
|
||||
{
|
||||
var ptr = VariantPtr( Data, partIdx, variantIdx );
|
||||
return ptr == null ? new ImcEntry() : *ptr;
|
||||
}
|
||||
|
||||
public static int PartIndex( EquipSlot slot )
|
||||
=> slot switch
|
||||
{
|
||||
|
|
@ -122,7 +140,6 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
return true;
|
||||
}
|
||||
|
||||
var numParts = NumParts;
|
||||
if( ActualLength > Length )
|
||||
{
|
||||
PluginLog.Warning( "Adding too many variants to IMC, size exceeded." );
|
||||
|
|
@ -130,10 +147,10 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
}
|
||||
|
||||
var defaultPtr = ( ImcEntry* )( Data + PreambleSize );
|
||||
var endPtr = defaultPtr + ( numVariants + 1 ) * numParts;
|
||||
for( var ptr = defaultPtr + numParts; ptr < endPtr; ptr += numParts )
|
||||
var endPtr = defaultPtr + ( numVariants + 1 ) * NumParts;
|
||||
for( var ptr = defaultPtr + NumParts; ptr < endPtr; ptr += NumParts )
|
||||
{
|
||||
Functions.MemCpyUnchecked( ptr, defaultPtr, numParts * sizeof( ImcEntry ) );
|
||||
Functions.MemCpyUnchecked( ptr, defaultPtr, NumParts * sizeof( ImcEntry ) );
|
||||
}
|
||||
|
||||
PluginLog.Verbose( "Expanded imc from {Count} to {NewCount} variants.", Count, numVariants );
|
||||
|
|
@ -143,15 +160,14 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
|
||||
public bool SetEntry( int partIdx, int variantIdx, ImcEntry entry )
|
||||
{
|
||||
var numParts = NumParts;
|
||||
if( partIdx >= numParts )
|
||||
if( partIdx >= NumParts )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureVariantCount( variantIdx + 1 );
|
||||
EnsureVariantCount( variantIdx );
|
||||
|
||||
var variantPtr = VariantPtr( partIdx, variantIdx );
|
||||
var variantPtr = VariantPtr( Data, partIdx, variantIdx );
|
||||
if( variantPtr == null )
|
||||
{
|
||||
PluginLog.Error( "Error during expansion of imc file." );
|
||||
|
|
@ -168,9 +184,20 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
}
|
||||
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
var file = Dalamud.GameData.GetFile( Path.ToString() );
|
||||
fixed( byte* ptr = file!.Data )
|
||||
{
|
||||
Functions.MemCpyUnchecked( Data, ptr, file.Data.Length );
|
||||
Functions.MemSet( Data + file.Data.Length, 0, Length - file.Data.Length );
|
||||
}
|
||||
}
|
||||
|
||||
public ImcFile( Utf8GamePath path )
|
||||
: base( 0 )
|
||||
{
|
||||
Path = path;
|
||||
var file = Dalamud.GameData.GetFile( path.ToString() );
|
||||
if( file == null )
|
||||
{
|
||||
|
|
@ -182,6 +209,22 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
NumParts = BitOperations.PopCount( *( ushort* )( ptr + 2 ) );
|
||||
AllocateData( file.Data.Length + sizeof( ImcEntry ) * 100 * NumParts );
|
||||
Functions.MemCpyUnchecked( Data, ptr, file.Data.Length );
|
||||
Functions.MemSet( Data + file.Data.Length, 0, sizeof( ImcEntry ) * 100 * NumParts );
|
||||
}
|
||||
}
|
||||
|
||||
public static ImcEntry GetDefault( Utf8GamePath path, EquipSlot slot, int variantIdx )
|
||||
{
|
||||
var file = Dalamud.GameData.GetFile( path.ToString() );
|
||||
if( file == null )
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
fixed( byte* ptr = file.Data )
|
||||
{
|
||||
var entry = VariantPtr( ptr, PartIndex( slot ), variantIdx );
|
||||
return entry == null ? new ImcEntry() : *entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue