mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 20:24:17 +01:00
Rework some metastuff.
This commit is contained in:
parent
53818f3556
commit
f0b970c102
25 changed files with 312 additions and 221 deletions
|
|
@ -2,8 +2,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Metadata.Ecma335;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Penumbra.GameData.Enums;
|
namespace Penumbra.GameData.Enums;
|
||||||
|
|
||||||
|
|
@ -31,7 +29,9 @@ public enum EquipSlot : byte
|
||||||
FullBody = 19,
|
FullBody = 19,
|
||||||
BodyHands = 20,
|
BodyHands = 20,
|
||||||
BodyLegsFeet = 21,
|
BodyLegsFeet = 21,
|
||||||
All = 22, // Not officially existing
|
ChestHands = 22,
|
||||||
|
Nothing = 23,
|
||||||
|
All = 24, // Not officially existing
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EquipSlotExtensions
|
public static class EquipSlotExtensions
|
||||||
|
|
@ -111,7 +111,8 @@ public static class EquipSlotExtensions
|
||||||
EquipSlot.FullBody => EquipSlot.Body,
|
EquipSlot.FullBody => EquipSlot.Body,
|
||||||
EquipSlot.BodyHands => EquipSlot.Body,
|
EquipSlot.BodyHands => EquipSlot.Body,
|
||||||
EquipSlot.BodyLegsFeet => EquipSlot.Body,
|
EquipSlot.BodyLegsFeet => EquipSlot.Body,
|
||||||
_ => throw new InvalidEnumArgumentException(),
|
EquipSlot.ChestHands => EquipSlot.Body,
|
||||||
|
_ => throw new InvalidEnumArgumentException($"{value} ({(int) value}) is not valid."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Lumina.Data.Files;
|
using Lumina.Data.Files;
|
||||||
using OtterGui;
|
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using Functions = Penumbra.GameData.Util.Functions;
|
|
||||||
|
|
||||||
namespace Penumbra.Import.Dds;
|
namespace Penumbra.Import.Dds;
|
||||||
|
|
||||||
public class TextureImporter
|
public static class TextureImporter
|
||||||
{
|
{
|
||||||
private static void WriteHeader( byte[] target, int width, int height )
|
private static void WriteHeader( byte[] target, int width, int height )
|
||||||
{
|
{
|
||||||
|
|
@ -91,7 +89,4 @@ public class TextureImporter
|
||||||
texData = buffer;
|
texData = buffer;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Import( string inputFile )
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,8 @@ namespace Penumbra.Interop;
|
||||||
|
|
||||||
public unsafe class CharacterUtility : IDisposable
|
public unsafe class CharacterUtility : IDisposable
|
||||||
{
|
{
|
||||||
|
public record struct InternalIndex( int Value );
|
||||||
|
|
||||||
// A static pointer to the CharacterUtility address.
|
// A static pointer to the CharacterUtility address.
|
||||||
[Signature( "48 8B 05 ?? ?? ?? ?? 83 B9", ScanType = ScanType.StaticAddress )]
|
[Signature( "48 8B 05 ?? ?? ?? ?? 83 B9", ScanType = ScanType.StaticAddress )]
|
||||||
private readonly Structs.CharacterUtility** _characterUtilityAddress = null;
|
private readonly Structs.CharacterUtility** _characterUtilityAddress = null;
|
||||||
|
|
@ -28,25 +30,22 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
|
|
||||||
// The relevant indices depend on which meta manipulations we allow for.
|
// The relevant indices depend on which meta manipulations we allow for.
|
||||||
// The defines are set in the project configuration.
|
// The defines are set in the project configuration.
|
||||||
public static readonly int[] RelevantIndices
|
public static readonly Structs.CharacterUtility.Index[]
|
||||||
= Array.Empty< int >()
|
RelevantIndices = Enum.GetValues< Structs.CharacterUtility.Index >();
|
||||||
.Append( Structs.CharacterUtility.EqpIdx )
|
|
||||||
.Append( Structs.CharacterUtility.GmpIdx )
|
public static readonly InternalIndex[] ReverseIndices
|
||||||
.Concat( Enumerable.Range( Structs.CharacterUtility.EqdpStartIdx, Structs.CharacterUtility.NumEqdpFiles )
|
= Enumerable.Range( 0, Structs.CharacterUtility.TotalNumResources )
|
||||||
.Where( i => i is not Structs.CharacterUtility.EqdpStartIdx + 15 or Structs.CharacterUtility.EqdpStartIdx + 15 + Structs.CharacterUtility.NumEqdpFiles / 2 ) ) // TODO: Female Hrothgar
|
.Select( i => new InternalIndex( Array.IndexOf( RelevantIndices, (Structs.CharacterUtility.Index) i ) ) )
|
||||||
.Append( Structs.CharacterUtility.HumanCmpIdx )
|
|
||||||
.Concat( Enumerable.Range( Structs.CharacterUtility.FaceEstIdx, 4 ) )
|
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
public static readonly int[] ReverseIndices
|
|
||||||
= Enumerable.Range( 0, Structs.CharacterUtility.NumResources )
|
|
||||||
.Select( i => Array.IndexOf( RelevantIndices, i ) ).ToArray();
|
|
||||||
|
|
||||||
|
private readonly (IntPtr Address, int Size)[] _defaultResources = new (IntPtr, int)[RelevantIndices.Length];
|
||||||
|
|
||||||
public 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 ];
|
||||||
|
|
||||||
public (IntPtr Address, int Size) DefaultResource( int fullIdx )
|
public (IntPtr Address, int Size) DefaultResource( InternalIndex idx )
|
||||||
=> DefaultResources[ ReverseIndices[ fullIdx ] ];
|
=> _defaultResources[ idx.Value ];
|
||||||
|
|
||||||
public CharacterUtility()
|
public CharacterUtility()
|
||||||
{
|
{
|
||||||
|
|
@ -70,13 +69,13 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
|
|
||||||
for( var i = 0; i < RelevantIndices.Length; ++i )
|
for( var i = 0; i < RelevantIndices.Length; ++i )
|
||||||
{
|
{
|
||||||
if( DefaultResources[ i ].Size == 0 )
|
if( _defaultResources[ i ].Size == 0 )
|
||||||
{
|
{
|
||||||
var resource = ( Structs.ResourceHandle* )Address->Resources[ RelevantIndices[ i ] ];
|
var resource = Address->Resource( RelevantIndices[i] );
|
||||||
var data = resource->GetData();
|
var data = resource->GetData();
|
||||||
if( data.Data != IntPtr.Zero && data.Length != 0 )
|
if( data.Data != IntPtr.Zero && data.Length != 0 )
|
||||||
{
|
{
|
||||||
DefaultResources[ i ] = data;
|
_defaultResources[ i ] = data;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -94,7 +93,7 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the data of one of the stored resources to a given pointer and length.
|
// Set the data of one of the stored resources to a given pointer and length.
|
||||||
public bool SetResource( int resourceIdx, IntPtr data, int length )
|
public bool SetResource( Structs.CharacterUtility.Index resourceIdx, IntPtr data, int length )
|
||||||
{
|
{
|
||||||
if( !Ready )
|
if( !Ready )
|
||||||
{
|
{
|
||||||
|
|
@ -109,7 +108,7 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the data of one of the stored resources to its default values.
|
// Reset the data of one of the stored resources to its default values.
|
||||||
public void ResetResource( int resourceIdx )
|
public void ResetResource( Structs.CharacterUtility.Index resourceIdx )
|
||||||
{
|
{
|
||||||
if( !Ready )
|
if( !Ready )
|
||||||
{
|
{
|
||||||
|
|
@ -117,8 +116,7 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var relevantIdx = ReverseIndices[ resourceIdx ];
|
var (data, length) = DefaultResource( resourceIdx);
|
||||||
var (data, length) = DefaultResources[ relevantIdx ];
|
|
||||||
var resource = Address->Resource( resourceIdx );
|
var resource = Address->Resource( resourceIdx );
|
||||||
PluginLog.Verbose( "Reset resource {Idx} to default at 0x{DefaultData:X} ({NewLength} bytes).", resourceIdx, ( ulong )data, length );
|
PluginLog.Verbose( "Reset resource {Idx} to default at 0x{DefaultData:X} ({NewLength} bytes).", resourceIdx, ( ulong )data, length );
|
||||||
resource->SetData( data, length );
|
resource->SetData( data, length );
|
||||||
|
|
|
||||||
|
|
@ -160,11 +160,11 @@ public unsafe partial class PathResolver
|
||||||
{
|
{
|
||||||
if( _inChangeCustomize )
|
if( _inChangeCustomize )
|
||||||
{
|
{
|
||||||
using var rsp = MetaChanger.ChangeCmp( _parent, drawObject );
|
|
||||||
_rspSetupCharacterHook.Original( drawObject, unk2, unk3, unk4, unk5 );
|
_rspSetupCharacterHook.Original( drawObject, unk2, unk3, unk4, unk5 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
using var rsp = MetaChanger.ChangeCmp( _parent, drawObject );
|
||||||
_rspSetupCharacterHook.Original( drawObject, unk2, unk3, unk4, unk5 );
|
_rspSetupCharacterHook.Original( drawObject, unk2, unk3, unk4, unk5 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,87 +8,153 @@ namespace Penumbra.Interop.Structs;
|
||||||
[StructLayout( LayoutKind.Explicit )]
|
[StructLayout( LayoutKind.Explicit )]
|
||||||
public unsafe struct CharacterUtility
|
public unsafe struct CharacterUtility
|
||||||
{
|
{
|
||||||
// TODO: female Hrothgar
|
public enum Index : int
|
||||||
public static readonly int[] EqdpIndices
|
{
|
||||||
= Enumerable.Range( EqdpStartIdx, NumEqdpFiles ).Where( i => i != EqdpStartIdx + 15 && i != EqdpStartIdx + 15 + NumEqdpFiles / 2 ).ToArray();
|
Eqp = 0,
|
||||||
|
Gmp = 2,
|
||||||
|
|
||||||
public const int NumResources = 86;
|
Eqdp0101 = 3,
|
||||||
public const int EqpIdx = 0;
|
Eqdp0201,
|
||||||
public const int GmpIdx = 2;
|
Eqdp0301,
|
||||||
public const int HumanCmpIdx = 64;
|
Eqdp0401,
|
||||||
public const int FaceEstIdx = 65;
|
Eqdp0501,
|
||||||
public const int HairEstIdx = 66;
|
Eqdp0601,
|
||||||
public const int HeadEstIdx = 67;
|
Eqdp0701,
|
||||||
public const int BodyEstIdx = 68;
|
Eqdp0801,
|
||||||
public const int EqdpStartIdx = 3;
|
Eqdp0901,
|
||||||
public const int NumEqdpFiles = 2 * 28;
|
Eqdp1001,
|
||||||
|
Eqdp1101,
|
||||||
|
Eqdp1201,
|
||||||
|
Eqdp1301,
|
||||||
|
Eqdp1401,
|
||||||
|
Eqdp1501,
|
||||||
|
|
||||||
public static int EqdpIdx( GenderRace raceCode, bool accessory )
|
//Eqdp1601, // TODO: female Hrothgar
|
||||||
=> ( accessory ? NumEqdpFiles / 2 : 0 )
|
Eqdp1701 = Eqdp1501 + 2,
|
||||||
+ ( int )raceCode switch
|
Eqdp1801,
|
||||||
{
|
Eqdp0104,
|
||||||
0101 => EqdpStartIdx,
|
Eqdp0204,
|
||||||
0201 => EqdpStartIdx + 1,
|
Eqdp0504,
|
||||||
0301 => EqdpStartIdx + 2,
|
Eqdp0604,
|
||||||
0401 => EqdpStartIdx + 3,
|
Eqdp0704,
|
||||||
0501 => EqdpStartIdx + 4,
|
Eqdp0804,
|
||||||
0601 => EqdpStartIdx + 5,
|
Eqdp1304,
|
||||||
0701 => EqdpStartIdx + 6,
|
Eqdp1404,
|
||||||
0801 => EqdpStartIdx + 7,
|
Eqdp9104,
|
||||||
0901 => EqdpStartIdx + 8,
|
Eqdp9204,
|
||||||
1001 => EqdpStartIdx + 9,
|
|
||||||
1101 => EqdpStartIdx + 10,
|
Eqdp0101Acc,
|
||||||
1201 => EqdpStartIdx + 11,
|
Eqdp0201Acc,
|
||||||
1301 => EqdpStartIdx + 12,
|
Eqdp0301Acc,
|
||||||
1401 => EqdpStartIdx + 13,
|
Eqdp0401Acc,
|
||||||
1501 => EqdpStartIdx + 14,
|
Eqdp0501Acc,
|
||||||
1601 => EqdpStartIdx + 15, // TODO: female Hrothgar
|
Eqdp0601Acc,
|
||||||
1701 => EqdpStartIdx + 16,
|
Eqdp0701Acc,
|
||||||
1801 => EqdpStartIdx + 17,
|
Eqdp0801Acc,
|
||||||
0104 => EqdpStartIdx + 18,
|
Eqdp0901Acc,
|
||||||
0204 => EqdpStartIdx + 19,
|
Eqdp1001Acc,
|
||||||
0504 => EqdpStartIdx + 20,
|
Eqdp1101Acc,
|
||||||
0604 => EqdpStartIdx + 21,
|
Eqdp1201Acc,
|
||||||
0704 => EqdpStartIdx + 22,
|
Eqdp1301Acc,
|
||||||
0804 => EqdpStartIdx + 23,
|
Eqdp1401Acc,
|
||||||
1304 => EqdpStartIdx + 24,
|
Eqdp1501Acc,
|
||||||
1404 => EqdpStartIdx + 25,
|
|
||||||
9104 => EqdpStartIdx + 26,
|
//Eqdp1601Acc, // TODO: female Hrothgar
|
||||||
9204 => EqdpStartIdx + 27,
|
Eqdp1701Acc = Eqdp1501Acc + 2,
|
||||||
_ => -1,
|
Eqdp1801Acc,
|
||||||
};
|
Eqdp0104Acc,
|
||||||
|
Eqdp0204Acc,
|
||||||
|
Eqdp0504Acc,
|
||||||
|
Eqdp0604Acc,
|
||||||
|
Eqdp0704Acc,
|
||||||
|
Eqdp0804Acc,
|
||||||
|
Eqdp1304Acc,
|
||||||
|
Eqdp1404Acc,
|
||||||
|
Eqdp9104Acc,
|
||||||
|
Eqdp9204Acc,
|
||||||
|
|
||||||
|
HumanCmp = 64,
|
||||||
|
FaceEst,
|
||||||
|
HairEst,
|
||||||
|
HeadEst,
|
||||||
|
BodyEst,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly Index[] EqdpIndices = Enum.GetNames< Index >()
|
||||||
|
.Zip( Enum.GetValues< Index >() )
|
||||||
|
.Where( n => n.First.StartsWith( "Eqdp" ) )
|
||||||
|
.Select( n => n.Second ).ToArray();
|
||||||
|
|
||||||
|
public const int TotalNumResources = 87;
|
||||||
|
|
||||||
|
public static Index EqdpIdx( GenderRace raceCode, bool accessory )
|
||||||
|
=> +( int )raceCode switch
|
||||||
|
{
|
||||||
|
0101 => accessory ? Index.Eqdp0101Acc : Index.Eqdp0101,
|
||||||
|
0201 => accessory ? Index.Eqdp0201Acc : Index.Eqdp0201,
|
||||||
|
0301 => accessory ? Index.Eqdp0301Acc : Index.Eqdp0301,
|
||||||
|
0401 => accessory ? Index.Eqdp0401Acc : Index.Eqdp0401,
|
||||||
|
0501 => accessory ? Index.Eqdp0501Acc : Index.Eqdp0501,
|
||||||
|
0601 => accessory ? Index.Eqdp0601Acc : Index.Eqdp0601,
|
||||||
|
0701 => accessory ? Index.Eqdp0701Acc : Index.Eqdp0701,
|
||||||
|
0801 => accessory ? Index.Eqdp0801Acc : Index.Eqdp0801,
|
||||||
|
0901 => accessory ? Index.Eqdp0901Acc : Index.Eqdp0901,
|
||||||
|
1001 => accessory ? Index.Eqdp1001Acc : Index.Eqdp1001,
|
||||||
|
1101 => accessory ? Index.Eqdp1101Acc : Index.Eqdp1101,
|
||||||
|
1201 => accessory ? Index.Eqdp1201Acc : Index.Eqdp1201,
|
||||||
|
1301 => accessory ? Index.Eqdp1301Acc : Index.Eqdp1301,
|
||||||
|
1401 => accessory ? Index.Eqdp1401Acc : Index.Eqdp1401,
|
||||||
|
1501 => accessory ? Index.Eqdp1501Acc : Index.Eqdp1501,
|
||||||
|
//1601 => accessory ? RelevantIndex.Eqdp1601Acc : RelevantIndex.Eqdp1601, Female Hrothgar
|
||||||
|
1701 => accessory ? Index.Eqdp1701Acc : Index.Eqdp1701,
|
||||||
|
1801 => accessory ? Index.Eqdp1801Acc : Index.Eqdp1801,
|
||||||
|
0104 => accessory ? Index.Eqdp0104Acc : Index.Eqdp0104,
|
||||||
|
0204 => accessory ? Index.Eqdp0204Acc : Index.Eqdp0204,
|
||||||
|
0504 => accessory ? Index.Eqdp0504Acc : Index.Eqdp0504,
|
||||||
|
0604 => accessory ? Index.Eqdp0604Acc : Index.Eqdp0604,
|
||||||
|
0704 => accessory ? Index.Eqdp0704Acc : Index.Eqdp0704,
|
||||||
|
0804 => accessory ? Index.Eqdp0804Acc : Index.Eqdp0804,
|
||||||
|
1304 => accessory ? Index.Eqdp1304Acc : Index.Eqdp1304,
|
||||||
|
1404 => accessory ? Index.Eqdp1404Acc : Index.Eqdp1404,
|
||||||
|
9104 => accessory ? Index.Eqdp9104Acc : Index.Eqdp9104,
|
||||||
|
9204 => accessory ? Index.Eqdp9204Acc : Index.Eqdp9204,
|
||||||
|
_ => ( Index )( -1 ),
|
||||||
|
};
|
||||||
|
|
||||||
[FieldOffset( 0 )]
|
[FieldOffset( 0 )]
|
||||||
public void* VTable;
|
public void* VTable;
|
||||||
|
|
||||||
[FieldOffset( 8 )]
|
[FieldOffset( 8 )]
|
||||||
public fixed ulong Resources[NumResources];
|
public fixed ulong Resources[TotalNumResources];
|
||||||
|
|
||||||
[FieldOffset( 8 + EqpIdx * 8 )]
|
[FieldOffset( 8 + ( int )Index.Eqp * 8 )]
|
||||||
public ResourceHandle* EqpResource;
|
public ResourceHandle* EqpResource;
|
||||||
|
|
||||||
[FieldOffset( 8 + GmpIdx * 8 )]
|
[FieldOffset( 8 + ( int )Index.Gmp * 8 )]
|
||||||
public ResourceHandle* GmpResource;
|
public ResourceHandle* GmpResource;
|
||||||
|
|
||||||
public ResourceHandle* Resource( int idx )
|
public ResourceHandle* Resource( int idx )
|
||||||
=> ( ResourceHandle* )Resources[ idx ];
|
=> ( ResourceHandle* )Resources[ idx ];
|
||||||
|
|
||||||
public ResourceHandle* EqdpResource( GenderRace raceCode, bool accessory )
|
public ResourceHandle* Resource( Index idx )
|
||||||
=> Resource( EqdpIdx( raceCode, accessory ) );
|
=> Resource( ( int )idx );
|
||||||
|
|
||||||
[FieldOffset( 8 + HumanCmpIdx * 8 )]
|
public ResourceHandle* EqdpResource( GenderRace raceCode, bool accessory )
|
||||||
|
=> Resource( ( int )EqdpIdx( raceCode, accessory ) );
|
||||||
|
|
||||||
|
[FieldOffset( 8 + ( int )Index.HumanCmp * 8 )]
|
||||||
public ResourceHandle* HumanCmpResource;
|
public ResourceHandle* HumanCmpResource;
|
||||||
|
|
||||||
[FieldOffset( 8 + FaceEstIdx * 8 )]
|
[FieldOffset( 8 + ( int )Index.FaceEst * 8 )]
|
||||||
public ResourceHandle* FaceEstResource;
|
public ResourceHandle* FaceEstResource;
|
||||||
|
|
||||||
[FieldOffset( 8 + HairEstIdx * 8 )]
|
[FieldOffset( 8 + ( int )Index.HairEst * 8 )]
|
||||||
public ResourceHandle* HairEstResource;
|
public ResourceHandle* HairEstResource;
|
||||||
|
|
||||||
[FieldOffset( 8 + BodyEstIdx * 8 )]
|
[FieldOffset( 8 + ( int )Index.BodyEst * 8 )]
|
||||||
public ResourceHandle* BodyEstResource;
|
public ResourceHandle* BodyEstResource;
|
||||||
|
|
||||||
[FieldOffset( 8 + HeadEstIdx * 8 )]
|
[FieldOffset( 8 + ( int )Index.HeadEst * 8 )]
|
||||||
public ResourceHandle* HeadEstResource;
|
public ResourceHandle* HeadEstResource;
|
||||||
|
|
||||||
// not included resources have no known use case.
|
// not included resources have no known use case.
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ namespace Penumbra.Meta.Files;
|
||||||
// We only support manipulating the racial scaling parameters at the moment.
|
// We only support manipulating the racial scaling parameters at the moment.
|
||||||
public sealed unsafe class CmpFile : MetaBaseFile
|
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;
|
private const int RacialScalingStart = 0x2A800;
|
||||||
|
|
||||||
public float this[ SubRace subRace, RspAttribute attribute ]
|
public float this[ SubRace subRace, RspAttribute attribute ]
|
||||||
|
|
@ -31,7 +34,7 @@ public sealed unsafe class CmpFile : MetaBaseFile
|
||||||
}
|
}
|
||||||
|
|
||||||
public CmpFile()
|
public CmpFile()
|
||||||
: base( CharacterUtility.HumanCmpIdx )
|
: base( CharacterUtility.Index.HumanCmp )
|
||||||
{
|
{
|
||||||
AllocateData( DefaultData.Length );
|
AllocateData( DefaultData.Length );
|
||||||
Reset();
|
Reset();
|
||||||
|
|
@ -39,7 +42,7 @@ public sealed unsafe class CmpFile : MetaBaseFile
|
||||||
|
|
||||||
public static float GetDefault( SubRace subRace, RspAttribute attribute )
|
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 );
|
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 )
|
public EqdpEntry GetDefault( int setIdx )
|
||||||
=> GetDefault( Index, setIdx );
|
=> GetDefault( Index, setIdx );
|
||||||
|
|
||||||
public static EqdpEntry GetDefault( int fileIdx, int setIdx )
|
public static EqdpEntry GetDefault( Interop.CharacterUtility.InternalIndex idx, int setIdx )
|
||||||
=> GetDefault( ( byte* )Penumbra.CharacterUtility.DefaultResource( fileIdx ).Address, setIdx );
|
=> GetDefault( ( byte* )Penumbra.CharacterUtility.DefaultResource( idx ).Address, setIdx );
|
||||||
|
|
||||||
public static EqdpEntry GetDefault( byte* data, int 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 )
|
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 )
|
public ExpandedEqpGmpBase( bool gmp )
|
||||||
: base( gmp ? CharacterUtility.GmpIdx : CharacterUtility.EqpIdx )
|
: base( gmp ? CharacterUtility.Index.Gmp : CharacterUtility.Index.Eqp )
|
||||||
{
|
{
|
||||||
AllocateData( MaxSize );
|
AllocateData( MaxSize );
|
||||||
Reset();
|
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 )
|
if( setIdx == 0 )
|
||||||
{
|
{
|
||||||
setIdx = 1;
|
setIdx = 1;
|
||||||
|
|
@ -112,6 +112,9 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
||||||
|
|
||||||
public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable<EqpEntry>
|
public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable<EqpEntry>
|
||||||
{
|
{
|
||||||
|
public static readonly Interop.CharacterUtility.InternalIndex InternalIndex =
|
||||||
|
Interop.CharacterUtility.ReverseIndices[ (int) CharacterUtility.Index.Eqp ];
|
||||||
|
|
||||||
public ExpandedEqpFile()
|
public ExpandedEqpFile()
|
||||||
: base( false )
|
: base( false )
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -124,7 +127,7 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable<EqpEntry>
|
||||||
|
|
||||||
|
|
||||||
public static EqpEntry GetDefault( int setIdx )
|
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 )
|
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 sealed class ExpandedGmpFile : ExpandedEqpGmpBase, IEnumerable<GmpEntry>
|
||||||
{
|
{
|
||||||
|
public static readonly Interop.CharacterUtility.InternalIndex InternalIndex =
|
||||||
|
Interop.CharacterUtility.ReverseIndices[( int )CharacterUtility.Index.Gmp];
|
||||||
|
|
||||||
public ExpandedGmpFile()
|
public ExpandedGmpFile()
|
||||||
: base( true )
|
: base( true )
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -167,7 +173,7 @@ public sealed class ExpandedGmpFile : ExpandedEqpGmpBase, IEnumerable<GmpEntry>
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GmpEntry GetDefault( int setIdx )
|
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 )
|
public void Reset( IEnumerable< int > entries )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Util;
|
using Penumbra.GameData.Util;
|
||||||
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
namespace Penumbra.Meta.Files;
|
namespace Penumbra.Meta.Files;
|
||||||
|
|
@ -53,7 +54,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
||||||
ResizeResources( Length + IncreaseSize );
|
ResizeResources( Length + IncreaseSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
var control = ( Info* )( Data + 4 );
|
var control = ( Info* )( Data + 4 );
|
||||||
var entries = ( ushort* )( control + Count );
|
var entries = ( ushort* )( control + Count );
|
||||||
|
|
||||||
for( var i = Count - 1; i >= idx; --i )
|
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 )
|
for( var i = idx; i < Count - 1; ++i )
|
||||||
{
|
{
|
||||||
entries[i - 2] = entries[i + 1];
|
entries[ i - 2 ] = entries[ i + 1 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
entries[ Count - 3 ] = 0;
|
entries[ Count - 3 ] = 0;
|
||||||
|
|
@ -174,7 +175,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
||||||
}
|
}
|
||||||
|
|
||||||
public EstFile( EstManipulation.EstType estType )
|
public EstFile( EstManipulation.EstType estType )
|
||||||
: base( ( int )estType )
|
: base( ( CharacterUtility.Index )estType )
|
||||||
{
|
{
|
||||||
var length = DefaultData.Length;
|
var length = DefaultData.Length;
|
||||||
AllocateData( length + IncreaseSize );
|
AllocateData( length + IncreaseSize );
|
||||||
|
|
@ -182,11 +183,11 @@ public sealed unsafe class EstFile : MetaBaseFile
|
||||||
}
|
}
|
||||||
|
|
||||||
public ushort GetDefault( GenderRace genderRace, ushort setId )
|
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 count = *( int* )data;
|
||||||
var span = new ReadOnlySpan< Info >( data + 4, count );
|
var span = new ReadOnlySpan< Info >( data + 4, count );
|
||||||
var (idx, found) = FindEntry( span, genderRace, setId );
|
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 );
|
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 System;
|
||||||
using Dalamud.Memory;
|
using Dalamud.Memory;
|
||||||
using Penumbra.GameData.Util;
|
using Penumbra.GameData.Util;
|
||||||
|
using CharacterUtility = Penumbra.Interop.CharacterUtility;
|
||||||
|
|
||||||
namespace Penumbra.Meta.Files;
|
namespace Penumbra.Meta.Files;
|
||||||
|
|
||||||
|
|
@ -8,10 +9,10 @@ public unsafe class MetaBaseFile : IDisposable
|
||||||
{
|
{
|
||||||
public byte* Data { get; private set; }
|
public byte* Data { get; private set; }
|
||||||
public int Length { get; private set; }
|
public int Length { get; private set; }
|
||||||
public int Index { get; }
|
public CharacterUtility.InternalIndex Index { get; }
|
||||||
|
|
||||||
public MetaBaseFile( int idx )
|
public MetaBaseFile( Interop.Structs.CharacterUtility.Index idx )
|
||||||
=> Index = idx;
|
=> Index = CharacterUtility.ReverseIndices[(int) idx];
|
||||||
|
|
||||||
protected (IntPtr Data, int Length) DefaultData
|
protected (IntPtr Data, int Length) DefaultData
|
||||||
=> Penumbra.CharacterUtility.DefaultResource( Index );
|
=> Penumbra.CharacterUtility.DefaultResource( Index );
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ public partial class MetaManager
|
||||||
private readonly List< RspManipulation > _cmpManipulations = new();
|
private readonly List< RspManipulation > _cmpManipulations = new();
|
||||||
|
|
||||||
public void SetCmpFiles()
|
public void SetCmpFiles()
|
||||||
=> SetFile( _cmpFile, CharacterUtility.HumanCmpIdx );
|
=> SetFile( _cmpFile, CharacterUtility.Index.HumanCmp );
|
||||||
|
|
||||||
public static void ResetCmpFiles()
|
public static void ResetCmpFiles()
|
||||||
=> SetFile( null, CharacterUtility.HumanCmpIdx );
|
=> SetFile( null, CharacterUtility.Index.HumanCmp );
|
||||||
|
|
||||||
public void ResetCmp()
|
public void ResetCmp()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Penumbra.Meta.Manager;
|
||||||
|
|
||||||
public partial class MetaManager
|
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();
|
private readonly List< EqdpManipulation > _eqdpManipulations = new();
|
||||||
|
|
||||||
|
|
@ -33,9 +33,10 @@ public partial class MetaManager
|
||||||
|
|
||||||
public void ResetEqdp()
|
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();
|
_eqdpManipulations.Clear();
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ public partial class MetaManager
|
||||||
private readonly List< EqpManipulation > _eqpManipulations = new();
|
private readonly List< EqpManipulation > _eqpManipulations = new();
|
||||||
|
|
||||||
public void SetEqpFiles()
|
public void SetEqpFiles()
|
||||||
=> SetFile( _eqpFile, CharacterUtility.EqpIdx );
|
=> SetFile( _eqpFile, CharacterUtility.Index.Eqp );
|
||||||
|
|
||||||
public static void ResetEqpFiles()
|
public static void ResetEqpFiles()
|
||||||
=> SetFile( null, CharacterUtility.EqpIdx );
|
=> SetFile( null, CharacterUtility.Index.Eqp );
|
||||||
|
|
||||||
public void ResetEqp()
|
public void ResetEqp()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,18 @@ public partial class MetaManager
|
||||||
|
|
||||||
public void SetEstFiles()
|
public void SetEstFiles()
|
||||||
{
|
{
|
||||||
SetFile( _estFaceFile, CharacterUtility.FaceEstIdx );
|
SetFile( _estFaceFile, CharacterUtility.Index.FaceEst );
|
||||||
SetFile( _estHairFile, CharacterUtility.HairEstIdx );
|
SetFile( _estHairFile, CharacterUtility.Index.HairEst );
|
||||||
SetFile( _estBodyFile, CharacterUtility.BodyEstIdx );
|
SetFile( _estBodyFile, CharacterUtility.Index.BodyEst );
|
||||||
SetFile( _estHeadFile, CharacterUtility.HeadEstIdx );
|
SetFile( _estHeadFile, CharacterUtility.Index.HeadEst );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ResetEstFiles()
|
public static void ResetEstFiles()
|
||||||
{
|
{
|
||||||
SetFile( null, CharacterUtility.FaceEstIdx );
|
SetFile( null, CharacterUtility.Index.FaceEst );
|
||||||
SetFile( null, CharacterUtility.HairEstIdx );
|
SetFile( null, CharacterUtility.Index.HairEst );
|
||||||
SetFile( null, CharacterUtility.BodyEstIdx );
|
SetFile( null, CharacterUtility.Index.BodyEst );
|
||||||
SetFile( null, CharacterUtility.HeadEstIdx );
|
SetFile( null, CharacterUtility.Index.HeadEst );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetEst()
|
public void ResetEst()
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ public partial class MetaManager
|
||||||
private readonly List< GmpManipulation > _gmpManipulations = new();
|
private readonly List< GmpManipulation > _gmpManipulations = new();
|
||||||
|
|
||||||
public void SetGmpFiles()
|
public void SetGmpFiles()
|
||||||
=> SetFile( _gmpFile, CharacterUtility.GmpIdx );
|
=> SetFile( _gmpFile, CharacterUtility.Index.Gmp );
|
||||||
|
|
||||||
public static void ResetGmpFiles()
|
public static void ResetGmpFiles()
|
||||||
=> SetFile( null, CharacterUtility.GmpIdx );
|
=> SetFile( null, CharacterUtility.Index.Gmp );
|
||||||
|
|
||||||
public void ResetGmp()
|
public void ResetGmp()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.Meta.Files;
|
using Penumbra.Meta.Files;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
|
|
@ -168,7 +169,7 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
|
[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 )
|
if( file == null )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ public readonly struct EqdpManipulation : IMetaManipulation< EqdpManipulation >
|
||||||
return set != 0 ? set : Slot.CompareTo( other.Slot );
|
return set != 0 ? set : Slot.CompareTo( other.Slot );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int FileIndex()
|
public CharacterUtility.Index FileIndex()
|
||||||
=> CharacterUtility.EqdpIdx( Names.CombinedRace( Gender, Race ), Slot.IsAccessory() );
|
=> CharacterUtility.EqdpIdx( Names.CombinedRace( Gender, Race ), Slot.IsAccessory() );
|
||||||
|
|
||||||
public bool Apply( ExpandedEqdpFile file )
|
public bool Apply( ExpandedEqdpFile file )
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation >
|
||||||
return set != 0 ? set : Slot.CompareTo( other.Slot );
|
return set != 0 ? set : Slot.CompareTo( other.Slot );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int FileIndex()
|
public CharacterUtility.Index FileIndex()
|
||||||
=> CharacterUtility.EqpIdx;
|
=> CharacterUtility.Index.Eqp;
|
||||||
|
|
||||||
public bool Apply( ExpandedEqpFile file )
|
public bool Apply( ExpandedEqpFile file )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
|
||||||
{
|
{
|
||||||
public enum EstType : byte
|
public enum EstType : byte
|
||||||
{
|
{
|
||||||
Hair = CharacterUtility.HairEstIdx,
|
Hair = CharacterUtility.Index.HairEst,
|
||||||
Face = CharacterUtility.FaceEstIdx,
|
Face = CharacterUtility.Index.FaceEst,
|
||||||
Body = CharacterUtility.BodyEstIdx,
|
Body = CharacterUtility.Index.BodyEst,
|
||||||
Head = CharacterUtility.HeadEstIdx,
|
Head = CharacterUtility.Index.HeadEst,
|
||||||
}
|
}
|
||||||
|
|
||||||
public ushort Entry { get; init; } // SkeletonIdx.
|
public ushort Entry { get; init; } // SkeletonIdx.
|
||||||
|
|
@ -76,8 +76,8 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
|
||||||
return s != 0 ? s : SetId.CompareTo( other.SetId );
|
return s != 0 ? s : SetId.CompareTo( other.SetId );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int FileIndex()
|
public CharacterUtility.Index FileIndex()
|
||||||
=> ( int )Slot;
|
=> ( CharacterUtility.Index )Slot;
|
||||||
|
|
||||||
public bool Apply( EstFile file )
|
public bool Apply( EstFile file )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ public readonly struct GmpManipulation : IMetaManipulation< GmpManipulation >
|
||||||
public int CompareTo( GmpManipulation other )
|
public int CompareTo( GmpManipulation other )
|
||||||
=> SetId.CompareTo( other.SetId );
|
=> SetId.CompareTo( other.SetId );
|
||||||
|
|
||||||
public int FileIndex()
|
public CharacterUtility.Index FileIndex()
|
||||||
=> CharacterUtility.GmpIdx;
|
=> CharacterUtility.Index.Gmp;
|
||||||
|
|
||||||
public bool Apply( ExpandedGmpFile file )
|
public bool Apply( ExpandedGmpFile file )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using Penumbra.GameData.ByteString;
|
using Penumbra.GameData.ByteString;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.Meta.Files;
|
using Penumbra.Meta.Files;
|
||||||
|
|
||||||
namespace Penumbra.Meta.Manipulations;
|
namespace Penumbra.Meta.Manipulations;
|
||||||
|
|
@ -119,8 +120,8 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation >
|
||||||
return b != 0 ? b : Variant.CompareTo( other.Variant );
|
return b != 0 ? b : Variant.CompareTo( other.Variant );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int FileIndex()
|
public CharacterUtility.Index FileIndex()
|
||||||
=> -1;
|
=> ( CharacterUtility.Index )( -1 );
|
||||||
|
|
||||||
public Utf8GamePath GamePath()
|
public Utf8GamePath GamePath()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@ using System.Runtime.InteropServices;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using Penumbra.GameData.Util;
|
using Penumbra.GameData.Util;
|
||||||
|
using Penumbra.Interop.Structs;
|
||||||
|
|
||||||
namespace Penumbra.Meta.Manipulations;
|
namespace Penumbra.Meta.Manipulations;
|
||||||
|
|
||||||
public interface IMetaManipulation
|
public interface IMetaManipulation
|
||||||
{
|
{
|
||||||
public int FileIndex();
|
public CharacterUtility.Index FileIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IMetaManipulation< T >
|
public interface IMetaManipulation< T >
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ public readonly struct RspManipulation : IMetaManipulation< RspManipulation >
|
||||||
return s != 0 ? s : Attribute.CompareTo( other.Attribute );
|
return s != 0 ? s : Attribute.CompareTo( other.Attribute );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int FileIndex()
|
public CharacterUtility.Index FileIndex()
|
||||||
=> CharacterUtility.HumanCmpIdx;
|
=> CharacterUtility.Index.HumanCmp;
|
||||||
|
|
||||||
public bool Apply( CmpFile file )
|
public bool Apply( CmpFile file )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -69,75 +69,84 @@ public class Penumbra : IDalamudPlugin
|
||||||
|
|
||||||
public Penumbra( DalamudPluginInterface pluginInterface )
|
public Penumbra( DalamudPluginInterface pluginInterface )
|
||||||
{
|
{
|
||||||
Dalamud.Initialize( pluginInterface );
|
try
|
||||||
GameData.GameData.GetIdentifier( Dalamud.GameData );
|
|
||||||
DevPenumbraExists = CheckDevPluginPenumbra();
|
|
||||||
IsNotInstalledPenumbra = CheckIsNotInstalled();
|
|
||||||
|
|
||||||
Framework = new FrameworkManager();
|
|
||||||
CharacterUtility = new CharacterUtility();
|
|
||||||
Backup.CreateBackup( pluginInterface.ConfigDirectory, PenumbraBackupFiles() );
|
|
||||||
Config = Configuration.Load();
|
|
||||||
|
|
||||||
TempMods = new TempModManager();
|
|
||||||
MetaFileManager = new MetaFileManager();
|
|
||||||
ResourceLoader = new ResourceLoader( this );
|
|
||||||
ResourceLoader.EnableHooks();
|
|
||||||
ResourceLogger = new ResourceLogger( ResourceLoader );
|
|
||||||
ResidentResources = new ResidentResourceManager();
|
|
||||||
ModManager = new Mod.Manager( Config.ModDirectory );
|
|
||||||
ModManager.DiscoverMods();
|
|
||||||
CollectionManager = new ModCollection.Manager( ModManager );
|
|
||||||
ModFileSystem = ModFileSystem.Load();
|
|
||||||
ObjectReloader = new ObjectReloader();
|
|
||||||
PathResolver = new PathResolver( ResourceLoader );
|
|
||||||
|
|
||||||
Dalamud.Commands.AddHandler( CommandName, new CommandInfo( OnCommand )
|
|
||||||
{
|
{
|
||||||
HelpMessage = "/penumbra - toggle ui\n/penumbra reload - reload mod file lists & discover any new mods",
|
Dalamud.Initialize( pluginInterface );
|
||||||
} );
|
GameData.GameData.GetIdentifier( Dalamud.GameData );
|
||||||
|
DevPenumbraExists = CheckDevPluginPenumbra();
|
||||||
|
IsNotInstalledPenumbra = CheckIsNotInstalled();
|
||||||
|
|
||||||
SetupInterface( out _configWindow, out _launchButton, out _windowSystem );
|
Framework = new FrameworkManager();
|
||||||
|
CharacterUtility = new CharacterUtility();
|
||||||
|
Backup.CreateBackup( pluginInterface.ConfigDirectory, PenumbraBackupFiles() );
|
||||||
|
Config = Configuration.Load();
|
||||||
|
|
||||||
if( Config.EnableMods )
|
TempMods = new TempModManager();
|
||||||
{
|
MetaFileManager = new MetaFileManager();
|
||||||
ResourceLoader.EnableReplacements();
|
ResourceLoader = new ResourceLoader( this );
|
||||||
PathResolver.Enable();
|
ResourceLoader.EnableHooks();
|
||||||
|
ResourceLogger = new ResourceLogger( ResourceLoader );
|
||||||
|
ResidentResources = new ResidentResourceManager();
|
||||||
|
ModManager = new Mod.Manager( Config.ModDirectory );
|
||||||
|
ModManager.DiscoverMods();
|
||||||
|
CollectionManager = new ModCollection.Manager( ModManager );
|
||||||
|
ModFileSystem = ModFileSystem.Load();
|
||||||
|
ObjectReloader = new ObjectReloader();
|
||||||
|
PathResolver = new PathResolver( ResourceLoader );
|
||||||
|
|
||||||
|
Dalamud.Commands.AddHandler( CommandName, new CommandInfo( OnCommand )
|
||||||
|
{
|
||||||
|
HelpMessage = "/penumbra - toggle ui\n/penumbra reload - reload mod file lists & discover any new mods",
|
||||||
|
} );
|
||||||
|
|
||||||
|
SetupInterface( out _configWindow, out _launchButton, out _windowSystem );
|
||||||
|
|
||||||
|
if( Config.EnableMods )
|
||||||
|
{
|
||||||
|
ResourceLoader.EnableReplacements();
|
||||||
|
PathResolver.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Config.EnableHttpApi )
|
||||||
|
{
|
||||||
|
CreateWebServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Config.DebugMode )
|
||||||
|
{
|
||||||
|
ResourceLoader.EnableDebug();
|
||||||
|
_configWindow.IsOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Config.EnableFullResourceLogging )
|
||||||
|
{
|
||||||
|
ResourceLoader.EnableFullLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( CharacterUtility.Ready )
|
||||||
|
{
|
||||||
|
ResidentResources.Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
Api = new PenumbraApi( this );
|
||||||
|
Ipc = new PenumbraIpc( Dalamud.PluginInterface, Api );
|
||||||
|
SubscribeItemLinks();
|
||||||
|
if( ImcExceptions > 0 )
|
||||||
|
{
|
||||||
|
PluginLog.Error( $"{ImcExceptions} IMC Exceptions thrown. Please repair your game files." );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PluginLog.Information( $"Penumbra Version {Version}, Commit #{CommitHash} successfully Loaded." );
|
||||||
|
}
|
||||||
|
|
||||||
|
Dalamud.PluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
if( Config.EnableHttpApi )
|
|
||||||
{
|
{
|
||||||
CreateWebServer();
|
Dispose();
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Config.DebugMode )
|
|
||||||
{
|
|
||||||
ResourceLoader.EnableDebug();
|
|
||||||
_configWindow.IsOpen = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( Config.EnableFullResourceLogging )
|
|
||||||
{
|
|
||||||
ResourceLoader.EnableFullLogging();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( CharacterUtility.Ready )
|
|
||||||
{
|
|
||||||
ResidentResources.Reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
Api = new PenumbraApi( this );
|
|
||||||
Ipc = new PenumbraIpc( Dalamud.PluginInterface, Api );
|
|
||||||
SubscribeItemLinks();
|
|
||||||
if( ImcExceptions > 0 )
|
|
||||||
{
|
|
||||||
PluginLog.Error( $"{ImcExceptions} IMC Exceptions thrown. Please repair your game files." );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PluginLog.Information( $"Penumbra Version {Version}, Commit #{CommitHash} successfully Loaded." );
|
|
||||||
}
|
|
||||||
Dalamud.PluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupInterface( out ConfigWindow cfg, out LaunchButton btn, out WindowSystem system )
|
private void SetupInterface( out ConfigWindow cfg, out LaunchButton btn, out WindowSystem system )
|
||||||
|
|
@ -154,8 +163,8 @@ public class Penumbra : IDalamudPlugin
|
||||||
{
|
{
|
||||||
Dalamud.PluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
Dalamud.PluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
||||||
Dalamud.PluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
|
Dalamud.PluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
|
||||||
_launchButton.Dispose();
|
_launchButton?.Dispose();
|
||||||
_configWindow.Dispose();
|
_configWindow?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enable()
|
public bool Enable()
|
||||||
|
|
@ -249,18 +258,18 @@ public class Penumbra : IDalamudPlugin
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
DisposeInterface();
|
DisposeInterface();
|
||||||
Ipc.Dispose();
|
Ipc?.Dispose();
|
||||||
Api.Dispose();
|
Api?.Dispose();
|
||||||
ObjectReloader.Dispose();
|
ObjectReloader?.Dispose();
|
||||||
ModFileSystem.Dispose();
|
ModFileSystem?.Dispose();
|
||||||
CollectionManager.Dispose();
|
CollectionManager?.Dispose();
|
||||||
|
|
||||||
Dalamud.Commands.RemoveHandler( CommandName );
|
Dalamud.Commands.RemoveHandler( CommandName );
|
||||||
|
|
||||||
PathResolver.Dispose();
|
PathResolver?.Dispose();
|
||||||
ResourceLogger.Dispose();
|
ResourceLogger?.Dispose();
|
||||||
ResourceLoader.Dispose();
|
ResourceLoader?.Dispose();
|
||||||
CharacterUtility.Dispose();
|
CharacterUtility?.Dispose();
|
||||||
|
|
||||||
ShutdownWebServer();
|
ShutdownWebServer();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,8 @@ public partial class ConfigWindow
|
||||||
for( var i = 0; i < CharacterUtility.RelevantIndices.Length; ++i )
|
for( var i = 0; i < CharacterUtility.RelevantIndices.Length; ++i )
|
||||||
{
|
{
|
||||||
var idx = CharacterUtility.RelevantIndices[ i ];
|
var idx = CharacterUtility.RelevantIndices[ i ];
|
||||||
var resource = ( ResourceHandle* )Penumbra.CharacterUtility.Address->Resources[ idx ];
|
var intern = new CharacterUtility.InternalIndex( i );
|
||||||
|
var resource = ( ResourceHandle* )Penumbra.CharacterUtility.Address->Resource(idx);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.TextUnformatted( $"0x{( ulong )resource:X}" );
|
ImGui.TextUnformatted( $"0x{( ulong )resource:X}" );
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
|
|
@ -259,18 +260,18 @@ public partial class ConfigWindow
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.TextUnformatted( $"{resource->GetData().Length}" );
|
ImGui.TextUnformatted( $"{resource->GetData().Length}" );
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.Selectable( $"0x{Penumbra.CharacterUtility.DefaultResources[ i ].Address:X}" );
|
ImGui.Selectable( $"0x{Penumbra.CharacterUtility.DefaultResource(intern).Address:X}" );
|
||||||
if( ImGui.IsItemClicked() )
|
if( ImGui.IsItemClicked() )
|
||||||
{
|
{
|
||||||
ImGui.SetClipboardText( string.Join( "\n",
|
ImGui.SetClipboardText( string.Join( "\n",
|
||||||
new ReadOnlySpan< byte >( ( byte* )Penumbra.CharacterUtility.DefaultResources[ i ].Address,
|
new ReadOnlySpan< byte >( ( byte* )Penumbra.CharacterUtility.DefaultResource(intern).Address,
|
||||||
Penumbra.CharacterUtility.DefaultResources[ i ].Size ).ToArray().Select( b => b.ToString( "X2" ) ) ) );
|
Penumbra.CharacterUtility.DefaultResource(intern).Size ).ToArray().Select( b => b.ToString( "X2" ) ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiUtil.HoverTooltip( "Click to copy bytes to clipboard." );
|
ImGuiUtil.HoverTooltip( "Click to copy bytes to clipboard." );
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.TextUnformatted( $"{Penumbra.CharacterUtility.DefaultResources[ i ].Size}" );
|
ImGui.TextUnformatted( $"{Penumbra.CharacterUtility.DefaultResource(intern).Size}" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue