diff --git a/OtterGui b/OtterGui index a4f9b285..6f17ef70 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit a4f9b285c82f84ff0841695c0787dbba93afc59b +Subproject commit 6f17ef70c41f3b31a401fdc9d6e37087e64f2035 diff --git a/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs b/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs index bacc72fa..0b7bafe0 100644 --- a/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs +++ b/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs @@ -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; diff --git a/Penumbra/Interop/MaterialPreview/LiveMaterialPreviewer.cs b/Penumbra/Interop/MaterialPreview/LiveMaterialPreviewer.cs index fa03ac49..972d81be 100644 --- a/Penumbra/Interop/MaterialPreview/LiveMaterialPreviewer.cs +++ b/Penumbra/Interop/MaterialPreview/LiveMaterialPreviewer.cs @@ -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 value) diff --git a/Penumbra/Interop/MaterialPreview/MaterialInfo.cs b/Penumbra/Interop/MaterialPreview/MaterialInfo.cs index c64e4d0b..ec0ddd29 100644 --- a/Penumbra/Interop/MaterialPreview/MaterialInfo.cs +++ b/Penumbra/Interop/MaterialPreview/MaterialInfo.cs @@ -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)); } diff --git a/Penumbra/Interop/ResourceTree/ResolveContext.cs b/Penumbra/Interop/ResourceTree/ResolveContext.cs index 55893cab..5e3970cc 100644 --- a/Penumbra/Interop/ResourceTree/ResolveContext.cs +++ b/Penumbra/Interop/ResourceTree/ResolveContext.cs @@ -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 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(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(); - 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(); } } diff --git a/Penumbra/Interop/ResourceTree/ResourceTree.cs b/Penumbra/Interop/ResourceTree/ResourceTree.cs index bc2cca26..53e7db35 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTree.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTree.cs @@ -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(&character->DrawData.Head, 10); // var customize = new ReadOnlySpan( 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(); @@ -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) diff --git a/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs b/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs index df97371b..fd020804 100644 --- a/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs +++ b/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs @@ -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; } diff --git a/Penumbra/Interop/Services/SkinFixer.cs b/Penumbra/Interop/Services/SkinFixer.cs index be5b778e..d25a5638 100644 --- a/Penumbra/Interop/Services/SkinFixer.cs +++ b/Penumbra/Interop/Services/SkinFixer.cs @@ -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 diff --git a/Penumbra/Interop/Structs/CharacterBaseExt.cs b/Penumbra/Interop/Structs/CharacterBaseExt.cs deleted file mode 100644 index 53fda2cd..00000000 --- a/Penumbra/Interop/Structs/CharacterBaseExt.cs +++ /dev/null @@ -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; -} diff --git a/Penumbra/Interop/Structs/ConstantBuffer.cs b/Penumbra/Interop/Structs/ConstantBuffer.cs deleted file mode 100644 index d61aaeea..00000000 --- a/Penumbra/Interop/Structs/ConstantBuffer.cs +++ /dev/null @@ -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 buffer) - { - if ((Flags & 0x4003) == 0 && _maybeSourcePointer != null) - { - buffer = new Span(_maybeSourcePointer, Size >> 2); - return true; - } - else - { - buffer = null; - return false; - } - } -} diff --git a/Penumbra/Interop/Structs/HumanExt.cs b/Penumbra/Interop/Structs/HumanExt.cs deleted file mode 100644 index 274b4fb2..00000000 --- a/Penumbra/Interop/Structs/HumanExt.cs +++ /dev/null @@ -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; -} diff --git a/Penumbra/Interop/Structs/Material.cs b/Penumbra/Interop/Structs/Material.cs deleted file mode 100644 index f7c8679e..00000000 --- a/Penumbra/Interop/Structs/Material.cs +++ /dev/null @@ -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 TextureSpan - => new(Textures, TextureCount); -} diff --git a/Penumbra/Interop/Structs/MtrlResource.cs b/Penumbra/Interop/Structs/MtrlResource.cs deleted file mode 100644 index c3b86e14..00000000 --- a/Penumbra/Interop/Structs/MtrlResource.cs +++ /dev/null @@ -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; - } -} diff --git a/Penumbra/Interop/Structs/RenderModel.cs b/Penumbra/Interop/Structs/RenderModel.cs index f9cb2d56..86b09e8d 100644 --- a/Penumbra/Interop/Structs/RenderModel.cs +++ b/Penumbra/Interop/Structs/RenderModel.cs @@ -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; diff --git a/Penumbra/Interop/Structs/ResourceHandle.cs b/Penumbra/Interop/Structs/ResourceHandle.cs index 3cceb949..382368b4 100644 --- a/Penumbra/Interop/Structs/ResourceHandle.cs +++ b/Penumbra/Interop/Structs/ResourceHandle.cs @@ -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 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. diff --git a/Penumbra/Interop/Structs/ShaderPackageUtility.cs b/Penumbra/Interop/Structs/ShaderPackageUtility.cs deleted file mode 100644 index 9f7ec1f5..00000000 --- a/Penumbra/Interop/Structs/ShaderPackageUtility.cs +++ /dev/null @@ -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; - } -} diff --git a/Penumbra/Interop/Structs/StructExtensions.cs b/Penumbra/Interop/Structs/StructExtensions.cs new file mode 100644 index 00000000..d1a38ae4 --- /dev/null +++ b/Penumbra/Interop/Structs/StructExtensions.cs @@ -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 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); +} diff --git a/Penumbra/Interop/Structs/TextureUtility.cs b/Penumbra/Interop/Structs/TextureUtility.cs deleted file mode 100644 index eeea4c33..00000000 --- a/Penumbra/Interop/Structs/TextureUtility.cs +++ /dev/null @@ -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)_textureCreate2D)(device, size, mipLevel, textureFormat, - flags, unk); - - public static bool InitializeContents(Texture* texture, void* contents) - => ((delegate* unmanaged)_textureInitializeContents)(texture, contents); - - public static void IncRef(Texture* texture) - => ((delegate* unmanaged)(*(void***)texture)[2])(texture); - - public static void DecRef(Texture* texture) - => ((delegate* unmanaged)(*(void***)texture)[3])(texture); -} diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 73d1013e..ce1bdae5 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -75,7 +75,6 @@ public class Penumbra : IDalamudPlugin _communicatorService = _services.GetRequiredService(); _services.GetRequiredService(); // Initialize because not required anywhere else. _services.GetRequiredService(); // Initialize because not required anywhere else. - _services.GetRequiredService(); // Initialize because not required anywhere else. _collectionManager.Caches.CreateNecessaryCaches(); using (var t = _services.GetRequiredService().Measure(StartTimeType.PathResolver)) { diff --git a/Penumbra/Services/ServiceManager.cs b/Penumbra/Services/ServiceManager.cs index 84f89f6d..6a522ca2 100644 --- a/Penumbra/Services/ServiceManager.cs +++ b/Penumbra/Services/ServiceManager.cs @@ -90,8 +90,7 @@ public static class ServiceManager .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() - .AddSingleton(); + .AddSingleton(); private static IServiceCollection AddConfiguration(this IServiceCollection services) => services.AddTransient() diff --git a/Penumbra/UI/Tabs/DebugTab.cs b/Penumbra/UI/Tabs/DebugTab.cs index 5abb3c2f..1c5f7946 100644 --- a/Penumbra/UI/Tabs/DebugTab.cs +++ b/Penumbra/UI/Tabs/DebugTab.cs @@ -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", diff --git a/Penumbra/UI/Tabs/ResourceTab.cs b/Penumbra/UI/Tabs/ResourceTab.cs index 020493d1..6f3dec30 100644 --- a/Penumbra/UI/Tabs/ResourceTab.cs +++ b/Penumbra/UI/Tabs/ResourceTab.cs @@ -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(data, length).ToArray().Select(b => b.ToString("X2")))); } diff --git a/Penumbra/UI/UiHelpers.cs b/Penumbra/UI/UiHelpers.cs index 6c64bd55..8fbce6d0 100644 --- a/Penumbra/UI/UiHelpers.cs +++ b/Penumbra/UI/UiHelpers.cs @@ -19,9 +19,18 @@ public static class UiHelpers public static unsafe void Text(byte* s, int length) => ImGuiNative.igTextUnformatted(s, s + length); + /// Draw text given by a byte span. + public static unsafe void Text(ReadOnlySpan s) + { + fixed (byte* pS = s) + { + Text(pS, s.Length); + } + } + /// Draw the name of a resource file. public static unsafe void Text(ResourceHandle* resource) - => Text(resource->FileName().Path, resource->FileNameLength); + => Text(resource->CsHandle.FileName.AsSpan()); /// Draw a ByteString as a selectable. public static unsafe bool Selectable(ByteString s, bool selected)