mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Fixes.
This commit is contained in:
parent
8d2e84eecf
commit
581b91b337
13 changed files with 123 additions and 52 deletions
|
|
@ -20,7 +20,14 @@ public readonly struct Utf8RelPath : IEquatable< Utf8RelPath >, IComparable< Utf
|
||||||
|
|
||||||
|
|
||||||
public static explicit operator Utf8RelPath( string s )
|
public static explicit operator Utf8RelPath( string s )
|
||||||
=> FromString( s, out var p ) ? p : Empty;
|
{
|
||||||
|
if( !FromString( s, out var p ) )
|
||||||
|
{
|
||||||
|
return Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Utf8RelPath( p.Path.AsciiToLower() );
|
||||||
|
}
|
||||||
|
|
||||||
public static bool FromString( string? s, out Utf8RelPath path )
|
public static bool FromString( string? s, out Utf8RelPath path )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ public sealed unsafe partial class Utf8String
|
||||||
var length = Length;
|
var length = Length;
|
||||||
var newPtr = ByteStringFunctions.CopyString( _path, length );
|
var newPtr = ByteStringFunctions.CopyString( _path, length );
|
||||||
var numReplaced = ByteStringFunctions.Replace( newPtr, length, from, to );
|
var numReplaced = ByteStringFunctions.Replace( newPtr, length, from, to );
|
||||||
return new Utf8String().Setup( newPtr, length, numReplaced > 0 ? _crc32 : null, true, true, IsAsciiLowerInternal, IsAsciiInternal );
|
return new Utf8String().Setup( newPtr, length, numReplaced == 0 ? _crc32 : null, true, true, IsAsciiLowerInternal, IsAsciiInternal );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join a number of strings with a given byte between them.
|
// Join a number of strings with a given byte between them.
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Lumina.Data.Files;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.GameData.Util;
|
using Penumbra.GameData.Util;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,9 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
|
|
||||||
public (IntPtr Address, int Size)[] DefaultResources = new (IntPtr, int)[RelevantIndices.Length];
|
public (IntPtr Address, int Size)[] DefaultResources = new (IntPtr, int)[RelevantIndices.Length];
|
||||||
|
|
||||||
|
public (IntPtr Address, int Size) DefaultResource( int fullIdx )
|
||||||
|
=> DefaultResources[ ReverseIndices[ fullIdx ] ];
|
||||||
|
|
||||||
public CharacterUtility()
|
public CharacterUtility()
|
||||||
{
|
{
|
||||||
SignatureHelper.Initialise( this );
|
SignatureHelper.Initialise( this );
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,11 @@ namespace Penumbra.Interop.Resolver;
|
||||||
// EST entries seem to be obtained by "44 8B C9 83 EA ?? 74", which is only called by
|
// EST entries seem to be obtained by "44 8B C9 83 EA ?? 74", which is only called by
|
||||||
// ResolveSKLBPath, ResolveSKPPath, ResolvePHYBPath and indirectly by ResolvePAPPath.
|
// ResolveSKLBPath, ResolveSKPPath, ResolvePHYBPath and indirectly by ResolvePAPPath.
|
||||||
|
|
||||||
// RSP entries seem to be obtained by "E8 ?? ?? ?? ?? 48 8B 8E ?? ?? ?? ?? 44 8B CF", or maybe "E8 ?? ?? ?? ?? 0F 28 F0 48 8B 05",
|
// RSP height entries seem to be obtained by "E8 ?? ?? ?? ?? 48 8B 8E ?? ?? ?? ?? 44 8B CF"
|
||||||
// possibly also "E8 ?? ?? ?? ?? F2 0F 10 44 24 ?? 8B 44 24 ?? F2 0F 11 45 ?? 89 45 ?? 83 FF"
|
// RSP tail entries seem to be obtained by "E8 ?? ?? ?? ?? 0F 28 F0 48 8B 05"
|
||||||
// which is called by a lot of functions, but the mostly relevant is probably Human.SetupFromCharacterData, which is only called by CharacterBase.Create.
|
// RSP bust size entries seem to be obtained by "E8 ?? ?? ?? ?? F2 0F 10 44 24 ?? 8B 44 24 ?? F2 0F 11 45 ?? 89 45 ?? 83 FF"
|
||||||
|
// they all are called by many functions, but the most relevant seem to be Human.SetupFromCharacterData, which is only called by CharacterBase.Create,
|
||||||
|
// and RspSetupCharacter, which is hooked here.
|
||||||
|
|
||||||
// GMP Entries seem to be only used by "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", which has a DrawObject as its first parameter.
|
// GMP Entries seem to be only used by "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", which has a DrawObject as its first parameter.
|
||||||
|
|
||||||
|
|
@ -102,6 +104,18 @@ public unsafe partial class PathResolver
|
||||||
ApplyVisorHook!.Original( drawObject, unk1, unk2, unk3, unk4, unk5 );
|
ApplyVisorHook!.Original( drawObject, unk1, unk2, unk3, unk4, unk5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RSP
|
||||||
|
public delegate void RspSetupCharacterDelegate( IntPtr drawObject, IntPtr unk2, float unk3, IntPtr unk4, byte unk5 );
|
||||||
|
|
||||||
|
[Signature( "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 88 54 24 ?? 57 41 56 ", DetourName = "RspSetupCharacterDetour" )]
|
||||||
|
public Hook< RspSetupCharacterDelegate >? RspSetupCharacterHook;
|
||||||
|
|
||||||
|
private void RspSetupCharacterDetour( IntPtr drawObject, IntPtr unk2, float unk3, IntPtr unk4, byte unk5 )
|
||||||
|
{
|
||||||
|
using var rsp = MetaChanger.ChangeCmp( this, drawObject );
|
||||||
|
RspSetupCharacterHook!.Original( drawObject, unk2, unk3, unk4, unk5 );
|
||||||
|
}
|
||||||
|
|
||||||
private void SetupMetaHooks()
|
private void SetupMetaHooks()
|
||||||
{
|
{
|
||||||
OnModelLoadCompleteHook =
|
OnModelLoadCompleteHook =
|
||||||
|
|
@ -119,6 +133,9 @@ public unsafe partial class PathResolver
|
||||||
#endif
|
#endif
|
||||||
#if USE_GMP
|
#if USE_GMP
|
||||||
ApplyVisorHook?.Enable();
|
ApplyVisorHook?.Enable();
|
||||||
|
#endif
|
||||||
|
#if USE_CMP
|
||||||
|
RspSetupCharacterHook?.Enable();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,6 +145,7 @@ public unsafe partial class PathResolver
|
||||||
UpdateModelsHook?.Disable();
|
UpdateModelsHook?.Disable();
|
||||||
OnModelLoadCompleteHook?.Disable();
|
OnModelLoadCompleteHook?.Disable();
|
||||||
ApplyVisorHook?.Disable();
|
ApplyVisorHook?.Disable();
|
||||||
|
RspSetupCharacterHook?.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeMetaHooks()
|
private void DisposeMetaHooks()
|
||||||
|
|
@ -136,6 +154,7 @@ public unsafe partial class PathResolver
|
||||||
UpdateModelsHook?.Dispose();
|
UpdateModelsHook?.Dispose();
|
||||||
OnModelLoadCompleteHook?.Dispose();
|
OnModelLoadCompleteHook?.Dispose();
|
||||||
ApplyVisorHook?.Dispose();
|
ApplyVisorHook?.Dispose();
|
||||||
|
RspSetupCharacterHook?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModCollection? GetCollection( IntPtr drawObject )
|
private ModCollection? GetCollection( IntPtr drawObject )
|
||||||
|
|
@ -249,6 +268,19 @@ public unsafe partial class PathResolver
|
||||||
return new MetaChanger( MetaManipulation.Type.Unknown );
|
return new MetaChanger( MetaManipulation.Type.Unknown );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MetaChanger ChangeCmp( PathResolver resolver, IntPtr drawObject )
|
||||||
|
{
|
||||||
|
#if USE_CMP
|
||||||
|
var collection = resolver.GetCollection( drawObject );
|
||||||
|
if( collection != null )
|
||||||
|
{
|
||||||
|
collection.SetCmpFiles();
|
||||||
|
return new MetaChanger( MetaManipulation.Type.Rsp );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return new MetaChanger( MetaManipulation.Type.Unknown );
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
switch( _type )
|
switch( _type )
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ public unsafe struct CharacterUtility
|
||||||
public const int HumanCmpIdx = 63;
|
public const int HumanCmpIdx = 63;
|
||||||
public const int FaceEstIdx = 64;
|
public const int FaceEstIdx = 64;
|
||||||
public const int HairEstIdx = 65;
|
public const int HairEstIdx = 65;
|
||||||
public const int BodyEstIdx = 66;
|
public const int HeadEstIdx = 66;
|
||||||
public const int HeadEstIdx = 67;
|
public const int BodyEstIdx = 67;
|
||||||
public const int EqdpStartIdx = 2;
|
public const int EqdpStartIdx = 2;
|
||||||
public const int NumEqdpFiles = 2 * 28;
|
public const int NumEqdpFiles = 2 * 28;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,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.DefaultResources[ CharacterUtility.HumanCmpIdx ].Address;
|
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource( CharacterUtility.HumanCmpIdx ).Address;
|
||||||
return *( float* )( data + RacialScalingStart + ToRspIndex( subRace ) * RspEntry.ByteSize + ( int )attribute * 4 );
|
return *( float* )( data + RacialScalingStart + ToRspIndex( subRace ) * RspEntry.ByteSize + ( int )attribute * 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Forms;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Util;
|
using Penumbra.GameData.Util;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
|
|
@ -15,7 +16,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
||||||
{
|
{
|
||||||
private const ushort EntryDescSize = 4;
|
private const ushort EntryDescSize = 4;
|
||||||
private const ushort EntrySize = 2;
|
private const ushort EntrySize = 2;
|
||||||
private const int IncreaseSize = 100;
|
private const int IncreaseSize = 512;
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
=> *( int* )Data;
|
=> *( int* )Data;
|
||||||
|
|
@ -52,58 +53,57 @@ public sealed unsafe class EstFile : MetaBaseFile
|
||||||
{
|
{
|
||||||
var data = Data;
|
var data = Data;
|
||||||
var length = Length;
|
var length = Length;
|
||||||
AllocateData( length + IncreaseSize * ( EntryDescSize + EntrySize ) );
|
AllocateData( length + IncreaseSize );
|
||||||
Functions.MemCpyUnchecked( Data, data, length );
|
Functions.MemCpyUnchecked( Data, data, length );
|
||||||
Functions.MemSet( Data + length, 0, IncreaseSize * ( EntryDescSize + EntrySize ) );
|
Functions.MemSet( Data + length, 0, IncreaseSize );
|
||||||
GC.RemoveMemoryPressure( length );
|
GC.RemoveMemoryPressure( length );
|
||||||
Marshal.FreeHGlobal( ( IntPtr )data );
|
Marshal.FreeHGlobal( ( IntPtr )data );
|
||||||
}
|
}
|
||||||
|
|
||||||
var control = ( uint* )( Data + 4 );
|
var control = ( Info* )( Data + 4 );
|
||||||
var entries = ( ushort* )( Data + 4 * ( Count + 1 ) );
|
var entries = ( ushort* )( control + Count );
|
||||||
|
|
||||||
for( var i = Count; i > idx; --i )
|
for( var i = Count - 1; i >= idx; --i )
|
||||||
{
|
{
|
||||||
*( entries + i + 2 ) = entries[ i - 1 ];
|
entries[ i + 3 ] = entries[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entries[ idx + 2 ] = skeletonId;
|
||||||
|
|
||||||
for( var i = idx - 1; i >= 0; --i )
|
for( var i = idx - 1; i >= 0; --i )
|
||||||
{
|
{
|
||||||
*( entries + i + 2 ) = entries[ i ];
|
entries[ i + 2 ] = entries[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
for( var i = Count; i > idx; --i )
|
for( var i = Count - 1; i >= idx; --i )
|
||||||
{
|
{
|
||||||
*( control + i ) = control[ i - 1 ];
|
control[ i + 1 ] = control[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
control[ idx ] = new Info( genderRace, setId );
|
||||||
|
|
||||||
*( int* )Data = Count + 1;
|
*( int* )Data = Count + 1;
|
||||||
|
|
||||||
*( ushort* )control = setId;
|
|
||||||
*( ( ushort* )control + 1 ) = ( ushort )genderRace;
|
|
||||||
control[ idx ] = skeletonId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveEntry( int idx )
|
private void RemoveEntry( int idx )
|
||||||
{
|
{
|
||||||
var entries = ( ushort* )( Data + 4 * Count );
|
var control = ( Info* )( Data + 4 );
|
||||||
var control = ( uint* )( Data + 4 );
|
var entries = ( ushort* )( control + Count );
|
||||||
*( int* )Data = Count - 1;
|
|
||||||
var count = Count;
|
|
||||||
|
|
||||||
for( var i = idx; i < count; ++i )
|
for( var i = idx; i < Count; ++i )
|
||||||
{
|
{
|
||||||
control[ i ] = control[ i + 1 ];
|
control[ i ] = control[ i + 1 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
for( var i = 0; i < count; ++i )
|
for( var i = 0; i < Count; ++i )
|
||||||
{
|
{
|
||||||
entries[ i ] = entries[ i + 1 ];
|
entries[ i - 2 ] = entries[ i + 1 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
entries[ count ] = 0;
|
entries[ Count - 3 ] = 0;
|
||||||
entries[ count + 1 ] = 0;
|
entries[ Count - 2 ] = 0;
|
||||||
entries[ count + 2 ] = 0;
|
entries[ Count - 1 ] = 0;
|
||||||
|
*( int* )Data = Count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout( LayoutKind.Sequential, Size = 4 )]
|
[StructLayout( LayoutKind.Sequential, Size = 4 )]
|
||||||
|
|
@ -179,7 +179,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
||||||
: base( ( int )estType )
|
: base( ( int )estType )
|
||||||
{
|
{
|
||||||
var length = DefaultData.Length;
|
var length = DefaultData.Length;
|
||||||
AllocateData( length + IncreaseSize * ( EntryDescSize + EntrySize ) );
|
AllocateData( length + IncreaseSize );
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
||||||
|
|
||||||
public static ushort GetDefault( EstManipulation.EstType estType, GenderRace genderRace, ushort setId )
|
public static ushort GetDefault( EstManipulation.EstType estType, GenderRace genderRace, ushort setId )
|
||||||
{
|
{
|
||||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResources[ ( int )estType ].Address;
|
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource( ( int )estType ).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 );
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Dalamud.Memory;
|
using Dalamud.Memory;
|
||||||
|
|
||||||
namespace Penumbra.Meta.Files;
|
namespace Penumbra.Meta.Files;
|
||||||
|
|
@ -14,17 +13,18 @@ public unsafe class MetaBaseFile : IDisposable
|
||||||
=> Index = idx;
|
=> Index = idx;
|
||||||
|
|
||||||
protected (IntPtr Data, int Length) DefaultData
|
protected (IntPtr Data, int Length) DefaultData
|
||||||
=> Penumbra.CharacterUtility.DefaultResources[ Index ];
|
=> Penumbra.CharacterUtility.DefaultResource( Index );
|
||||||
|
|
||||||
// Reset to default values.
|
// Reset to default values.
|
||||||
public virtual void Reset()
|
public virtual void Reset()
|
||||||
{}
|
{ }
|
||||||
|
|
||||||
// Obtain memory.
|
// Obtain memory.
|
||||||
protected void AllocateData( int length )
|
protected void AllocateData( int length )
|
||||||
{
|
{
|
||||||
Length = length;
|
Length = length;
|
||||||
Data = ( byte* )MemoryHelper.GameAllocateDefault( ( ulong )length ); ;
|
Data = ( byte* )MemoryHelper.GameAllocateDefault( ( ulong )length );
|
||||||
|
;
|
||||||
GC.AddMemoryPressure( length );
|
GC.AddMemoryPressure( length );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ public unsafe class MetaBaseFile : IDisposable
|
||||||
protected void ReleaseUnmanagedResources()
|
protected void ReleaseUnmanagedResources()
|
||||||
{
|
{
|
||||||
var ptr = ( IntPtr )Data;
|
var ptr = ( IntPtr )Data;
|
||||||
MemoryHelper.GameFree( ref ptr, (ulong) Length );
|
MemoryHelper.GameFree( ref ptr, ( ulong )Length );
|
||||||
GC.RemoveMemoryPressure( Length );
|
GC.RemoveMemoryPressure( Length );
|
||||||
Length = 0;
|
Length = 0;
|
||||||
Data = null;
|
Data = null;
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public partial class MetaManager
|
||||||
public bool ApplyMod( GmpManipulation m, Mod.Mod mod )
|
public bool ApplyMod( GmpManipulation m, Mod.Mod mod )
|
||||||
{
|
{
|
||||||
#if USE_GMP
|
#if USE_GMP
|
||||||
if( Manipulations.TryAdd( m, mod ) )
|
if( !Manipulations.TryAdd( m, mod ) )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,22 +19,27 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
|
||||||
Head = CharacterUtility.HeadEstIdx,
|
Head = CharacterUtility.HeadEstIdx,
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly ushort SkeletonIdx;
|
public readonly ushort SkeletonIdx;
|
||||||
|
|
||||||
[JsonConverter( typeof( StringEnumConverter ) )]
|
[JsonConverter( typeof( StringEnumConverter ) )]
|
||||||
public readonly Gender Gender;
|
public readonly Gender Gender;
|
||||||
|
|
||||||
[JsonConverter( typeof( StringEnumConverter ) )]
|
[JsonConverter( typeof( StringEnumConverter ) )]
|
||||||
public readonly ModelRace Race;
|
public readonly ModelRace Race;
|
||||||
public readonly ushort SetId;
|
|
||||||
[JsonConverter( typeof( StringEnumConverter ) )]
|
|
||||||
public readonly EstType Slot;
|
|
||||||
|
|
||||||
public EstManipulation( Gender gender, ModelRace race, EstType estType, ushort setId, ushort skeletonIdx )
|
public readonly ushort SetId;
|
||||||
|
|
||||||
|
[JsonConverter( typeof( StringEnumConverter ) )]
|
||||||
|
public readonly EstType Slot;
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
public EstManipulation( Gender gender, ModelRace race, EstType slot, ushort setId, ushort skeletonIdx )
|
||||||
{
|
{
|
||||||
SkeletonIdx = skeletonIdx;
|
SkeletonIdx = skeletonIdx;
|
||||||
Gender = gender;
|
Gender = gender;
|
||||||
Race = race;
|
Race = race;
|
||||||
SetId = setId;
|
SetId = setId;
|
||||||
Slot = estType;
|
Slot = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -360,17 +360,15 @@ public partial class SettingsInterface
|
||||||
|
|
||||||
using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
|
using var font = ImGuiRaii.PushFont( UiBuilder.IconFont );
|
||||||
|
|
||||||
using var style = ImGuiRaii.PushStyle( ImGuiStyleVar.FramePadding, Vector2.One * ImGuiHelpers.GlobalScale * 1.5f );
|
if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##{name}", Vector2.One * ImGui.GetFrameHeight() ) )
|
||||||
if( ImGui.Button( $"{FontAwesomeIcon.Trash.ToIconString()}##{name}" ) )
|
|
||||||
{
|
{
|
||||||
manager.Collections.RemoveCharacterCollection( name );
|
manager.Collections.RemoveCharacterCollection( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
style.Pop();
|
|
||||||
|
|
||||||
font.Pop();
|
font.Pop();
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.Text( name );
|
ImGui.Text( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Interop;
|
using Penumbra.Interop;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.Meta.Files;
|
using Penumbra.Meta.Files;
|
||||||
|
using Penumbra.Meta.Manipulations;
|
||||||
using Penumbra.UI.Custom;
|
using Penumbra.UI.Custom;
|
||||||
using CharacterUtility = Penumbra.Interop.CharacterUtility;
|
using CharacterUtility = Penumbra.Interop.CharacterUtility;
|
||||||
using ResourceHandle = Penumbra.Interop.Structs.ResourceHandle;
|
using ResourceHandle = Penumbra.Interop.Structs.ResourceHandle;
|
||||||
|
|
@ -410,6 +411,32 @@ public partial class SettingsInterface
|
||||||
catch
|
catch
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
var est = 0;
|
||||||
|
ImGui.InputInt( "##EstInput", ref est );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var def = EstFile.GetDefault( EstManipulation.EstType.Body, GenderRace.MidlanderFemale, ( ushort )est );
|
||||||
|
var val = Penumbra.ModManager.Collections.ActiveCollection.Cache?.MetaManipulations.Est.BodyFile?[ GenderRace.MidlanderFemale,
|
||||||
|
( ushort )est ]
|
||||||
|
?? def;
|
||||||
|
ImGui.Text( def.ToString() );
|
||||||
|
ImGui.Text( val.ToString() );
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{ }
|
||||||
|
|
||||||
|
var gmp = 0;
|
||||||
|
ImGui.InputInt( "##GmpInput", ref gmp );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var def = ExpandedGmpFile.GetDefault( gmp );
|
||||||
|
var val = Penumbra.ModManager.Collections.ActiveCollection.Cache?.MetaManipulations.Gmp.File?[ gmp ] ?? def;
|
||||||
|
ImGui.Text( def.Value.ToString("X") );
|
||||||
|
ImGui.Text( val.Value.ToString("X") );
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
if( !ImGui.BeginTable( "##CharacterUtilityDebugList", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ) )
|
if( !ImGui.BeginTable( "##CharacterUtilityDebugList", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ) )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue