diff --git a/.github/workflows/test_release.yml b/.github/workflows/test_release.yml index c6b4e459..90a8b176 100644 --- a/.github/workflows/test_release.yml +++ b/.github/workflows/test_release.yml @@ -9,7 +9,7 @@ jobs: build: runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v5 with: submodules: recursive - name: Setup .NET diff --git a/Penumbra.Api b/Penumbra.Api index 52a3216a..1750c41b 160000 --- a/Penumbra.Api +++ b/Penumbra.Api @@ -1 +1 @@ -Subproject commit 52a3216a525592205198303df2844435e382cf87 +Subproject commit 1750c41b53e1000c99a7fb9d8a0f082aef639a41 diff --git a/Penumbra/Api/Api/EditingApi.cs b/Penumbra/Api/Api/EditingApi.cs index 5a1fc347..e50b7a1b 100644 --- a/Penumbra/Api/Api/EditingApi.cs +++ b/Penumbra/Api/Api/EditingApi.cs @@ -19,12 +19,6 @@ public class EditingApi(TextureManager textureManager) : IPenumbraApiEditing, IA TextureType.Bc3Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC3, mipMaps, false, inputFile, outputFile), TextureType.Bc7Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC7, mipMaps, true, inputFile, outputFile), TextureType.Bc7Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC7, mipMaps, false, inputFile, outputFile), - TextureType.Bc1Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC1, mipMaps, true, inputFile, outputFile), - TextureType.Bc1Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC1, mipMaps, false, inputFile, outputFile), - TextureType.Bc4Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC4, mipMaps, true, inputFile, outputFile), - TextureType.Bc4Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC4, mipMaps, false, inputFile, outputFile), - TextureType.Bc5Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC5, mipMaps, true, inputFile, outputFile), - TextureType.Bc5Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC5, mipMaps, false, inputFile, outputFile), _ => Task.FromException(new Exception($"Invalid input value {textureType}.")), }; @@ -42,12 +36,6 @@ public class EditingApi(TextureManager textureManager) : IPenumbraApiEditing, IA TextureType.Bc3Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC3, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), TextureType.Bc7Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC7, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), TextureType.Bc7Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC7, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), - TextureType.Bc1Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC1, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), - TextureType.Bc1Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC1, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), - TextureType.Bc4Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC4, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), - TextureType.Bc4Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC4, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), - TextureType.Bc5Tex => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC5, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), - TextureType.Bc5Dds => textureManager.SaveAs(CombinedTexture.TextureSaveType.BC5, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), _ => Task.FromException(new Exception($"Invalid input value {textureType}.")), }; // @formatter:on diff --git a/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs b/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs index ff794d81..caf43d08 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs @@ -1,7 +1,6 @@ using System.Text.Unicode; using Dalamud.Hooking; using Iced.Intel; -using static Iced.Intel.AssemblerRegisters; using OtterGui.Extensions; using Penumbra.String.Classes; using Swan; @@ -47,32 +46,36 @@ public sealed class PapRewriter(PeSigScanner sigScanner, PapRewriter.PapResource stackAccesses.RemoveAll(instr => instr.IP == hp.IP); var detourPointer = Marshal.GetFunctionPointerForDelegate(papResourceHandler); - var targetRegister = GetRegister64(hookPoint.Op0Register); + var targetRegister = hookPoint.Op0Register.ToString().ToLower(); var hookAddress = new IntPtr((long)detourPoint.IP); var caveAllocation = NativeAllocCave(16); - var assembler = new Assembler(64); - assembler.mov(targetRegister, stringAllocation); // Move our char *path into the relevant register (rdx) + var hook = new AsmHook( + hookAddress, + [ + "use64", + $"mov {targetRegister}, 0x{stringAllocation:x8}", // Move our char *path into the relevant register (rdx) - // After this asm stub, we have a call to Crc32(); since r9 is a volatile, unused register, we can use it ourselves - // We're essentially storing the original 2 arguments ('this', 'path'), in case they get mangled in our call - // We technically don't need to save rdx ('path'), since it'll be stringLoc, but eh - assembler.mov(r9, caveAllocation); - assembler.mov(__qword_ptr[r9], rcx); - assembler.mov(__qword_ptr[r9 + 8], rdx); + // After this asm stub, we have a call to Crc32(); since r9 is a volatile, unused register, we can use it ourselves + // We're essentially storing the original 2 arguments ('this', 'path'), in case they get mangled in our call + // We technically don't need to save rdx ('path'), since it'll be stringLoc, but eh + $"mov r9, 0x{caveAllocation:x8}", + "mov [r9], rcx", + "mov [r9+0x8], rdx", - // We can use 'rax' here too since it's also volatile, and it'll be overwritten by Crc32()'s return anyway - assembler.mov(rax, detourPointer); - assembler.call(rax); + // We can use 'rax' here too since it's also volatile, and it'll be overwritten by Crc32()'s return anyway + $"mov rax, 0x{detourPointer:x8}", // Get a pointer to our detour in place + "call rax", // Call detour - // Do the reverse process and retrieve the stored stuff - assembler.mov(r9, caveAllocation); - assembler.mov(rcx, __qword_ptr[r9]); - assembler.mov(rdx, __qword_ptr[r9 + 8]); + // Do the reverse process and retrieve the stored stuff + $"mov r9, 0x{caveAllocation:x8}", + "mov rcx, [r9]", + "mov rdx, [r9+0x8]", - // Plop 'rax' (our return value, the path size) into r8, so it's the third argument for the subsequent Crc32() call - assembler.mov(r8, rax); - var hook = new AsmHook(hookAddress, AssembleToBytes(assembler), $"{name}.PapRedirection"); + // Plop 'rax' (our return value, the path size) into r8, so it's the third argument for the subsequent Crc32() call + "mov r8, rax", + ], $"{name}.PapRedirection" + ); _hooks.Add(hookAddress, hook); hook.Enable(); @@ -92,45 +95,19 @@ public sealed class PapRewriter(PeSigScanner sigScanner, PapRewriter.PapResource if (_hooks.ContainsKey(hookAddress)) continue; - var targetRegister = GetRegister64(stackAccess.Op0Register); - var assembler = new Assembler(64); - assembler.mov(targetRegister, stringAllocation); - var hook = new AsmHook(hookAddress, AssembleToBytes(assembler), $"{name}.PapStackAccess[{index}]"); + var targetRegister = stackAccess.Op0Register.ToString().ToLower(); + var hook = new AsmHook( + hookAddress, + [ + "use64", + $"mov {targetRegister}, 0x{stringAllocation:x8}", + ], $"{name}.PapStackAccess[{index}]" + ); _hooks.Add(hookAddress, hook); hook.Enable(); } } - - private static AssemblerRegister64 GetRegister64(Register reg) - => reg switch - { - Register.RAX => rax, - Register.RCX => rcx, - Register.RDX => rdx, - Register.RBX => rbx, - Register.RSP => rsp, - Register.RBP => rbp, - Register.RSI => rsi, - Register.RDI => rdi, - Register.R8 => r8, - Register.R9 => r9, - Register.R10 => r10, - Register.R11 => r11, - Register.R12 => r12, - Register.R13 => r13, - Register.R14 => r14, - Register.R15 => r15, - _ => throw new ArgumentOutOfRangeException(nameof(reg), reg, "Unsupported register."), - }; - - private static byte[] AssembleToBytes(Assembler assembler) - { - using var stream = new MemoryStream(); - var writer = new StreamCodeWriter(stream); - assembler.Assemble(writer, 0); - return stream.ToArray(); - } private static IEnumerable ScanStackAccesses(IEnumerable instructions, Instruction hookPoint) { diff --git a/Penumbra/Interop/Services/TextureArraySlicer.cs b/Penumbra/Interop/Services/TextureArraySlicer.cs index a3db4d04..3cd57a33 100644 --- a/Penumbra/Interop/Services/TextureArraySlicer.cs +++ b/Penumbra/Interop/Services/TextureArraySlicer.cs @@ -18,7 +18,7 @@ public sealed unsafe class TextureArraySlicer : IUiService, IDisposable /// Caching this across frames will cause a crash to desktop. public ImTextureID GetImGuiHandle(Texture* texture, byte sliceIndex) { - if (texture is null) + if (texture == null) throw new ArgumentNullException(nameof(texture)); if (sliceIndex >= texture->ArraySize) throw new ArgumentOutOfRangeException(nameof(sliceIndex), @@ -74,6 +74,9 @@ public sealed unsafe class TextureArraySlicer : IUiService, IDisposable { ID3D11ShaderResourceView* slicedSrv = null; Marshal.ThrowExceptionForHR(device->CreateShaderResourceView(resource, &description, &slicedSrv)); + resource->Release(); + device->Release(); + state = new SliceState(slicedSrv); _activeSlices.Add(((nint)texture, sliceIndex), state); return new ImTextureID((nint)state.ShaderResourceView); diff --git a/repo.json b/repo.json index 22a682ee..5b780560 100644 --- a/repo.json +++ b/repo.json @@ -5,8 +5,8 @@ "Punchline": "Runtime mod loader and manager.", "Description": "Runtime mod loader and manager.", "InternalName": "Penumbra", - "AssemblyVersion": "1.5.1.13", - "TestingAssemblyVersion": "1.5.1.13", + "AssemblyVersion": "1.5.1.8", + "TestingAssemblyVersion": "1.5.1.8", "RepoUrl": "https://github.com/xivdev/Penumbra", "ApplicableVersion": "any", "DalamudApiLevel": 14, @@ -18,9 +18,9 @@ "LoadPriority": 69420, "LoadRequiredState": 2, "LoadSync": true, - "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.13/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.13/Penumbra.zip", - "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.13/Penumbra.zip", + "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.8/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.8/Penumbra.zip", + "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.8/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } ]