From deb3686df5cf1f30365d70b3a2f382863136e953 Mon Sep 17 00:00:00 2001 From: Actions User Date: Fri, 19 Dec 2025 00:12:44 +0000 Subject: [PATCH 1/9] [CI] Updating repo.json for 1.5.1.9 --- repo.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/repo.json b/repo.json index 5b780560..611de678 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.8", - "TestingAssemblyVersion": "1.5.1.8", + "AssemblyVersion": "1.5.1.9", + "TestingAssemblyVersion": "1.5.1.9", "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.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", + "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.9/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.9/Penumbra.zip", + "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.9/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } ] From 9cf7030f87142f6ae446b64601f56f9e849e67ca Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 19 Dec 2025 01:13:02 +0100 Subject: [PATCH 2/9] ... --- .github/workflows/test_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_release.yml b/.github/workflows/test_release.yml index 90a8b176..c6b4e459 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 From eff3784a85c6fb498ba7f9655d6b9d26b524953e Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 20 Dec 2025 15:34:08 +0100 Subject: [PATCH 3/9] Fix multi-release bug in texturearrayslicer. --- Penumbra/Interop/Services/TextureArraySlicer.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Penumbra/Interop/Services/TextureArraySlicer.cs b/Penumbra/Interop/Services/TextureArraySlicer.cs index 3cd57a33..a3db4d04 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 == null) + if (texture is null) throw new ArgumentNullException(nameof(texture)); if (sliceIndex >= texture->ArraySize) throw new ArgumentOutOfRangeException(nameof(sliceIndex), @@ -74,9 +74,6 @@ 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); From 9aa566f521d0375959ceeffee2e9fcbce660c999 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 20 Dec 2025 15:34:50 +0100 Subject: [PATCH 4/9] Fix typo in new IPC providers. --- Penumbra.Api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Penumbra.Api b/Penumbra.Api index 1750c41b..52a3216a 160000 --- a/Penumbra.Api +++ b/Penumbra.Api @@ -1 +1 @@ -Subproject commit 1750c41b53e1000c99a7fb9d8a0f082aef639a41 +Subproject commit 52a3216a525592205198303df2844435e382cf87 From 069323cfb8220b893df878b5067ee9d87656ab9a Mon Sep 17 00:00:00 2001 From: Actions User Date: Sat, 20 Dec 2025 14:38:27 +0000 Subject: [PATCH 5/9] [CI] Updating repo.json for 1.5.1.11 --- repo.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/repo.json b/repo.json index 611de678..f337e8ff 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.9", - "TestingAssemblyVersion": "1.5.1.9", + "AssemblyVersion": "1.5.1.11", + "TestingAssemblyVersion": "1.5.1.11", "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.9/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.9/Penumbra.zip", - "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.9/Penumbra.zip", + "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.11/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.11/Penumbra.zip", + "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.11/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } ] From 73f02851a64e2a0ea9447173a7981d098a38bac1 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 20 Dec 2025 21:51:34 +0100 Subject: [PATCH 6/9] Cherry pick API support for other block compression types from Luna branch. --- Penumbra/Api/Api/EditingApi.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Penumbra/Api/Api/EditingApi.cs b/Penumbra/Api/Api/EditingApi.cs index e50b7a1b..5a1fc347 100644 --- a/Penumbra/Api/Api/EditingApi.cs +++ b/Penumbra/Api/Api/EditingApi.cs @@ -19,6 +19,12 @@ 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}.")), }; @@ -36,6 +42,12 @@ 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 From 6ba735eefba180538190842973604e8b0a592d0d Mon Sep 17 00:00:00 2001 From: Actions User Date: Sat, 20 Dec 2025 20:53:36 +0000 Subject: [PATCH 7/9] [CI] Updating repo.json for 1.5.1.12 --- repo.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/repo.json b/repo.json index f337e8ff..583e5e52 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.11", - "TestingAssemblyVersion": "1.5.1.11", + "AssemblyVersion": "1.5.1.12", + "TestingAssemblyVersion": "1.5.1.12", "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.11/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.11/Penumbra.zip", - "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.11/Penumbra.zip", + "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.12/Penumbra.zip", + "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.12/Penumbra.zip", + "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.12/Penumbra.zip", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } ] From 13500264b7f046cacbddae41df704089be7e7908 Mon Sep 17 00:00:00 2001 From: Marc-Aurel Zent Date: Mon, 22 Dec 2025 14:41:32 +0100 Subject: [PATCH 8/9] Use iced to create AsmHooks in PapRewriter. --- .../Hooks/ResourceLoading/PapRewriter.cs | 85 ++++++++++++------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs b/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs index caf43d08..ff794d81 100644 --- a/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs +++ b/Penumbra/Interop/Hooks/ResourceLoading/PapRewriter.cs @@ -1,6 +1,7 @@ using System.Text.Unicode; using Dalamud.Hooking; using Iced.Intel; +using static Iced.Intel.AssemblerRegisters; using OtterGui.Extensions; using Penumbra.String.Classes; using Swan; @@ -46,36 +47,32 @@ public sealed class PapRewriter(PeSigScanner sigScanner, PapRewriter.PapResource stackAccesses.RemoveAll(instr => instr.IP == hp.IP); var detourPointer = Marshal.GetFunctionPointerForDelegate(papResourceHandler); - var targetRegister = hookPoint.Op0Register.ToString().ToLower(); + var targetRegister = GetRegister64(hookPoint.Op0Register); var hookAddress = new IntPtr((long)detourPoint.IP); var caveAllocation = NativeAllocCave(16); - var hook = new AsmHook( - hookAddress, - [ - "use64", - $"mov {targetRegister}, 0x{stringAllocation:x8}", // Move our char *path into the relevant register (rdx) + var assembler = new Assembler(64); + assembler.mov(targetRegister, stringAllocation); // 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 - $"mov r9, 0x{caveAllocation:x8}", - "mov [r9], rcx", - "mov [r9+0x8], 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); - // 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 + // 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); - // Do the reverse process and retrieve the stored stuff - $"mov r9, 0x{caveAllocation:x8}", - "mov rcx, [r9]", - "mov rdx, [r9+0x8]", + // 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]); - // 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" - ); + // 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"); _hooks.Add(hookAddress, hook); hook.Enable(); @@ -95,19 +92,45 @@ public sealed class PapRewriter(PeSigScanner sigScanner, PapRewriter.PapResource if (_hooks.ContainsKey(hookAddress)) continue; - var targetRegister = stackAccess.Op0Register.ToString().ToLower(); - var hook = new AsmHook( - hookAddress, - [ - "use64", - $"mov {targetRegister}, 0x{stringAllocation:x8}", - ], $"{name}.PapStackAccess[{index}]" - ); + var targetRegister = GetRegister64(stackAccess.Op0Register); + var assembler = new Assembler(64); + assembler.mov(targetRegister, stringAllocation); + var hook = new AsmHook(hookAddress, AssembleToBytes(assembler), $"{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) { From eec8ee709411f18704b95b543fb4966b525b0428 Mon Sep 17 00:00:00 2001 From: Actions User Date: Tue, 27 Jan 2026 15:30:23 +0000 Subject: [PATCH 9/9] [CI] Updating repo.json for 1.5.1.13 --- repo.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/repo.json b/repo.json index 583e5e52..22a682ee 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.12", - "TestingAssemblyVersion": "1.5.1.12", + "AssemblyVersion": "1.5.1.13", + "TestingAssemblyVersion": "1.5.1.13", "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.12/Penumbra.zip", - "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.12/Penumbra.zip", - "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.5.1.12/Penumbra.zip", + "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", "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" } ]