ClientStructs-ify some stuff

This commit is contained in:
Exter-N 2024-01-22 01:51:42 +01:00
parent b5a71ed7b3
commit c2e5499aef
7 changed files with 53 additions and 110 deletions

View file

@ -7,7 +7,7 @@ using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations;
using Penumbra.String;
using Penumbra.String.Classes;
using static Penumbra.Interop.Structs.CharacterBaseUtility;
using static Penumbra.Interop.Structs.StructExtensions;
using ModelType = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase.ModelType;
namespace Penumbra.Interop.ResourceTree;
@ -71,7 +71,7 @@ internal partial record ResolveContext
private unsafe Utf8GamePath ResolveModelPathNative()
{
var path = ResolveMdlPath(CharacterBase, SlotIndex);
var path = CharacterBase.Value->ResolveMdlPathAsByteString(SlotIndex);
return Utf8GamePath.FromByteString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty;
}
@ -139,8 +139,7 @@ internal partial record ResolveContext
private unsafe Utf8GamePath ResolveMonsterMaterialPath(Utf8GamePath modelPath, ResourceHandle* imc, byte* mtrlFileName)
{
// TODO: Submit this (Monster->Variant) to ClientStructs
var variant = ResolveMaterialVariant(imc, ((byte*)CharacterBase.Value)[0x8F4]);
var variant = ResolveMaterialVariant(imc, (byte)((Monster*)CharacterBase.Value)->Variant);
var fileName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlFileName);
Span<byte> pathBuffer = stackalloc byte[260];
@ -196,7 +195,7 @@ internal partial record ResolveContext
ByteString? path;
try
{
path = ResolveMtrlPath(CharacterBase, SlotIndex, mtrlFileName);
path = CharacterBase.Value->ResolveMtrlPathAsByteString(SlotIndex, mtrlFileName);
}
catch (AccessViolationException)
{
@ -277,7 +276,7 @@ internal partial record ResolveContext
private unsafe Utf8GamePath ResolveSkeletonPathNative(uint partialSkeletonIndex)
{
var path = ResolveSklbPath(CharacterBase, partialSkeletonIndex);
var path = CharacterBase.Value->ResolveSklbPathAsByteString(partialSkeletonIndex);
return Utf8GamePath.FromByteString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty;
}
@ -305,7 +304,7 @@ internal partial record ResolveContext
private unsafe Utf8GamePath ResolveSkeletonParameterPathNative(uint partialSkeletonIndex)
{
var path = ResolveSkpPath(CharacterBase, partialSkeletonIndex);
var path = CharacterBase.Value->ResolveSkpPathAsByteString(partialSkeletonIndex);
return Utf8GamePath.FromByteString(path, out var gamePath) ? gamePath : Utf8GamePath.Empty;
}
}

View file

@ -13,8 +13,6 @@ using Penumbra.GameData.Structs;
using Penumbra.String;
using Penumbra.String.Classes;
using Penumbra.UI;
using static Penumbra.Interop.Structs.CharacterBaseUtility;
using static Penumbra.Interop.Structs.ModelResourceHandleUtility;
using static Penumbra.Interop.Structs.StructExtensions;
using ModelType = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase.ModelType;
@ -126,7 +124,7 @@ internal partial record ResolveContext(
if (eid == null)
return null;
if (!Utf8GamePath.FromByteString(ResolveEidPath(CharacterBase), out var path))
if (!Utf8GamePath.FromByteString(CharacterBase.Value->ResolveEidPathAsByteString(), out var path))
return null;
return GetOrCreateNode(ResourceType.Eid, 0, eid, path);
@ -137,7 +135,7 @@ internal partial record ResolveContext(
if (imc == null)
return null;
if (!Utf8GamePath.FromByteString(ResolveImcPath(CharacterBase, SlotIndex), out var path))
if (!Utf8GamePath.FromByteString(CharacterBase.Value->ResolveImcPathAsByteString(SlotIndex), out var path))
return null;
return GetOrCreateNode(ResourceType.Imc, 0, imc, path);
@ -174,7 +172,7 @@ internal partial record ResolveContext(
if (mtrl == null)
continue;
var mtrlFileName = GetMaterialFileNameBySlot(mdlResource, (uint)i);
var mtrlFileName = mdlResource->GetMaterialFileNameBySlot((uint)i);
var mtrlNode = CreateNodeFromMaterial(mtrl, ResolveMaterialPath(path, imc, mtrlFileName));
if (mtrlNode != null)
{

View file

@ -1,62 +0,0 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Penumbra.String;
namespace Penumbra.Interop.Structs;
// TODO submit these to ClientStructs
public static unsafe class CharacterBaseUtility
{
private const int PathBufferSize = 260;
private const uint ResolveSklbPathVf = 72;
private const uint ResolveMdlPathVf = 73;
private const uint ResolveSkpPathVf = 74;
private const uint ResolveImcPathVf = 81;
private const uint ResolveMtrlPathVf = 82;
private const uint ResolveEidPathVf = 85;
private static void* GetVFunc(CharacterBase* characterBase, uint vfIndex)
=> ((void**)characterBase->VTable)[vfIndex];
private static ByteString? ResolvePath(CharacterBase* characterBase, uint vfIndex)
{
var vFunc = (delegate* unmanaged<CharacterBase*, byte*, nint, byte*>)GetVFunc(characterBase, vfIndex);
var pathBuffer = stackalloc byte[PathBufferSize];
var path = vFunc(characterBase, pathBuffer, PathBufferSize);
return path != null ? new ByteString(path).Clone() : null;
}
private static ByteString? ResolvePath(CharacterBase* characterBase, uint vfIndex, uint slotIndex)
{
var vFunc = (delegate* unmanaged<CharacterBase*, byte*, nint, uint, byte*>)GetVFunc(characterBase, vfIndex);
var pathBuffer = stackalloc byte[PathBufferSize];
var path = vFunc(characterBase, pathBuffer, PathBufferSize, slotIndex);
return path != null ? new ByteString(path).Clone() : null;
}
private static ByteString? ResolvePath(CharacterBase* characterBase, uint vfIndex, uint slotIndex, byte* name)
{
var vFunc = (delegate* unmanaged<CharacterBase*, byte*, nint, uint, byte*, byte*>)GetVFunc(characterBase, vfIndex);
var pathBuffer = stackalloc byte[PathBufferSize];
var path = vFunc(characterBase, pathBuffer, PathBufferSize, slotIndex, name);
return path != null ? new ByteString(path).Clone() : null;
}
public static ByteString? ResolveEidPath(CharacterBase* characterBase)
=> ResolvePath(characterBase, ResolveEidPathVf);
public static ByteString? ResolveImcPath(CharacterBase* characterBase, uint slotIndex)
=> ResolvePath(characterBase, ResolveImcPathVf, slotIndex);
public static ByteString? ResolveMdlPath(CharacterBase* characterBase, uint slotIndex)
=> ResolvePath(characterBase, ResolveMdlPathVf, slotIndex);
public static ByteString? ResolveMtrlPath(CharacterBase* characterBase, uint slotIndex, byte* mtrlFileName)
=> ResolvePath(characterBase, ResolveMtrlPathVf, slotIndex, mtrlFileName);
public static ByteString? ResolveSklbPath(CharacterBase* characterBase, uint partialSkeletonIndex)
=> ResolvePath(characterBase, ResolveSklbPathVf, partialSkeletonIndex);
public static ByteString? ResolveSkpPath(CharacterBase* characterBase, uint partialSkeletonIndex)
=> ResolvePath(characterBase, ResolveSkpPathVf, partialSkeletonIndex);
}

View file

@ -1,19 +0,0 @@
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using Penumbra.GameData;
namespace Penumbra.Interop.Structs;
// TODO submit this to ClientStructs
public class ModelResourceHandleUtility
{
public ModelResourceHandleUtility(IGameInteropProvider interop)
=> interop.InitializeFromAttributes(this);
[Signature(Sigs.GetMaterialFileNameBySlot)]
private static nint _getMaterialFileNameBySlot = nint.Zero;
public static unsafe byte* GetMaterialFileNameBySlot(ModelResourceHandle* handle, uint slot)
=> ((delegate* unmanaged<ModelResourceHandle*, uint, byte*>)_getMaterialFileNameBySlot)(handle, slot);
}

View file

@ -1,3 +1,4 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.STD;
using Penumbra.String;
@ -5,20 +6,48 @@ namespace Penumbra.Interop.Structs;
internal static class StructExtensions
{
// TODO submit this to ClientStructs
public static unsafe ReadOnlySpan<byte> AsSpan(in this StdString str)
{
if (str.Length < 16)
{
fixed (StdString* pStr = &str)
{
return new(pStr->Buffer, (int)str.Length);
}
}
else
return new(str.BufferPtr, (int)str.Length);
}
public static unsafe ByteString AsByteString(in this StdString str)
=> ByteString.FromSpanUnsafe(str.AsSpan(), true);
public static ByteString ResolveEidPathAsByteString(in this CharacterBase character)
{
Span<byte> pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
return ToOwnedByteString(character.ResolveEidPath(pathBuffer));
}
public static ByteString ResolveImcPathAsByteString(in this CharacterBase character, uint slotIndex)
{
Span<byte> pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
return ToOwnedByteString(character.ResolveImcPath(pathBuffer, slotIndex));
}
public static ByteString ResolveMdlPathAsByteString(in this CharacterBase character, uint slotIndex)
{
Span<byte> pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
return ToOwnedByteString(character.ResolveMdlPath(pathBuffer, slotIndex));
}
public static unsafe ByteString ResolveMtrlPathAsByteString(in this CharacterBase character, uint slotIndex, byte* mtrlFileName)
{
var pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
return ToOwnedByteString(character.ResolveMtrlPath(pathBuffer, CharacterBase.PathBufferSize, slotIndex, mtrlFileName));
}
public static ByteString ResolveSklbPathAsByteString(in this CharacterBase character, uint partialSkeletonIndex)
{
Span<byte> pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
return ToOwnedByteString(character.ResolveSklbPath(pathBuffer, partialSkeletonIndex));
}
public static ByteString ResolveSkpPathAsByteString(in this CharacterBase character, uint partialSkeletonIndex)
{
Span<byte> pathBuffer = stackalloc byte[CharacterBase.PathBufferSize];
return ToOwnedByteString(character.ResolveSkpPath(pathBuffer, partialSkeletonIndex));
}
private static unsafe ByteString ToOwnedByteString(byte* str)
=> str == null ? ByteString.Empty : new ByteString(str).Clone();
private static ByteString ToOwnedByteString(ReadOnlySpan<byte> str)
=> str.Length == 0 ? ByteString.Empty : ByteString.FromSpanUnsafe(str, true).Clone();
}

View file

@ -76,7 +76,6 @@ public class Penumbra : IDalamudPlugin
_communicatorService = _services.GetService<CommunicatorService>();
_services.GetService<ResourceService>(); // Initialize because not required anywhere else.
_services.GetService<ModCacheManager>(); // Initialize because not required anywhere else.
_services.GetService<ModelResourceHandleUtility>(); // Initialize because not required anywhere else.
_collectionManager.Caches.CreateNecessaryCaches();
_services.GetService<PathResolver>();
_services.GetService<SkinFixer>();

View file

@ -99,8 +99,7 @@ public static class ServiceManagerA
.AddSingleton<CreateFileWHook>()
.AddSingleton<ResidentResourceManager>()
.AddSingleton<FontReloader>()
.AddSingleton<RedrawService>()
.AddSingleton<ModelResourceHandleUtility>();
.AddSingleton<RedrawService>();
private static ServiceManager AddConfiguration(this ServiceManager services)
=> services.AddSingleton<Configuration>()