mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Add Human skin material handling
This commit is contained in:
parent
62e9dc164d
commit
a97d9e4953
4 changed files with 76 additions and 45 deletions
|
|
@ -35,6 +35,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
||||||
private readonly Hook<MPapResolveDelegate> _resolveMPapPathHook;
|
private readonly Hook<MPapResolveDelegate> _resolveMPapPathHook;
|
||||||
private readonly Hook<PerSlotResolveDelegate> _resolveMdlPathHook;
|
private readonly Hook<PerSlotResolveDelegate> _resolveMdlPathHook;
|
||||||
private readonly Hook<NamedResolveDelegate> _resolveMtrlPathHook;
|
private readonly Hook<NamedResolveDelegate> _resolveMtrlPathHook;
|
||||||
|
private readonly Hook<PerSlotResolveDelegate> _resolveSkinMtrlPathHook;
|
||||||
private readonly Hook<NamedResolveDelegate> _resolvePapPathHook;
|
private readonly Hook<NamedResolveDelegate> _resolvePapPathHook;
|
||||||
private readonly Hook<PerSlotResolveDelegate> _resolveKdbPathHook;
|
private readonly Hook<PerSlotResolveDelegate> _resolveKdbPathHook;
|
||||||
private readonly Hook<PerSlotResolveDelegate> _resolvePhybPathHook;
|
private readonly Hook<PerSlotResolveDelegate> _resolvePhybPathHook;
|
||||||
|
|
@ -65,6 +66,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
||||||
_resolveMPapPathHook = Create<MPapResolveDelegate>( $"{name}.{nameof(ResolveMPap)}", hooks, vTable[87], ResolveMPap);
|
_resolveMPapPathHook = Create<MPapResolveDelegate>( $"{name}.{nameof(ResolveMPap)}", hooks, vTable[87], ResolveMPap);
|
||||||
_resolveImcPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolveImc)}", hooks, vTable[89], ResolveImc);
|
_resolveImcPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolveImc)}", hooks, vTable[89], ResolveImc);
|
||||||
_resolveMtrlPathHook = Create<NamedResolveDelegate>( $"{name}.{nameof(ResolveMtrl)}", hooks, vTable[90], ResolveMtrl);
|
_resolveMtrlPathHook = Create<NamedResolveDelegate>( $"{name}.{nameof(ResolveMtrl)}", hooks, vTable[90], ResolveMtrl);
|
||||||
|
_resolveSkinMtrlPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolveSkinMtrl)}", hooks, vTable[91], ResolveSkinMtrl);
|
||||||
_resolveDecalPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolveDecal)}", hooks, vTable[92], ResolveDecal);
|
_resolveDecalPathHook = Create<PerSlotResolveDelegate>($"{name}.{nameof(ResolveDecal)}", hooks, vTable[92], ResolveDecal);
|
||||||
_resolveVfxPathHook = Create<VfxResolveDelegate>( $"{name}.{nameof(ResolveVfx)}", hooks, vTable[93], type, ResolveVfx, ResolveVfxHuman);
|
_resolveVfxPathHook = Create<VfxResolveDelegate>( $"{name}.{nameof(ResolveVfx)}", hooks, vTable[93], type, ResolveVfx, ResolveVfxHuman);
|
||||||
_resolveEidPathHook = Create<SingleResolveDelegate>( $"{name}.{nameof(ResolveEid)}", hooks, vTable[94], ResolveEid);
|
_resolveEidPathHook = Create<SingleResolveDelegate>( $"{name}.{nameof(ResolveEid)}", hooks, vTable[94], ResolveEid);
|
||||||
|
|
@ -83,6 +85,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
||||||
_resolveMPapPathHook.Enable();
|
_resolveMPapPathHook.Enable();
|
||||||
_resolveMdlPathHook.Enable();
|
_resolveMdlPathHook.Enable();
|
||||||
_resolveMtrlPathHook.Enable();
|
_resolveMtrlPathHook.Enable();
|
||||||
|
_resolveSkinMtrlPathHook.Enable();
|
||||||
_resolvePapPathHook.Enable();
|
_resolvePapPathHook.Enable();
|
||||||
_resolveKdbPathHook.Enable();
|
_resolveKdbPathHook.Enable();
|
||||||
_resolvePhybPathHook.Enable();
|
_resolvePhybPathHook.Enable();
|
||||||
|
|
@ -103,6 +106,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
||||||
_resolveMPapPathHook.Disable();
|
_resolveMPapPathHook.Disable();
|
||||||
_resolveMdlPathHook.Disable();
|
_resolveMdlPathHook.Disable();
|
||||||
_resolveMtrlPathHook.Disable();
|
_resolveMtrlPathHook.Disable();
|
||||||
|
_resolveSkinMtrlPathHook.Disable();
|
||||||
_resolvePapPathHook.Disable();
|
_resolvePapPathHook.Disable();
|
||||||
_resolveKdbPathHook.Disable();
|
_resolveKdbPathHook.Disable();
|
||||||
_resolvePhybPathHook.Disable();
|
_resolvePhybPathHook.Disable();
|
||||||
|
|
@ -123,6 +127,7 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
||||||
_resolveMPapPathHook.Dispose();
|
_resolveMPapPathHook.Dispose();
|
||||||
_resolveMdlPathHook.Dispose();
|
_resolveMdlPathHook.Dispose();
|
||||||
_resolveMtrlPathHook.Dispose();
|
_resolveMtrlPathHook.Dispose();
|
||||||
|
_resolveSkinMtrlPathHook.Dispose();
|
||||||
_resolvePapPathHook.Dispose();
|
_resolvePapPathHook.Dispose();
|
||||||
_resolveKdbPathHook.Dispose();
|
_resolveKdbPathHook.Dispose();
|
||||||
_resolvePhybPathHook.Dispose();
|
_resolvePhybPathHook.Dispose();
|
||||||
|
|
@ -153,6 +158,9 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
|
||||||
private nint ResolveMtrl(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, nint mtrlFileName)
|
private nint ResolveMtrl(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, nint mtrlFileName)
|
||||||
=> 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)
|
||||||
|
=> ResolvePath(drawObject, _resolveSkinMtrlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex));
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,8 @@ internal unsafe partial record ResolveContext(
|
||||||
return GetOrCreateNode(ResourceType.Tex, (nint)tex->Texture, &tex->ResourceHandle, gamePath);
|
return GetOrCreateNode(ResourceType.Tex, (nint)tex->Texture, &tex->ResourceHandle, gamePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceNode? CreateNodeFromModel(Model* mdl, ResourceHandle* imc, TextureResourceHandle* decalHandle, ResourceHandle* mpapHandle)
|
public ResourceNode? CreateNodeFromModel(Model* mdl, ResourceHandle* imc, TextureResourceHandle* decalHandle,
|
||||||
|
MaterialResourceHandle* skinMtrlHandle, ResourceHandle* mpapHandle)
|
||||||
{
|
{
|
||||||
if (mdl is null || mdl->ModelResourceHandle is null)
|
if (mdl is null || mdl->ModelResourceHandle is null)
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -218,6 +219,12 @@ internal unsafe partial record ResolveContext(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skinMtrlHandle is not null
|
||||||
|
&& Utf8GamePath.FromByteString(CharacterBase->ResolveSkinMtrlPathAsByteString(SlotIndex), out var skinMtrlPath)
|
||||||
|
&& CreateNodeFromMaterial(skinMtrlHandle->Material, skinMtrlPath) is
|
||||||
|
{ } skinMaaterialNode)
|
||||||
|
node.Children.Add(skinMaaterialNode);
|
||||||
|
|
||||||
if (CreateNodeFromDecal(decalHandle, imc) is { } decalNode)
|
if (CreateNodeFromDecal(decalHandle, imc) is { } decalNode)
|
||||||
node.Children.Add(decalNode);
|
node.Children.Add(decalNode);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,12 @@ public class ResourceTree(
|
||||||
// TODO ClientStructs-ify (aers/FFXIVClientStructs#1312)
|
// TODO ClientStructs-ify (aers/FFXIVClientStructs#1312)
|
||||||
var mpapArrayPtr = *(ResourceHandle***)((nint)model + 0x948);
|
var mpapArrayPtr = *(ResourceHandle***)((nint)model + 0x948);
|
||||||
var mpapArray = mpapArrayPtr is not null ? new ReadOnlySpan<Pointer<ResourceHandle>>(mpapArrayPtr, model->SlotCount) : [];
|
var mpapArray = mpapArrayPtr is not null ? new ReadOnlySpan<Pointer<ResourceHandle>>(mpapArrayPtr, model->SlotCount) : [];
|
||||||
|
// TODO ClientStructs-ify (aers/FFXIVClientStructs#1474)
|
||||||
|
var skinMtrlArray = modelType switch
|
||||||
|
{
|
||||||
|
ModelType.Human => new ReadOnlySpan<Pointer<MaterialResourceHandle>>((MaterialResourceHandle**)((nint)model + 0xB48), 5),
|
||||||
|
_ => [],
|
||||||
|
};
|
||||||
var decalArray = modelType switch
|
var decalArray = modelType switch
|
||||||
{
|
{
|
||||||
ModelType.Human => human->SlotDecalsSpan,
|
ModelType.Human => human->SlotDecalsSpan,
|
||||||
|
|
@ -108,7 +114,8 @@ public class ResourceTree(
|
||||||
|
|
||||||
var mdl = model->Models[i];
|
var mdl = model->Models[i];
|
||||||
if (slotContext.CreateNodeFromModel(mdl, imc, i < decalArray.Length ? decalArray[(int)i].Value : null,
|
if (slotContext.CreateNodeFromModel(mdl, imc, i < decalArray.Length ? decalArray[(int)i].Value : null,
|
||||||
i < mpapArray.Length ? mpapArray[(int)i].Value : null) is { } mdlNode)
|
i < skinMtrlArray.Length ? skinMtrlArray[(int)i].Value : null, i < mpapArray.Length ? mpapArray[(int)i].Value : null) is
|
||||||
|
{ } mdlNode)
|
||||||
{
|
{
|
||||||
if (globalContext.WithUiData)
|
if (globalContext.WithUiData)
|
||||||
mdlNode.FallbackName = $"Model #{i}";
|
mdlNode.FallbackName = $"Model #{i}";
|
||||||
|
|
@ -166,7 +173,8 @@ public class ResourceTree(
|
||||||
}
|
}
|
||||||
|
|
||||||
var mdl = subObject->Models[i];
|
var mdl = subObject->Models[i];
|
||||||
if (slotContext.CreateNodeFromModel(mdl, imc, weapon->Decal, i < mpapArray.Length ? mpapArray[i].Value : null) is { } mdlNode)
|
if (slotContext.CreateNodeFromModel(mdl, imc, weapon->Decal, null, i < mpapArray.Length ? mpapArray[i].Value : null) is
|
||||||
|
{ } mdlNode)
|
||||||
{
|
{
|
||||||
if (globalContext.WithUiData)
|
if (globalContext.WithUiData)
|
||||||
mdlNode.FallbackName = $"Weapon #{weaponIndex}, Model #{i}";
|
mdlNode.FallbackName = $"Weapon #{weaponIndex}, Model #{i}";
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,14 @@ internal static class StructExtensions
|
||||||
return ToOwnedByteString(character.ResolveMtrlPath(pathBuffer, CharacterBase.PathBufferSize, slotIndex, mtrlFileName));
|
return ToOwnedByteString(character.ResolveMtrlPath(pathBuffer, CharacterBase.PathBufferSize, slotIndex, mtrlFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static unsafe CiByteString ResolveSkinMtrlPathAsByteString(ref this CharacterBase character, uint slotIndex)
|
||||||
|
{
|
||||||
|
// TODO ClientStructs-ify (aers/FFXIVClientStructs#1474)
|
||||||
|
var vf91 = (delegate* unmanaged<CharacterBase*, byte*, nuint, uint, byte*>)((nint*)character.VirtualTable)[91];
|
||||||
|
var pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
|
||||||
|
return ToOwnedByteString(vf91((CharacterBase*)Unsafe.AsPointer(ref character), pathBuffer, CharacterBase.PathBufferSize, slotIndex));
|
||||||
|
}
|
||||||
|
|
||||||
public static CiByteString ResolveMaterialPapPathAsByteString(ref this CharacterBase character, uint slotIndex, uint unkSId)
|
public static CiByteString ResolveMaterialPapPathAsByteString(ref this CharacterBase character, uint slotIndex, uint unkSId)
|
||||||
{
|
{
|
||||||
Span<byte> pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
|
Span<byte> pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue