mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Merge branch 'refs/heads/Exter-N/stockings-skin-slot'
This commit is contained in:
commit
10b71930a1
5 changed files with 83 additions and 10 deletions
|
|
@ -3,4 +3,5 @@ namespace Penumbra;
|
||||||
public class DebugConfiguration
|
public class DebugConfiguration
|
||||||
{
|
{
|
||||||
public static bool WriteImcBytesToLog = false;
|
public static bool WriteImcBytesToLog = false;
|
||||||
|
public static bool UseSkinMaterialProcessing = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using Penumbra.Collections;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Interop.PathResolving;
|
using Penumbra.Interop.PathResolving;
|
||||||
|
using Penumbra.Interop.Processing;
|
||||||
using static FFXIVClientStructs.FFXIV.Client.Game.Character.ActionEffectHandler;
|
using static FFXIVClientStructs.FFXIV.Client.Game.Character.ActionEffectHandler;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.Resources;
|
namespace Penumbra.Interop.Hooks.Resources;
|
||||||
|
|
@ -159,7 +160,13 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
||||||
=> ResolvePath(drawObject, _resolveMtrlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex, mtrlFileName));
|
=> ResolvePath(drawObject, _resolveMtrlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex, mtrlFileName));
|
||||||
|
|
||||||
private nint ResolveSkinMtrl(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
|
private nint ResolveSkinMtrl(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
|
||||||
=> ResolvePath(drawObject, _resolveSkinMtrlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex));
|
{
|
||||||
|
var finalPathBuffer = _resolveSkinMtrlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex);
|
||||||
|
if (DebugConfiguration.UseSkinMaterialProcessing && finalPathBuffer != nint.Zero && finalPathBuffer == pathBuffer)
|
||||||
|
SkinMtrlPathEarlyProcessing.Process(new Span<byte>((void*)pathBuffer, (int)pathBufferSize), (CharacterBase*)drawObject, slotIndex);
|
||||||
|
|
||||||
|
return ResolvePath(drawObject, finalPathBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
private nint ResolvePap(nint drawObject, nint pathBuffer, nint pathBufferSize, uint unkAnimationIndex, nint animationName)
|
private nint ResolvePap(nint drawObject, nint pathBuffer, nint pathBufferSize, uint unkAnimationIndex, nint animationName)
|
||||||
=> ResolvePath(drawObject, _resolvePapPathHook.Original(drawObject, pathBuffer, pathBufferSize, unkAnimationIndex, animationName));
|
=> ResolvePath(drawObject, _resolvePapPathHook.Original(drawObject, pathBuffer, pathBufferSize, unkAnimationIndex, animationName));
|
||||||
|
|
|
||||||
64
Penumbra/Interop/Processing/SkinMtrlPathEarlyProcessing.cs
Normal file
64
Penumbra/Interop/Processing/SkinMtrlPathEarlyProcessing.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||||
|
|
||||||
|
namespace Penumbra.Interop.Processing;
|
||||||
|
|
||||||
|
public static unsafe class SkinMtrlPathEarlyProcessing
|
||||||
|
{
|
||||||
|
public static void Process(Span<byte> path, CharacterBase* character, uint slotIndex)
|
||||||
|
{
|
||||||
|
var end = path.IndexOf(MaterialExtension());
|
||||||
|
if (end < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var suffixPos = path[..end].LastIndexOf((byte)'_');
|
||||||
|
if (suffixPos < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var handle = GetModelResourceHandle(character, slotIndex);
|
||||||
|
if (handle == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var skinSuffix = GetSkinSuffix(handle);
|
||||||
|
if (skinSuffix.IsEmpty || skinSuffix.Length > path.Length - suffixPos - 7)
|
||||||
|
return;
|
||||||
|
|
||||||
|
++suffixPos;
|
||||||
|
skinSuffix.CopyTo(path[suffixPos..]);
|
||||||
|
suffixPos += skinSuffix.Length;
|
||||||
|
MaterialExtension().CopyTo(path[suffixPos..]);
|
||||||
|
return;
|
||||||
|
|
||||||
|
static ReadOnlySpan<byte> MaterialExtension()
|
||||||
|
=> ".mtrl\0"u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModelResourceHandle* GetModelResourceHandle(CharacterBase* character, uint slotIndex)
|
||||||
|
{
|
||||||
|
if (character is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (character->TempSlotData is not null)
|
||||||
|
{
|
||||||
|
// TODO ClientStructs-ify
|
||||||
|
var handle = *(ModelResourceHandle**)((nint)character->TempSlotData + 0xE0 * slotIndex + 0x8);
|
||||||
|
if (handle != null)
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = character->Models[slotIndex];
|
||||||
|
return model is null ? null : model->ModelResourceHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> GetSkinSuffix(ModelResourceHandle* handle)
|
||||||
|
{
|
||||||
|
foreach (var (attribute, _) in handle->Attributes)
|
||||||
|
{
|
||||||
|
var attributeSpan = attribute.AsSpan();
|
||||||
|
if (attributeSpan.Length > 12 && attributeSpan[..11].SequenceEqual("skin_suffix"u8) && attributeSpan[11] is (byte)'=' or (byte)'_')
|
||||||
|
return attributeSpan[12..];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -131,7 +131,7 @@ public sealed unsafe class MaterialTemplatePickers : IUiService
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
continue;
|
continue;
|
||||||
var handle = _textureArraySlicer.GetImGuiHandle(texture, sliceIndex);
|
var handle = _textureArraySlicer.GetImGuiHandle(texture, sliceIndex);
|
||||||
if (handle == 0)
|
if (handle.IsNull)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var position = regionStart with { X = regionStart.X + (itemSize.X + itemSpacing) * j };
|
var position = regionStart with { X = regionStart.X + (itemSize.X + itemSpacing) * j };
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@ public static class DebugConfigurationDrawer
|
||||||
{
|
{
|
||||||
public static void Draw()
|
public static void Draw()
|
||||||
{
|
{
|
||||||
using var id = ImUtf8.CollapsingHeaderId("Debug Logging Options"u8);
|
using var id = ImUtf8.CollapsingHeaderId("Debugging Options"u8);
|
||||||
if (!id)
|
if (!id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImUtf8.Checkbox("Log IMC File Replacements"u8, ref DebugConfiguration.WriteImcBytesToLog);
|
ImUtf8.Checkbox("Log IMC File Replacements"u8, ref DebugConfiguration.WriteImcBytesToLog);
|
||||||
|
ImUtf8.Checkbox("Scan for Skin Material Attributes"u8, ref DebugConfiguration.UseSkinMaterialProcessing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue