mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-31 21:03:48 +01:00
Rework some metastuff.
This commit is contained in:
parent
53818f3556
commit
f0b970c102
25 changed files with 312 additions and 221 deletions
|
|
@ -11,6 +11,9 @@ namespace Penumbra.Meta.Files;
|
|||
// We only support manipulating the racial scaling parameters at the moment.
|
||||
public sealed unsafe class CmpFile : MetaBaseFile
|
||||
{
|
||||
public static readonly Interop.CharacterUtility.InternalIndex InternalIndex =
|
||||
Interop.CharacterUtility.ReverseIndices[ ( int )CharacterUtility.Index.HumanCmp ];
|
||||
|
||||
private const int RacialScalingStart = 0x2A800;
|
||||
|
||||
public float this[ SubRace subRace, RspAttribute attribute ]
|
||||
|
|
@ -31,7 +34,7 @@ public sealed unsafe class CmpFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public CmpFile()
|
||||
: base( CharacterUtility.HumanCmpIdx )
|
||||
: base( CharacterUtility.Index.HumanCmp )
|
||||
{
|
||||
AllocateData( DefaultData.Length );
|
||||
Reset();
|
||||
|
|
@ -39,7 +42,7 @@ public sealed unsafe class CmpFile : MetaBaseFile
|
|||
|
||||
public static float GetDefault( SubRace subRace, RspAttribute attribute )
|
||||
{
|
||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource( CharacterUtility.HumanCmpIdx ).Address;
|
||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource( InternalIndex ).Address;
|
||||
return *( float* )( data + RacialScalingStart + ToRspIndex( subRace ) * RspEntry.ByteSize + ( int )attribute * 4 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,8 +114,8 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
public EqdpEntry GetDefault( int setIdx )
|
||||
=> GetDefault( Index, setIdx );
|
||||
|
||||
public static EqdpEntry GetDefault( int fileIdx, int setIdx )
|
||||
=> GetDefault( ( byte* )Penumbra.CharacterUtility.DefaultResource( fileIdx ).Address, setIdx );
|
||||
public static EqdpEntry GetDefault( Interop.CharacterUtility.InternalIndex idx, int setIdx )
|
||||
=> GetDefault( ( byte* )Penumbra.CharacterUtility.DefaultResource( idx ).Address, setIdx );
|
||||
|
||||
public static EqdpEntry GetDefault( byte* data, int setIdx )
|
||||
{
|
||||
|
|
@ -139,5 +139,5 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public static EqdpEntry GetDefault( GenderRace raceCode, bool accessory, int setIdx )
|
||||
=> GetDefault( CharacterUtility.EqdpIdx( raceCode, accessory ), setIdx );
|
||||
=> GetDefault( Interop.CharacterUtility.ReverseIndices[ ( int )CharacterUtility.EqdpIdx( raceCode, accessory ) ], setIdx );
|
||||
}
|
||||
|
|
@ -76,15 +76,15 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
}
|
||||
|
||||
public ExpandedEqpGmpBase( bool gmp )
|
||||
: base( gmp ? CharacterUtility.GmpIdx : CharacterUtility.EqpIdx )
|
||||
: base( gmp ? CharacterUtility.Index.Gmp : CharacterUtility.Index.Eqp )
|
||||
{
|
||||
AllocateData( MaxSize );
|
||||
Reset();
|
||||
}
|
||||
|
||||
protected static ulong GetDefaultInternal( int fileIdx, int setIdx, ulong def )
|
||||
protected static ulong GetDefaultInternal( Interop.CharacterUtility.InternalIndex fileIndex, int setIdx, ulong def )
|
||||
{
|
||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResources[ fileIdx ].Address;
|
||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource(fileIndex).Address;
|
||||
if( setIdx == 0 )
|
||||
{
|
||||
setIdx = 1;
|
||||
|
|
@ -112,6 +112,9 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
|
||||
public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable<EqpEntry>
|
||||
{
|
||||
public static readonly Interop.CharacterUtility.InternalIndex InternalIndex =
|
||||
Interop.CharacterUtility.ReverseIndices[ (int) CharacterUtility.Index.Eqp ];
|
||||
|
||||
public ExpandedEqpFile()
|
||||
: base( false )
|
||||
{ }
|
||||
|
|
@ -124,7 +127,7 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable<EqpEntry>
|
|||
|
||||
|
||||
public static EqpEntry GetDefault( int setIdx )
|
||||
=> ( EqpEntry )GetDefaultInternal( CharacterUtility.EqpIdx, setIdx, ( ulong )Eqp.DefaultEntry );
|
||||
=> ( EqpEntry )GetDefaultInternal( InternalIndex, setIdx, ( ulong )Eqp.DefaultEntry );
|
||||
|
||||
protected override unsafe void SetEmptyBlock( int idx )
|
||||
{
|
||||
|
|
@ -156,6 +159,9 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable<EqpEntry>
|
|||
|
||||
public sealed class ExpandedGmpFile : ExpandedEqpGmpBase, IEnumerable<GmpEntry>
|
||||
{
|
||||
public static readonly Interop.CharacterUtility.InternalIndex InternalIndex =
|
||||
Interop.CharacterUtility.ReverseIndices[( int )CharacterUtility.Index.Gmp];
|
||||
|
||||
public ExpandedGmpFile()
|
||||
: base( true )
|
||||
{ }
|
||||
|
|
@ -167,7 +173,7 @@ public sealed class ExpandedGmpFile : ExpandedEqpGmpBase, IEnumerable<GmpEntry>
|
|||
}
|
||||
|
||||
public static GmpEntry GetDefault( int setIdx )
|
||||
=> ( GmpEntry )GetDefaultInternal( CharacterUtility.GmpIdx, setIdx, ( ulong )GmpEntry.Default );
|
||||
=> ( GmpEntry )GetDefaultInternal( InternalIndex, setIdx, ( ulong )GmpEntry.Default );
|
||||
|
||||
public void Reset( IEnumerable< int > entries )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Runtime.InteropServices;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
||||
namespace Penumbra.Meta.Files;
|
||||
|
|
@ -53,7 +54,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
|||
ResizeResources( Length + IncreaseSize );
|
||||
}
|
||||
|
||||
var control = ( Info* )( Data + 4 );
|
||||
var control = ( Info* )( Data + 4 );
|
||||
var entries = ( ushort* )( control + Count );
|
||||
|
||||
for( var i = Count - 1; i >= idx; --i )
|
||||
|
|
@ -95,7 +96,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
|||
|
||||
for( var i = idx; i < Count - 1; ++i )
|
||||
{
|
||||
entries[i - 2] = entries[i + 1];
|
||||
entries[ i - 2 ] = entries[ i + 1 ];
|
||||
}
|
||||
|
||||
entries[ Count - 3 ] = 0;
|
||||
|
|
@ -174,7 +175,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public EstFile( EstManipulation.EstType estType )
|
||||
: base( ( int )estType )
|
||||
: base( ( CharacterUtility.Index )estType )
|
||||
{
|
||||
var length = DefaultData.Length;
|
||||
AllocateData( length + IncreaseSize );
|
||||
|
|
@ -182,11 +183,11 @@ public sealed unsafe class EstFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public ushort GetDefault( GenderRace genderRace, ushort setId )
|
||||
=> GetDefault( ( EstManipulation.EstType )Index, genderRace, setId );
|
||||
=> GetDefault( Index, genderRace, setId );
|
||||
|
||||
public static ushort GetDefault( EstManipulation.EstType estType, GenderRace genderRace, ushort setId )
|
||||
public static ushort GetDefault( Interop.CharacterUtility.InternalIndex index, GenderRace genderRace, ushort setId )
|
||||
{
|
||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource( ( int )estType ).Address;
|
||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource( index ).Address;
|
||||
var count = *( int* )data;
|
||||
var span = new ReadOnlySpan< Info >( data + 4, count );
|
||||
var (idx, found) = FindEntry( span, genderRace, setId );
|
||||
|
|
@ -197,4 +198,10 @@ public sealed unsafe class EstFile : MetaBaseFile
|
|||
|
||||
return *( ushort* )( data + 4 + count * EntryDescSize + idx * EntrySize );
|
||||
}
|
||||
|
||||
public static ushort GetDefault( CharacterUtility.Index index, GenderRace genderRace, ushort setId )
|
||||
=> GetDefault( Interop.CharacterUtility.ReverseIndices[ ( int )index ], genderRace, setId );
|
||||
|
||||
public static ushort GetDefault( EstManipulation.EstType estType, GenderRace genderRace, ushort setId )
|
||||
=> GetDefault( ( CharacterUtility.Index )estType, genderRace, setId );
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using Dalamud.Memory;
|
||||
using Penumbra.GameData.Util;
|
||||
using CharacterUtility = Penumbra.Interop.CharacterUtility;
|
||||
|
||||
namespace Penumbra.Meta.Files;
|
||||
|
||||
|
|
@ -8,10 +9,10 @@ public unsafe class MetaBaseFile : IDisposable
|
|||
{
|
||||
public byte* Data { get; private set; }
|
||||
public int Length { get; private set; }
|
||||
public int Index { get; }
|
||||
public CharacterUtility.InternalIndex Index { get; }
|
||||
|
||||
public MetaBaseFile( int idx )
|
||||
=> Index = idx;
|
||||
public MetaBaseFile( Interop.Structs.CharacterUtility.Index idx )
|
||||
=> Index = CharacterUtility.ReverseIndices[(int) idx];
|
||||
|
||||
protected (IntPtr Data, int Length) DefaultData
|
||||
=> Penumbra.CharacterUtility.DefaultResource( Index );
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ public partial class MetaManager
|
|||
private readonly List< RspManipulation > _cmpManipulations = new();
|
||||
|
||||
public void SetCmpFiles()
|
||||
=> SetFile( _cmpFile, CharacterUtility.HumanCmpIdx );
|
||||
=> SetFile( _cmpFile, CharacterUtility.Index.HumanCmp );
|
||||
|
||||
public static void ResetCmpFiles()
|
||||
=> SetFile( null, CharacterUtility.HumanCmpIdx );
|
||||
=> SetFile( null, CharacterUtility.Index.HumanCmp );
|
||||
|
||||
public void ResetCmp()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Penumbra.Meta.Manager;
|
|||
|
||||
public partial class MetaManager
|
||||
{
|
||||
private readonly ExpandedEqdpFile?[] _eqdpFiles = new ExpandedEqdpFile?[CharacterUtility.NumEqdpFiles - 2]; // TODO: female Hrothgar
|
||||
private readonly ExpandedEqdpFile?[] _eqdpFiles = new ExpandedEqdpFile[CharacterUtility.EqdpIndices.Length]; // TODO: female Hrothgar
|
||||
|
||||
private readonly List< EqdpManipulation > _eqdpManipulations = new();
|
||||
|
||||
|
|
@ -33,9 +33,10 @@ public partial class MetaManager
|
|||
|
||||
public void ResetEqdp()
|
||||
{
|
||||
foreach( var file in _eqdpFiles )
|
||||
foreach( var file in _eqdpFiles.OfType<ExpandedEqdpFile>() )
|
||||
{
|
||||
file?.Reset( _eqdpManipulations.Where( m => m.FileIndex() == file.Index ).Select( m => ( int )m.SetId ) );
|
||||
var relevant = Interop.CharacterUtility.RelevantIndices[ file.Index.Value ];
|
||||
file.Reset( _eqdpManipulations.Where( m => m.FileIndex() == relevant ).Select( m => ( int )m.SetId ) );
|
||||
}
|
||||
|
||||
_eqdpManipulations.Clear();
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ public partial class MetaManager
|
|||
private readonly List< EqpManipulation > _eqpManipulations = new();
|
||||
|
||||
public void SetEqpFiles()
|
||||
=> SetFile( _eqpFile, CharacterUtility.EqpIdx );
|
||||
=> SetFile( _eqpFile, CharacterUtility.Index.Eqp );
|
||||
|
||||
public static void ResetEqpFiles()
|
||||
=> SetFile( null, CharacterUtility.EqpIdx );
|
||||
=> SetFile( null, CharacterUtility.Index.Eqp );
|
||||
|
||||
public void ResetEqp()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,18 +19,18 @@ public partial class MetaManager
|
|||
|
||||
public void SetEstFiles()
|
||||
{
|
||||
SetFile( _estFaceFile, CharacterUtility.FaceEstIdx );
|
||||
SetFile( _estHairFile, CharacterUtility.HairEstIdx );
|
||||
SetFile( _estBodyFile, CharacterUtility.BodyEstIdx );
|
||||
SetFile( _estHeadFile, CharacterUtility.HeadEstIdx );
|
||||
SetFile( _estFaceFile, CharacterUtility.Index.FaceEst );
|
||||
SetFile( _estHairFile, CharacterUtility.Index.HairEst );
|
||||
SetFile( _estBodyFile, CharacterUtility.Index.BodyEst );
|
||||
SetFile( _estHeadFile, CharacterUtility.Index.HeadEst );
|
||||
}
|
||||
|
||||
public static void ResetEstFiles()
|
||||
{
|
||||
SetFile( null, CharacterUtility.FaceEstIdx );
|
||||
SetFile( null, CharacterUtility.HairEstIdx );
|
||||
SetFile( null, CharacterUtility.BodyEstIdx );
|
||||
SetFile( null, CharacterUtility.HeadEstIdx );
|
||||
SetFile( null, CharacterUtility.Index.FaceEst );
|
||||
SetFile( null, CharacterUtility.Index.HairEst );
|
||||
SetFile( null, CharacterUtility.Index.BodyEst );
|
||||
SetFile( null, CharacterUtility.Index.HeadEst );
|
||||
}
|
||||
|
||||
public void ResetEst()
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ public partial class MetaManager
|
|||
private readonly List< GmpManipulation > _gmpManipulations = new();
|
||||
|
||||
public void SetGmpFiles()
|
||||
=> SetFile( _gmpFile, CharacterUtility.GmpIdx );
|
||||
=> SetFile( _gmpFile, CharacterUtility.Index.Gmp );
|
||||
|
||||
public static void ResetGmpFiles()
|
||||
=> SetFile( null, CharacterUtility.GmpIdx );
|
||||
=> SetFile( null, CharacterUtility.Index.Gmp );
|
||||
|
||||
public void ResetGmp()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Runtime.CompilerServices;
|
||||
using Dalamud.Logging;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
|
|
@ -168,7 +169,7 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
|
|||
}
|
||||
|
||||
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
|
||||
private static unsafe void SetFile( MetaBaseFile? file, int index )
|
||||
private static unsafe void SetFile( MetaBaseFile? file, CharacterUtility.Index index )
|
||||
{
|
||||
if( file == null )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public readonly struct EqdpManipulation : IMetaManipulation< EqdpManipulation >
|
|||
return set != 0 ? set : Slot.CompareTo( other.Slot );
|
||||
}
|
||||
|
||||
public int FileIndex()
|
||||
public CharacterUtility.Index FileIndex()
|
||||
=> CharacterUtility.EqdpIdx( Names.CombinedRace( Gender, Race ), Slot.IsAccessory() );
|
||||
|
||||
public bool Apply( ExpandedEqdpFile file )
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation >
|
|||
return set != 0 ? set : Slot.CompareTo( other.Slot );
|
||||
}
|
||||
|
||||
public int FileIndex()
|
||||
=> CharacterUtility.EqpIdx;
|
||||
public CharacterUtility.Index FileIndex()
|
||||
=> CharacterUtility.Index.Eqp;
|
||||
|
||||
public bool Apply( ExpandedEqpFile file )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
|
|||
{
|
||||
public enum EstType : byte
|
||||
{
|
||||
Hair = CharacterUtility.HairEstIdx,
|
||||
Face = CharacterUtility.FaceEstIdx,
|
||||
Body = CharacterUtility.BodyEstIdx,
|
||||
Head = CharacterUtility.HeadEstIdx,
|
||||
Hair = CharacterUtility.Index.HairEst,
|
||||
Face = CharacterUtility.Index.FaceEst,
|
||||
Body = CharacterUtility.Index.BodyEst,
|
||||
Head = CharacterUtility.Index.HeadEst,
|
||||
}
|
||||
|
||||
public ushort Entry { get; init; } // SkeletonIdx.
|
||||
|
|
@ -76,8 +76,8 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
|
|||
return s != 0 ? s : SetId.CompareTo( other.SetId );
|
||||
}
|
||||
|
||||
public int FileIndex()
|
||||
=> ( int )Slot;
|
||||
public CharacterUtility.Index FileIndex()
|
||||
=> ( CharacterUtility.Index )Slot;
|
||||
|
||||
public bool Apply( EstFile file )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ public readonly struct GmpManipulation : IMetaManipulation< GmpManipulation >
|
|||
public int CompareTo( GmpManipulation other )
|
||||
=> SetId.CompareTo( other.SetId );
|
||||
|
||||
public int FileIndex()
|
||||
=> CharacterUtility.GmpIdx;
|
||||
public CharacterUtility.Index FileIndex()
|
||||
=> CharacterUtility.Index.Gmp;
|
||||
|
||||
public bool Apply( ExpandedGmpFile file )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Newtonsoft.Json;
|
|||
using Newtonsoft.Json.Converters;
|
||||
using Penumbra.GameData.ByteString;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
|
||||
namespace Penumbra.Meta.Manipulations;
|
||||
|
|
@ -119,8 +120,8 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation >
|
|||
return b != 0 ? b : Variant.CompareTo( other.Variant );
|
||||
}
|
||||
|
||||
public int FileIndex()
|
||||
=> -1;
|
||||
public CharacterUtility.Index FileIndex()
|
||||
=> ( CharacterUtility.Index )( -1 );
|
||||
|
||||
public Utf8GamePath GamePath()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@ using System.Runtime.InteropServices;
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
||||
namespace Penumbra.Meta.Manipulations;
|
||||
|
||||
public interface IMetaManipulation
|
||||
{
|
||||
public int FileIndex();
|
||||
public CharacterUtility.Index FileIndex();
|
||||
}
|
||||
|
||||
public interface IMetaManipulation< T >
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ public readonly struct RspManipulation : IMetaManipulation< RspManipulation >
|
|||
return s != 0 ? s : Attribute.CompareTo( other.Attribute );
|
||||
}
|
||||
|
||||
public int FileIndex()
|
||||
=> CharacterUtility.HumanCmpIdx;
|
||||
public CharacterUtility.Index FileIndex()
|
||||
=> CharacterUtility.Index.HumanCmp;
|
||||
|
||||
public bool Apply( CmpFile file )
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue