mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
ClientStructs-ify a few things
This commit is contained in:
parent
6375faa758
commit
00dc5f48b1
23 changed files with 102 additions and 314 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit a4f9b285c82f84ff0841695c0787dbba93afc59b
|
||||
Subproject commit 6f17ef70c41f3b31a401fdc9d6e37087e64f2035
|
||||
|
|
@ -31,7 +31,7 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase
|
|||
if (mtrlHandle == null)
|
||||
throw new InvalidOperationException("Material doesn't have a resource handle");
|
||||
|
||||
var colorSetTextures = ((Structs.CharacterBaseExt*)DrawObject)->ColorTableTextures;
|
||||
var colorSetTextures = DrawObject->ColorTableTextures;
|
||||
if (colorSetTextures == null)
|
||||
throw new InvalidOperationException("Draw object doesn't have color table textures");
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase
|
|||
textureSize[1] = TextureHeight;
|
||||
|
||||
using var texture =
|
||||
new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false);
|
||||
new SafeTextureHandle(Device.Instance()->CreateTexture2D(textureSize, 1, 0x2460, 0x80000804, 7), false);
|
||||
if (texture.IsInvalid)
|
||||
return;
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase
|
|||
{
|
||||
fixed (Half* colorTable = _colorTable)
|
||||
{
|
||||
success = Structs.TextureUtility.InitializeContents(texture.Texture, colorTable);
|
||||
success = texture.Texture->InitializeContents(colorTable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase
|
|||
if (!base.IsStillValid())
|
||||
return false;
|
||||
|
||||
var colorSetTextures = ((Structs.CharacterBaseExt*)DrawObject)->ColorTableTextures;
|
||||
var colorSetTextures = DrawObject->ColorTableTextures;
|
||||
if (colorSetTextures == null)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public sealed unsafe class LiveMaterialPreviewer : LiveMaterialPreviewerBase
|
|||
if (mtrlHandle == null)
|
||||
throw new InvalidOperationException("Material doesn't have a resource handle");
|
||||
|
||||
var shpkHandle = ((Structs.MtrlResource*)mtrlHandle)->ShpkResourceHandle;
|
||||
var shpkHandle = mtrlHandle->ShaderPackageResourceHandle;
|
||||
if (shpkHandle == null)
|
||||
throw new InvalidOperationException("Material doesn't have a ShPk resource handle");
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ public sealed unsafe class LiveMaterialPreviewer : LiveMaterialPreviewerBase
|
|||
if (!CheckValidity())
|
||||
return;
|
||||
|
||||
((Structs.Material*)Material)->ShaderPackageFlags = shPkFlags;
|
||||
Material->ShaderFlags = shPkFlags;
|
||||
}
|
||||
|
||||
public void SetMaterialParameter(uint parameterCrc, Index offset, Span<float> value)
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public readonly record struct MaterialInfo(ObjectIndex ObjectIndex, DrawObjectTy
|
|||
continue;
|
||||
|
||||
var mtrlHandle = material->MaterialResourceHandle;
|
||||
var path = ResolveContext.GetResourceHandlePath((Structs.ResourceHandle*)mtrlHandle);
|
||||
var path = ResolveContext.GetResourceHandlePath(&mtrlHandle->ResourceHandle);
|
||||
if (path == needle)
|
||||
result.Add(new MaterialInfo(index, type, i, j));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using OtterGui;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
using Penumbra.UI;
|
||||
using static Penumbra.Interop.Structs.StructExtensions;
|
||||
|
||||
namespace Penumbra.Interop.ResourceTree;
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
if (!Utf8GamePath.FromByteString(ByteString.Join((byte)'/', ShpkPrefix, gamePath), out var path, false))
|
||||
return null;
|
||||
|
||||
return CreateNodeFromGamePath(ResourceType.Shpk, (nint)resourceHandle->ShaderPackage, &resourceHandle->Handle, path, @internal);
|
||||
return CreateNodeFromGamePath(ResourceType.Shpk, (nint)resourceHandle->ShaderPackage, &resourceHandle->ResourceHandle, path, @internal);
|
||||
}
|
||||
|
||||
private unsafe ResourceNode? CreateNodeFromTex(TextureResourceHandle* resourceHandle, ByteString gamePath, bool @internal, bool dx11)
|
||||
|
|
@ -68,7 +69,7 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
if (!Utf8GamePath.FromByteString(gamePath, out var path))
|
||||
return null;
|
||||
|
||||
return CreateNodeFromGamePath(ResourceType.Tex, (nint)resourceHandle->KernelTexture, &resourceHandle->Handle, path, @internal);
|
||||
return CreateNodeFromGamePath(ResourceType.Tex, (nint)resourceHandle->Texture, &resourceHandle->ResourceHandle, path, @internal);
|
||||
}
|
||||
|
||||
private unsafe ResourceNode CreateNodeFromGamePath(ResourceType type, nint objectAddress, ResourceHandle* resourceHandle,
|
||||
|
|
@ -118,22 +119,22 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
if (Nodes.TryGetValue((nint)tex, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Tex, (nint)tex->KernelTexture, &tex->Handle, false);
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Tex, (nint)tex->Texture, &tex->ResourceHandle, false);
|
||||
if (node != null)
|
||||
Nodes.Add((nint)tex, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public unsafe ResourceNode? CreateNodeFromRenderModel(RenderModel* mdl)
|
||||
public unsafe ResourceNode? CreateNodeFromRenderModel(Model* mdl)
|
||||
{
|
||||
if (mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara)
|
||||
if (mdl == null || mdl->ModelResourceHandle == null || mdl->ModelResourceHandle->ResourceHandle.Type.Category != ResourceHandleType.HandleCategory.Chara)
|
||||
return null;
|
||||
|
||||
if (Nodes.TryGetValue((nint)mdl->ResourceHandle, out var cached))
|
||||
if (Nodes.TryGetValue((nint)mdl->ModelResourceHandle, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mdl, (nint)mdl, mdl->ResourceHandle, false);
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mdl, (nint)mdl, &mdl->ModelResourceHandle->ResourceHandle, false);
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
|
|
@ -149,7 +150,7 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
}
|
||||
}
|
||||
|
||||
Nodes.Add((nint)mdl->ResourceHandle, node);
|
||||
Nodes.Add((nint)mdl->ModelResourceHandle, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
|
@ -169,27 +170,27 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
}
|
||||
|
||||
static uint? GetTextureSamplerId(Material* mtrl, TextureResourceHandle* handle, HashSet<uint> alreadyVisitedSamplerIds)
|
||||
=> mtrl->TextureSpan.FindFirst(p => p.ResourceHandle == handle && !alreadyVisitedSamplerIds.Contains(p.Id), out var p)
|
||||
=> mtrl->TexturesSpan.FindFirst(p => p.Texture == handle && !alreadyVisitedSamplerIds.Contains(p.Id), out var p)
|
||||
? p.Id
|
||||
: null;
|
||||
|
||||
static uint? GetSamplerCrcById(ShaderPackage* shpk, uint id)
|
||||
=> new ReadOnlySpan<ShaderPackageUtility.Sampler>(shpk->Samplers, shpk->SamplerCount).FindFirst(s => s.Id == id, out var s)
|
||||
? s.Crc
|
||||
=> shpk->SamplersSpan.FindFirst(s => s.Id == id, out var s)
|
||||
? s.CRC
|
||||
: null;
|
||||
|
||||
if (mtrl == null)
|
||||
return null;
|
||||
|
||||
var resource = mtrl->ResourceHandle;
|
||||
var resource = mtrl->MaterialResourceHandle;
|
||||
if (Nodes.TryGetValue((nint)resource, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mtrl, (nint)mtrl, &resource->Handle, false);
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mtrl, (nint)mtrl, &resource->ResourceHandle, false);
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
var shpkNode = CreateNodeFromShpk(resource->ShpkResourceHandle, new ByteString(resource->ShpkString), false);
|
||||
var shpkNode = CreateNodeFromShpk(resource->ShaderPackageResourceHandle, new ByteString(resource->ShpkName), false);
|
||||
if (shpkNode != null)
|
||||
{
|
||||
if (WithUiData)
|
||||
|
|
@ -200,10 +201,10 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
var shpk = WithUiData && shpkNode != null ? (ShaderPackage*)shpkNode.ObjectAddress : null;
|
||||
|
||||
var alreadyProcessedSamplerIds = new HashSet<uint>();
|
||||
for (var i = 0; i < resource->NumTex; i++)
|
||||
for (var i = 0; i < resource->TextureCount; i++)
|
||||
{
|
||||
var texNode = CreateNodeFromTex(resource->TexSpace[i].ResourceHandle, new ByteString(resource->TexString(i)), false,
|
||||
resource->TexIsDX11(i));
|
||||
var texNode = CreateNodeFromTex(resource->Textures[i].TextureResourceHandle, new ByteString(resource->TexturePath(i)), false,
|
||||
resource->Textures[i].IsDX11);
|
||||
if (texNode == null)
|
||||
continue;
|
||||
|
||||
|
|
@ -212,12 +213,12 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
string? name = null;
|
||||
if (shpk != null)
|
||||
{
|
||||
var index = GetTextureIndex(mtrl, resource->TexSpace[i].Flags, alreadyProcessedSamplerIds);
|
||||
var index = GetTextureIndex(mtrl, resource->Textures[i].Flags, alreadyProcessedSamplerIds);
|
||||
uint? samplerId;
|
||||
if (index != 0x001F)
|
||||
samplerId = mtrl->Textures[index].Id;
|
||||
else
|
||||
samplerId = GetTextureSamplerId(mtrl, resource->TexSpace[i].ResourceHandle, alreadyProcessedSamplerIds);
|
||||
samplerId = GetTextureSamplerId(mtrl, resource->Textures[i].TextureResourceHandle, alreadyProcessedSamplerIds);
|
||||
if (samplerId.HasValue)
|
||||
{
|
||||
alreadyProcessedSamplerIds.Add(samplerId.Value);
|
||||
|
|
@ -367,7 +368,7 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
if (handle == null)
|
||||
return ByteString.Empty;
|
||||
|
||||
var name = handle->FileName();
|
||||
var name = handle->FileName.AsByteString();
|
||||
if (name.IsEmpty)
|
||||
return ByteString.Empty;
|
||||
|
||||
|
|
@ -388,6 +389,6 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
|||
if (handle == null)
|
||||
return 0;
|
||||
|
||||
return ResourceHandle.GetLength(handle);
|
||||
return handle->GetLength();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.UI;
|
||||
using CustomizeData = FFXIVClientStructs.FFXIV.Client.Game.Character.CustomizeData;
|
||||
|
||||
|
|
@ -50,11 +50,12 @@ public class ResourceTree
|
|||
{
|
||||
var character = (Character*)GameObjectAddress;
|
||||
var model = (CharacterBase*)DrawObjectAddress;
|
||||
var human = model->GetModelType() == CharacterBase.ModelType.Human ? (Human*)model : null;
|
||||
var equipment = new ReadOnlySpan<CharacterArmor>(&character->DrawData.Head, 10);
|
||||
// var customize = new ReadOnlySpan<byte>( character->CustomizeData, 26 );
|
||||
ModelId = character->CharacterData.ModelCharaId;
|
||||
CustomizeData = character->DrawData.CustomizeData;
|
||||
RaceCode = model->GetModelType() == CharacterBase.ModelType.Human ? (GenderRace)((Human*)model)->RaceSexId : GenderRace.Unknown;
|
||||
RaceCode = human != null ? (GenderRace)human->RaceSexId : GenderRace.Unknown;
|
||||
|
||||
for (var i = 0; i < model->SlotCount; ++i)
|
||||
{
|
||||
|
|
@ -72,7 +73,7 @@ public class ResourceTree
|
|||
Nodes.Add(imcNode);
|
||||
}
|
||||
|
||||
var mdl = (RenderModel*)model->Models[i];
|
||||
var mdl = model->Models[i];
|
||||
var mdlNode = context.CreateNodeFromRenderModel(mdl);
|
||||
if (mdlNode != null)
|
||||
{
|
||||
|
|
@ -84,13 +85,13 @@ public class ResourceTree
|
|||
|
||||
AddSkeleton(Nodes, globalContext.CreateContext(EquipSlot.Unknown, default), model->Skeleton);
|
||||
|
||||
if (model->GetModelType() == CharacterBase.ModelType.Human)
|
||||
AddHumanResources(globalContext, (HumanExt*)model);
|
||||
if (human != null)
|
||||
AddHumanResources(globalContext, human);
|
||||
}
|
||||
|
||||
private unsafe void AddHumanResources(GlobalResolveContext globalContext, HumanExt* human)
|
||||
private unsafe void AddHumanResources(GlobalResolveContext globalContext, Human* human)
|
||||
{
|
||||
var firstSubObject = (CharacterBase*)human->Human.CharacterBase.DrawObject.Object.ChildObject;
|
||||
var firstSubObject = (CharacterBase*)human->CharacterBase.DrawObject.Object.ChildObject;
|
||||
if (firstSubObject != null)
|
||||
{
|
||||
var subObjectNodes = new List<ResourceNode>();
|
||||
|
|
@ -116,7 +117,7 @@ public class ResourceTree
|
|||
subObjectNodes.Add(imcNode);
|
||||
}
|
||||
|
||||
var mdl = (RenderModel*)subObject->Models[i];
|
||||
var mdl = subObject->Models[i];
|
||||
var mdlNode = subObjectContext.CreateNodeFromRenderModel(mdl);
|
||||
if (mdlNode != null)
|
||||
{
|
||||
|
|
@ -137,7 +138,7 @@ public class ResourceTree
|
|||
|
||||
var context = globalContext.CreateContext(EquipSlot.Unknown, default);
|
||||
|
||||
var decalNode = context.CreateNodeFromTex((TextureResourceHandle*)human->Decal);
|
||||
var decalNode = context.CreateNodeFromTex(human->Decal);
|
||||
if (decalNode != null)
|
||||
{
|
||||
if (globalContext.WithUiData)
|
||||
|
|
@ -149,7 +150,7 @@ public class ResourceTree
|
|||
Nodes.Add(decalNode);
|
||||
}
|
||||
|
||||
var legacyDecalNode = context.CreateNodeFromTex((TextureResourceHandle*)human->LegacyBodyDecal);
|
||||
var legacyDecalNode = context.CreateNodeFromTex(human->LegacyBodyDecal);
|
||||
if (legacyDecalNode != null)
|
||||
{
|
||||
if (globalContext.WithUiData)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
||||
namespace Penumbra.Interop.SafeHandles;
|
||||
|
||||
|
|
@ -18,7 +17,7 @@ public unsafe class SafeTextureHandle : SafeHandle
|
|||
throw new ArgumentException("Non-owning SafeTextureHandle with IncRef is unsupported");
|
||||
|
||||
if (incRef && handle != null)
|
||||
TextureUtility.IncRef(handle);
|
||||
handle->IncRef();
|
||||
SetHandle((nint)handle);
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +42,7 @@ public unsafe class SafeTextureHandle : SafeHandle
|
|||
}
|
||||
|
||||
if (handle != 0)
|
||||
TextureUtility.DecRef((Texture*)handle);
|
||||
((Texture*)handle)->DecRef();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using Dalamud.Hooking;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData;
|
||||
|
|
@ -73,19 +74,19 @@ public sealed unsafe class SkinFixer : IDisposable
|
|||
public ulong GetAndResetSlowPathCallDelta()
|
||||
=> Interlocked.Exchange(ref _slowPathCallDelta, 0);
|
||||
|
||||
private static bool IsSkinMaterial(Structs.MtrlResource* mtrlResource)
|
||||
private static bool IsSkinMaterial(MaterialResourceHandle* mtrlResource)
|
||||
{
|
||||
if (mtrlResource == null)
|
||||
return false;
|
||||
|
||||
var shpkName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlResource->ShpkString);
|
||||
var shpkName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(mtrlResource->ShpkName);
|
||||
return SkinShpkName.SequenceEqual(shpkName);
|
||||
}
|
||||
|
||||
private void OnMtrlShpkLoaded(nint mtrlResourceHandle, nint gameObject)
|
||||
{
|
||||
var mtrl = (Structs.MtrlResource*)mtrlResourceHandle;
|
||||
var shpk = mtrl->ShpkResourceHandle;
|
||||
var mtrl = (MaterialResourceHandle*)mtrlResourceHandle;
|
||||
var shpk = mtrl->ShaderPackageResourceHandle;
|
||||
if (shpk == null)
|
||||
return;
|
||||
|
||||
|
|
@ -109,7 +110,7 @@ public sealed unsafe class SkinFixer : IDisposable
|
|||
return _onRenderMaterialHook.Original(human, param);
|
||||
|
||||
var material = param->Model->Materials[param->MaterialIndex];
|
||||
var mtrlResource = (Structs.MtrlResource*)material->MaterialResourceHandle;
|
||||
var mtrlResource = material->MaterialResourceHandle;
|
||||
if (!IsSkinMaterial(mtrlResource))
|
||||
return _onRenderMaterialHook.Original(human, param);
|
||||
|
||||
|
|
@ -124,7 +125,7 @@ public sealed unsafe class SkinFixer : IDisposable
|
|||
{
|
||||
try
|
||||
{
|
||||
_utility.Address->SkinShpkResource = (Structs.ResourceHandle*)mtrlResource->ShpkResourceHandle;
|
||||
_utility.Address->SkinShpkResource = (Structs.ResourceHandle*)mtrlResource->ShaderPackageResourceHandle;
|
||||
return _onRenderMaterialHook.Original(human, param);
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
|
||||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct CharacterBaseExt
|
||||
{
|
||||
[FieldOffset(0x0)]
|
||||
public CharacterBase CharacterBase;
|
||||
|
||||
[FieldOffset(0x258)]
|
||||
public Texture** ColorTableTextures;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x70)]
|
||||
public unsafe struct ConstantBuffer
|
||||
{
|
||||
[FieldOffset(0x20)]
|
||||
public int Size;
|
||||
|
||||
[FieldOffset(0x24)]
|
||||
public int Flags;
|
||||
|
||||
[FieldOffset(0x28)]
|
||||
private void* _maybeSourcePointer;
|
||||
|
||||
public bool TryGetBuffer(out Span<float> buffer)
|
||||
{
|
||||
if ((Flags & 0x4003) == 0 && _maybeSourcePointer != null)
|
||||
{
|
||||
buffer = new Span<float>(_maybeSourcePointer, Size >> 2);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
|
||||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct HumanExt
|
||||
{
|
||||
[FieldOffset(0x0)]
|
||||
public Human Human;
|
||||
|
||||
[FieldOffset(0x0)]
|
||||
public CharacterBaseExt CharacterBase;
|
||||
|
||||
[FieldOffset(0x9E8)]
|
||||
public ResourceHandle* Decal;
|
||||
|
||||
[FieldOffset(0x9F0)]
|
||||
public ResourceHandle* LegacyBodyDecal;
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
|
||||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
|
||||
public unsafe struct Material
|
||||
{
|
||||
[FieldOffset(0x10)]
|
||||
public MtrlResource* ResourceHandle;
|
||||
|
||||
[FieldOffset(0x18)]
|
||||
public uint ShaderPackageFlags;
|
||||
|
||||
[FieldOffset(0x20)]
|
||||
public uint* ShaderKeys;
|
||||
|
||||
public int ShaderKeyCount
|
||||
=> (int)((uint*)Textures - ShaderKeys);
|
||||
|
||||
[FieldOffset(0x28)]
|
||||
public ConstantBuffer* MaterialParameter;
|
||||
|
||||
[FieldOffset(0x30)]
|
||||
public TextureEntry* Textures;
|
||||
|
||||
[FieldOffset(0x38)]
|
||||
public ushort TextureCount;
|
||||
|
||||
public Texture* Texture(int index)
|
||||
=> Textures[index].ResourceHandle->KernelTexture;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x18)]
|
||||
public struct TextureEntry
|
||||
{
|
||||
[FieldOffset(0x00)]
|
||||
public uint Id;
|
||||
|
||||
[FieldOffset(0x08)]
|
||||
public TextureResourceHandle* ResourceHandle;
|
||||
|
||||
[FieldOffset(0x10)]
|
||||
public uint SamplerFlags;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<TextureEntry> TextureSpan
|
||||
=> new(Textures, TextureCount);
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct MtrlResource
|
||||
{
|
||||
[FieldOffset(0x00)]
|
||||
public ResourceHandle Handle;
|
||||
|
||||
[FieldOffset(0xC8)]
|
||||
public ShaderPackageResourceHandle* ShpkResourceHandle;
|
||||
|
||||
[FieldOffset(0xD0)]
|
||||
public TextureEntry* TexSpace; // Contains the offsets for the tex files inside the string list.
|
||||
|
||||
[FieldOffset(0xE0)]
|
||||
public byte* StringList;
|
||||
|
||||
[FieldOffset(0xF8)]
|
||||
public ushort ShpkOffset;
|
||||
|
||||
[FieldOffset(0xFA)]
|
||||
public byte NumTex;
|
||||
|
||||
public byte* ShpkString
|
||||
=> StringList + ShpkOffset;
|
||||
|
||||
public byte* TexString(int idx)
|
||||
=> StringList + TexSpace[idx].PathOffset;
|
||||
|
||||
public bool TexIsDX11(int idx)
|
||||
=> TexSpace[idx].Flags >= 0x8000;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x10)]
|
||||
public struct TextureEntry
|
||||
{
|
||||
[FieldOffset(0x00)]
|
||||
public TextureResourceHandle* ResourceHandle;
|
||||
|
||||
[FieldOffset(0x08)]
|
||||
public ushort PathOffset;
|
||||
|
||||
[FieldOffset(0x0A)]
|
||||
public ushort Flags;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,9 @@ namespace Penumbra.Interop.Structs;
|
|||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct RenderModel
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public Model Model;
|
||||
|
||||
[FieldOffset(0x18)]
|
||||
public RenderModel* PreviousModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
using CsHandle = FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
|
||||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
|
|
@ -14,24 +12,8 @@ public unsafe struct TextureResourceHandle
|
|||
[FieldOffset(0x0)]
|
||||
public ResourceHandle Handle;
|
||||
|
||||
[FieldOffset(0x38)]
|
||||
public IntPtr Unk;
|
||||
|
||||
[FieldOffset(0x118)]
|
||||
public Texture* KernelTexture;
|
||||
|
||||
[FieldOffset(0x20)]
|
||||
public IntPtr NewKernelTexture;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct ShaderPackageResourceHandle
|
||||
{
|
||||
[FieldOffset(0x0)]
|
||||
public ResourceHandle Handle;
|
||||
|
||||
[FieldOffset(0xB0)]
|
||||
public ShaderPackage* ShaderPackage;
|
||||
public CsHandle.TextureResourceHandle CsHandle;
|
||||
}
|
||||
|
||||
public enum LoadState : byte
|
||||
|
|
@ -59,27 +41,14 @@ public unsafe struct ResourceHandle
|
|||
public ulong DataLength;
|
||||
}
|
||||
|
||||
public const int SsoSize = 15;
|
||||
public readonly ByteString FileName()
|
||||
=> CsHandle.FileName.AsByteString();
|
||||
|
||||
public byte* FileNamePtr()
|
||||
{
|
||||
if (FileNameLength > SsoSize)
|
||||
return FileNameData;
|
||||
public readonly bool GamePath(out Utf8GamePath path)
|
||||
=> Utf8GamePath.FromSpan(CsHandle.FileName.AsSpan(), out path);
|
||||
|
||||
fixed (byte** name = &FileNameData)
|
||||
{
|
||||
return (byte*)name;
|
||||
}
|
||||
}
|
||||
|
||||
public ByteString FileName()
|
||||
=> ByteString.FromByteStringUnsafe(FileNamePtr(), FileNameLength, true);
|
||||
|
||||
public ReadOnlySpan<byte> FileNameAsSpan()
|
||||
=> new(FileNamePtr(), FileNameLength);
|
||||
|
||||
public bool GamePath(out Utf8GamePath path)
|
||||
=> Utf8GamePath.FromSpan(FileNameAsSpan(), out path);
|
||||
[FieldOffset(0x00)]
|
||||
public CsHandle.ResourceHandle CsHandle;
|
||||
|
||||
[FieldOffset(0x00)]
|
||||
public void** VTable;
|
||||
|
|
@ -90,18 +59,9 @@ public unsafe struct ResourceHandle
|
|||
[FieldOffset(0x0C)]
|
||||
public ResourceType FileType;
|
||||
|
||||
[FieldOffset(0x10)]
|
||||
public uint Id;
|
||||
|
||||
[FieldOffset(0x28)]
|
||||
public uint FileSize;
|
||||
|
||||
[FieldOffset(0x2C)]
|
||||
public uint FileSize2;
|
||||
|
||||
[FieldOffset(0x34)]
|
||||
public uint FileSize3;
|
||||
|
||||
[FieldOffset(0x48)]
|
||||
public byte* FileNameData;
|
||||
|
||||
|
|
@ -114,13 +74,6 @@ public unsafe struct ResourceHandle
|
|||
[FieldOffset(0xAC)]
|
||||
public uint RefCount;
|
||||
|
||||
// May return null.
|
||||
public static byte* GetData(ResourceHandle* handle)
|
||||
=> ((delegate* unmanaged< ResourceHandle*, byte* >)handle->VTable[Offsets.ResourceHandleGetDataVfunc])(handle);
|
||||
|
||||
public static ulong GetLength(ResourceHandle* handle)
|
||||
=> ((delegate* unmanaged< ResourceHandle*, ulong >)handle->VTable[Offsets.ResourceHandleGetLengthVfunc])(handle);
|
||||
|
||||
|
||||
// Only use these if you know what you are doing.
|
||||
// Those are actually only sure to be accessible for DefaultResourceHandles.
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
public static class ShaderPackageUtility
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0xC)]
|
||||
public unsafe struct Sampler
|
||||
{
|
||||
[FieldOffset(0x0)]
|
||||
public uint Crc;
|
||||
|
||||
[FieldOffset(0x4)]
|
||||
public uint Id;
|
||||
|
||||
[FieldOffset(0xA)]
|
||||
public ushort Slot;
|
||||
}
|
||||
}
|
||||
24
Penumbra/Interop/Structs/StructExtensions.cs
Normal file
24
Penumbra/Interop/Structs/StructExtensions.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using FFXIVClientStructs.STD;
|
||||
using Penumbra.String;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
|
||||
namespace Penumbra.Interop.Structs;
|
||||
|
||||
public unsafe class TextureUtility
|
||||
{
|
||||
public TextureUtility(IGameInteropProvider interop)
|
||||
=> interop.InitializeFromAttributes(this);
|
||||
|
||||
|
||||
[Signature("E8 ?? ?? ?? ?? 8B 0F 48 8D 54 24")]
|
||||
private static nint _textureCreate2D = nint.Zero;
|
||||
|
||||
[Signature("E9 ?? ?? ?? ?? 8B 02 25")]
|
||||
private static nint _textureInitializeContents = nint.Zero;
|
||||
|
||||
public static Texture* Create2D(Device* device, int* size, byte mipLevel, uint textureFormat, uint flags, uint unk)
|
||||
=> ((delegate* unmanaged<Device*, int*, byte, uint, uint, uint, Texture*>)_textureCreate2D)(device, size, mipLevel, textureFormat,
|
||||
flags, unk);
|
||||
|
||||
public static bool InitializeContents(Texture* texture, void* contents)
|
||||
=> ((delegate* unmanaged<Texture*, void*, bool>)_textureInitializeContents)(texture, contents);
|
||||
|
||||
public static void IncRef(Texture* texture)
|
||||
=> ((delegate* unmanaged<Texture*, void>)(*(void***)texture)[2])(texture);
|
||||
|
||||
public static void DecRef(Texture* texture)
|
||||
=> ((delegate* unmanaged<Texture*, void>)(*(void***)texture)[3])(texture);
|
||||
}
|
||||
|
|
@ -75,7 +75,6 @@ public class Penumbra : IDalamudPlugin
|
|||
_communicatorService = _services.GetRequiredService<CommunicatorService>();
|
||||
_services.GetRequiredService<ResourceService>(); // Initialize because not required anywhere else.
|
||||
_services.GetRequiredService<ModCacheManager>(); // Initialize because not required anywhere else.
|
||||
_services.GetRequiredService<TextureUtility>(); // Initialize because not required anywhere else.
|
||||
_collectionManager.Caches.CreateNecessaryCaches();
|
||||
using (var t = _services.GetRequiredService<StartTracker>().Measure(StartTimeType.PathResolver))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -90,8 +90,7 @@ public static class ServiceManager
|
|||
.AddSingleton<CreateFileWHook>()
|
||||
.AddSingleton<ResidentResourceManager>()
|
||||
.AddSingleton<FontReloader>()
|
||||
.AddSingleton<RedrawService>()
|
||||
.AddSingleton<TextureUtility>();
|
||||
.AddSingleton<RedrawService>();
|
||||
|
||||
private static IServiceCollection AddConfiguration(this IServiceCollection services)
|
||||
=> services.AddTransient<ConfigMigrationService>()
|
||||
|
|
|
|||
|
|
@ -669,8 +669,8 @@ public class DebugTab : Window, ITab
|
|||
|
||||
UiHelpers.Text(resource);
|
||||
ImGui.TableNextColumn();
|
||||
var data = (nint)ResourceHandle.GetData(resource);
|
||||
var length = ResourceHandle.GetLength(resource);
|
||||
var data = (nint)resource->CsHandle.GetData();
|
||||
var length = resource->CsHandle.GetLength();
|
||||
if (ImGui.Selectable($"0x{data:X}"))
|
||||
if (data != nint.Zero && length > 0)
|
||||
ImGui.SetClipboardText(string.Join("\n",
|
||||
|
|
|
|||
|
|
@ -99,10 +99,10 @@ public class ResourceTab : ITab
|
|||
UiHelpers.Text(resource);
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
var data = Interop.Structs.ResourceHandle.GetData(resource);
|
||||
var data = resource->CsHandle.GetData();
|
||||
if (data != null)
|
||||
{
|
||||
var length = (int)Interop.Structs.ResourceHandle.GetLength(resource);
|
||||
var length = (int)resource->CsHandle.GetLength();
|
||||
ImGui.SetClipboardText(string.Join(" ",
|
||||
new ReadOnlySpan<byte>(data, length).ToArray().Select(b => b.ToString("X2"))));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,18 @@ public static class UiHelpers
|
|||
public static unsafe void Text(byte* s, int length)
|
||||
=> ImGuiNative.igTextUnformatted(s, s + length);
|
||||
|
||||
/// <summary> Draw text given by a byte span. </summary>
|
||||
public static unsafe void Text(ReadOnlySpan<byte> s)
|
||||
{
|
||||
fixed (byte* pS = s)
|
||||
{
|
||||
Text(pS, s.Length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Draw the name of a resource file. </summary>
|
||||
public static unsafe void Text(ResourceHandle* resource)
|
||||
=> Text(resource->FileName().Path, resource->FileNameLength);
|
||||
=> Text(resource->CsHandle.FileName.AsSpan());
|
||||
|
||||
/// <summary> Draw a ByteString as a selectable. </summary>
|
||||
public static unsafe bool Selectable(ByteString s, bool selected)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue