From c1b07f9d98a79e3da977bef4ec2ee9a9a6930e8a Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 May 2024 20:51:03 +0300 Subject: [PATCH 1/6] AsmResolver comeback --- .github/workflows/publish.yml | 61 +------ build/gpu.csx | 295 ++++------------------------------ 2 files changed, 30 insertions(+), 326 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4893f6d..5edfd5f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -76,7 +76,7 @@ jobs: gpu-hint: name: Add GPU Hints needs: [build] - runs-on: windows-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -95,68 +95,13 @@ jobs: - name: Add Dedicated GPU Hint run: | - echo "Downloading ILAsm"; - Invoke-WebRequest https://globalcdn.nuget.org/packages/runtime.win-x64.microsoft.netcore.ilasm.8.0.0.nupkg -OutFile ilasm.nupkg; - Invoke-WebRequest https://globalcdn.nuget.org/packages/runtime.win-x64.microsoft.netcore.ildasm.8.0.0.nupkg -OutFile ildasm.nupkg; - echo "Extracting ILAsm"; - Expand-Archive ilasm.nupkg -d tools/ilasm; - Expand-Archive ildasm.nupkg -d tools/ildasm; - #echo "chmod ILAsm"; - #chmod +x tools/ilasm/runtimes/linux-x64/native/ilasm; - #chmod +x tools/ildasm/runtimes/linux-x64/native/ildasm; - - # So what is happening here? - # We're not able to export global variables from C# - # But ILAsm is able to do it - # So we compile our .exe files from C# - # Then we decompile them with ILDasm - # Then we compile them back to .exe with ILAsm and with the .il file for exporting the global variable - # Then we set the icon back because ILAsm doesn't support setting the icon - - $workingDir = "$PWD"; - mkdir tmp; - - cd build/set-icon; - yarn install; - cd $workingDir; - + dotnet tool install -g dotnet-script; $fileNames = Get-ChildItem -Path "bannerlord/" -Recurse -Include *.exe; foreach ($f in $fileNames) { - cd $workingDir/tmp; - echo $f.FullName; - - $runtime = ""; - If ($f.FullName.Contains("Win64_Shipping_Client")) { - $runtime = "Win64_Shipping_Client"; - } - If ($f.FullName.Contains("Gaming.Desktop.x64_Shipping_Client")) { - $runtime = "Gaming.Desktop.x64_Shipping_Client"; - } - - $fileDirname = $f.DirectoryName; - $dirname = [System.IO.Path]::GetFileNameWithoutExtension($f.FullName); - New-Item -ItemType Directory -Path $dirname/$runtime -Force - cd $dirname/$runtime; - - # Decompile to IL Code - & "$workingDir/tools/ildasm/runtimes/win-x64/native/ildasm.exe" "$f" /OUT=Code.il - #& "$workingDir/tools/ildasm/runtimes/linux-x64/native/ildasm" "$f" -OUT="Code.il" - Copy-Item -Path $workingDir/build/ForceDedicatedGraphicCard.il -Destination ForceDedicatedGraphicCard.il; - - # Recompile to .exe - & "$workingDir/tools/ilasm/runtimes/win-x64/native/ilasm.exe" -QUIET -NOLOGO -OPTIMIZE -EXE /X64 -OUTPUT="$dirname.exe" Code.il ForceDedicatedGraphicCard.il - #& "$workingDir/tools/ilasm/runtimes/linux-x64/native/ilasm" -QUIET -NOLOGO -OPTIMIZE -EXE -X64 -OUTPUT="$dirname.exe" Code.il ForceDedicatedGraphicCard.il - - # Set Icon - cd $workingDir/build/set-icon; - node index.js "$workingDir/tmp/$dirname/$runtime/$dirname.exe" "$workingDir/resources/BLSE_SMALL.ico"; - - Copy-Item -Path "$workingDir/tmp/$dirname/$runtime/$dirname.exe" -Destination "$fileDirname/$dirname.exe" -force + dotnet script build/gpu.csx -- "$f"; } - cd $workingDir; - rmdir tmp -Recurse -Force; shell: pwsh - name: Upload Bannerlord folder diff --git a/build/gpu.csx b/build/gpu.csx index a75fedd..a289c54 100644 --- a/build/gpu.csx +++ b/build/gpu.csx @@ -1,279 +1,38 @@ -#r "nuget: PE-Sharp, 1.0.0" +#r "nuget: AsmResolver.DotNet, 5.5.1" -using System.Collections.Generic; -using PE_Sharp.PEStatic; -using PE_Sharp.Exceptions; -using PE_Sharp.PEFormat; -using System.Reflection; -using System.Linq; -using System.IO; -using System; +var image = PEImage.FromFile(Args[0]); -class Program -{ - private static readonly string ExePath = AppDomain.CurrentDomain.BaseDirectory, ConfigPath = ExePath + "/config"; - - private const string SectionName = ".patchPE";//.nvpatch +// Force mixed-mode. +image.DotNetDirectory!.Flags &= ~DotNetDirectoryFlags.ILOnly; - private static readonly ExportSymbol[] GpuSymbols = { - new("NvOptimusEnablement"), - new("AmdPowerXpressRequestHighPerformance") - }; +// Define new file segments that will hold the data. +var nvOptimusEnablement = new DataSegment(BitConverter.GetBytes(1)); +var amdPowerXpressRequestHighPerformance = new DataSegment(BitConverter.GetBytes(1)); - public static unsafe int Main(IList args2) +// Define exports pointing to the new symbols added to the section. +image.Exports = new ExportDirectory(Path.GetFileName(inputPath)) +{ + Entries = { - var args = args2.ToArray(); - - // Local vars - List exportSymbols = new(); - var inFile = string.Empty; - var statusMode = false; - var enableGpuMode = false; - var disableGpuMode = false; - var enableMode = false; - var disableMode = false; - var quietYesMode = false; - var quietNoMode = false; - - // Work out input/output file names - if (args.Length == 0) - { - ShowLogo(); - Console.WriteLine("type '--help' or '/help' to get help"); - return 0; - } - - if (args.Length >= 1) - { - if (PEUtils.IsSwitch(args[0], out var name, out var value)) - { - switch (name) - { - case "enable-gpu": - enableGpuMode = true; - break; - case "disable-gpu": - disableGpuMode = true; - break; - case "enable": - enableMode = true; - break; - case "disable": - disableMode = true; - break; - case "status": - statusMode = true; - break; - case "quiet-yes": - quietYesMode = true; - break; - case "quiet-no": - quietNoMode = true; - break; - case "help": - ShowLogo(); - ShowHelp(); - return 0; - case "version": - ShowLogo(); - return 0; - } - - if (name != "version" && name != "help" && !quietNoMode && !quietYesMode && args.Length == 1) - { - var exc = "only '--version' '--help' --'quite-no' "; - exc += "'--quite-yes' have one options"; - throw new ArgException(exc); - } - } - else - { - var exc = $"don´t exist this option '{args[0]}'"; - throw new ArgException(exc); - } - } - if (args.Length >= 2) - { - if (!enableMode && !disableMode && !statusMode - && !enableGpuMode && !disableGpuMode) - { - var exc = "only '--enableMode' '--disableMode' '--enableGpuMode' "; - exc += "'--disableGpuMode' '--statusMode' have two or more options"; - throw new ArgException(exc); - } - - Console.WriteLine("DEU BOM 01"); //AAAAAAH - inFile = args[1]; - if (enableGpuMode || disableGpuMode || statusMode) - exportSymbols.AddRange(GpuSymbols); - else if ((enableMode || disableMode) && args.Length == 2) - throw new ArgException("'--enableMode' '--disableMode' need more than three options"); - - } - if (args.Length >= 3) - { - if (enableMode || disableMode) - { - var expArgs = args[2..]; - foreach (var exp in expArgs) - exportSymbols.Add(new(exp)); - } - else - { - var exc = "only '--enableMode' '--disableMode' have more than three options"; - throw new ArgException(exc); - } - } - - if (enableGpuMode) enableMode = true; - if (disableGpuMode) disableMode = true; - - // config file - var quietMode = false; - if (File.Exists(ConfigPath)) - { - var options = File.ReadAllBytes(ConfigPath); - if (options.Length > 0) - { - if (options[0] == '0') - { - quietMode = false; - } - else if (options[0] == '1') - { - Console.WriteLine("DEU BOM 04"); //AAAAAAH - quietMode = true; - } - } - else - { - quietMode = false; - } - } - else - { - Console.WriteLine("DEU BOM 02"); //AAAAAAH - quietMode = false; - } - - // Read the file - var pe = PEFileUtils.GetPEFile(inFile); - - // Get (or create) the export table) - var exports = new PEExportTable(pe) ?? throw new NullException("exports"); - - // Just check it? - if (statusMode) - { - foreach (var symbol in exportSymbols) - { - var export = exports.Find(symbol.Name); - if (export == null) - { - Console.WriteLine($"Module doesn't export {symbol.Name} symbol"); - } - else - { - var value = *(uint*)pe.GetRVA(export.RVA); - Console.WriteLine($"Module exports {symbol.Name} symbol as 0x{value:X8}"); - } - } - return 0; - } - - // Are all the symbols already present, update existing entries - if (exportSymbols.All(x => exports.Find(x.Name) != null)) - { - foreach (var symbol in exportSymbols) - { - var exportsEntry = exports.Find(symbol.Name) ?? throw new NullException("exportsEntry"); - *(uint*)pe.GetRVA(exportsEntry.RVA) = enableMode ? ExportSymbol.EnableValue : ExportSymbol.DisableValue; - } - } - else - { - if (pe.FindSection(SectionName) != null) - { - throw new InvalidOperationException($"Can't patch as some symbols are missing and {SectionName} section has already been created"); - } - - // Create a new section into which we'll write the changes - var newSection = pe.AddSection(); - newSection.Name = SectionName; - newSection.Characteristics = SectionFlags.InitializedData | SectionFlags.MemRead; - - // Setup the module name - exports.ModuleName = Path.GetFileName(args[1]); - - // Create entres - foreach (var symbol in exportSymbols) - { - // Add export table entry - exports.Add(new PEExportTable.Entry() - { - Ordinal = exports.GetNextOrdinal(), - Name = symbol.Name, - RVA = newSection.CurrentRVA, - }); - - // Write it's value - newSection.OutputStream.Write((uint)(enableMode ? 1 : 0)); - } - - // Write the new exports table - var newExportDD = exports.Write(newSection); - - // Patch the data directories with the new export table - pe.DataDirectories[(int)DataDirectoryIndex.ExportTable] = newExportDD; - } - - // Clear the checksum (just in case) - pe.WindowsHeader.CheckSum = 0; - - // Rewrite the file - pe.Write(inFile); - pe.Dispose(); - - if (!quietMode) - Console.WriteLine("OK"); - - Console.WriteLine("DEU BOM 03"); //AAAAAAH - - return 0; + new ExportedSymbol(nvOptimusEnablement.ToReference(), "NvOptimusEnablement"), + new ExportedSymbol(amdPowerXpressRequestHighPerformance.ToReference(), "AmdPowerXpressRequestHighPerformance"), } +}; - static void ShowLogo() - { - var show = $""" - EditBinPE v{Assembly.GetExecutingAssembly().GetName().Version} - PE-Sharp v{PEUtils.GetVersion()} - Copyright ©2023 Gabriel Frigo Software. All Rights Reserved +// Construct new PE file from image. +var newFile = new ManagedPEFileBuilder().CreateFile(image); - """; - Console.WriteLine(show); - } - - static void ShowHelp() +// Add extra data section with the new symbols (managed pe file builder doesn't do this out-of-the-box). +newFile.Sections.Add(new PESection( + ".extra", + SectionFlags.ContentInitializedData | SectionFlags.MemoryRead, + new SegmentBuilder { - var help = """ - Usage: BinPeEx [] [] - - Adds, updates or queries the export symbols 'NvOptimusEnablement' - and 'AmdPowerXpressRequestHighPerformance' in an existing .exe - - Options: - --enable-gpu sets GPU export symbols to 1 (adding if missing) - --disable-gpu sets GPU export symbols to 0 (if it exists) - --enable sets export symbols to 1 (adding if missing) - --disable sets export symbols to 0 (if it exists) - --status shows the current export symbols status - --help show this help, or help for a command - --version show version information - --quite-yes - --quite-no - """; - Console.WriteLine(help); + nvOptimusEnablement, + amdPowerXpressRequestHighPerformance, } -} +)); -Program.Main(Args); \ No newline at end of file +// Write to disk. +string outputPath = Path.ChangeExtension(inputPath, ".patched" + Path.GetExtension(inputPath)); +newFile.Write(outputPath); \ No newline at end of file From b5d370eb8e45fa38cb44c17203e36962b6963c90 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 May 2024 20:57:38 +0300 Subject: [PATCH 2/6] Fix --- build/gpu.csx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build/gpu.csx b/build/gpu.csx index a289c54..3afe498 100644 --- a/build/gpu.csx +++ b/build/gpu.csx @@ -1,5 +1,13 @@ #r "nuget: AsmResolver.DotNet, 5.5.1" +using AsmResolver; +using AsmResolver.PE; +using AsmResolver.PE.DotNet; +using AsmResolver.PE.DotNet.Builder; +using AsmResolver.PE.Exports; +using AsmResolver.PE.File; +using AsmResolver.PE.File.Headers; + var image = PEImage.FromFile(Args[0]); // Force mixed-mode. From e00c96a17373be43512d916685fbd0c1945aff8a Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 May 2024 21:00:37 +0300 Subject: [PATCH 3/6] Fix --- build/gpu.csx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/gpu.csx b/build/gpu.csx index 3afe498..2774b33 100644 --- a/build/gpu.csx +++ b/build/gpu.csx @@ -8,7 +8,8 @@ using AsmResolver.PE.Exports; using AsmResolver.PE.File; using AsmResolver.PE.File.Headers; -var image = PEImage.FromFile(Args[0]); +var inputPath = Args[0]; +var image = PEImage.FromFile(inputPath); // Force mixed-mode. image.DotNetDirectory!.Flags &= ~DotNetDirectoryFlags.ILOnly; From 9794ae8f8f2b143a5119e54ef866739c2068ffe5 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 May 2024 21:18:40 +0300 Subject: [PATCH 4/6] Cleanup --- .gitignore | 2 -- build/ForceDedicatedGraphicCard.il | 15 --------------- build/gpu.csx | 3 ++- build/set-icon/index.js | 7 ------- build/set-icon/package.json | 5 ----- build/set-icon/yarn.lock | 15 --------------- 6 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 build/ForceDedicatedGraphicCard.il delete mode 100644 build/set-icon/index.js delete mode 100644 build/set-icon/package.json delete mode 100644 build/set-icon/yarn.lock diff --git a/.gitignore b/.gitignore index 30f401f..1217d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -349,5 +349,3 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ /src/.idea/* -/tmp/* -/tools/* diff --git a/build/ForceDedicatedGraphicCard.il b/build/ForceDedicatedGraphicCard.il deleted file mode 100644 index 7f9ccb3..0000000 --- a/build/ForceDedicatedGraphicCard.il +++ /dev/null @@ -1,15 +0,0 @@ - .class public Bannerlord.BLSE.ForceDedicatedGraphicCard - { - .method public static int32 NvOptimusEnablement() cil managed - { - .export [1] - ldc.i4.1 - ret - } - .method public static uint32 AmdPowerXpressRequestHighPerformance() cil managed - { - .export [2] - ldc.i4.1 - ret - } - } \ No newline at end of file diff --git a/build/gpu.csx b/build/gpu.csx index 2774b33..f5ff545 100644 --- a/build/gpu.csx +++ b/build/gpu.csx @@ -43,5 +43,6 @@ newFile.Sections.Add(new PESection( )); // Write to disk. -string outputPath = Path.ChangeExtension(inputPath, ".patched" + Path.GetExtension(inputPath)); +//string outputPath = Path.ChangeExtension(inputPath, ".patched" + Path.GetExtension(inputPath)); +string outputPath = inputPath; newFile.Write(outputPath); \ No newline at end of file diff --git a/build/set-icon/index.js b/build/set-icon/index.js deleted file mode 100644 index 8791ac1..0000000 --- a/build/set-icon/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const changeExe = require('changeexe'); - -const args = process.argv; - -(async () => { - await changeExe.icon(args[2], args[3]); -})(); \ No newline at end of file diff --git a/build/set-icon/package.json b/build/set-icon/package.json deleted file mode 100644 index b6be7c4..0000000 --- a/build/set-icon/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "changeexe": "^1.0.3" - } -} diff --git a/build/set-icon/yarn.lock b/build/set-icon/yarn.lock deleted file mode 100644 index c19f53b..0000000 --- a/build/set-icon/yarn.lock +++ /dev/null @@ -1,15 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -adm-zip@^0.5.10: - version "0.5.12" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.12.tgz#87786328e91d54b37358d8a50f954c4cd73ba60b" - integrity sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ== - -changeexe@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/changeexe/-/changeexe-1.0.3.tgz#e9ccc889aa78179edce7128bb09bf0ff379c65ac" - integrity sha512-UpX2cVZW7smLML+fmdvBw12Nhz1PxODswpOx+9kYDOY+IWSntuFVaC3nFVIJ6+3dmZNFbwR2DDrkBrV861KRCA== - dependencies: - adm-zip "^0.5.10" From 88bb5e365541223419e2964faf3232316aa634b1 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 May 2024 21:22:40 +0300 Subject: [PATCH 5/6] Added cleanup post publish --- .github/workflows/publish.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5edfd5f..801d80d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -166,3 +166,13 @@ jobs: rootPath: build depot1Path: ./artifact releaseBranch: prerelease + + cleanup-build-output: + name: Cleanup Build Output + needs: [publish-on-nexusmods, publish-on-github, publish-on-steam] + runs-on: ubuntu-latest + if: always() + steps: + - uses: joutvhu/delete-artifact@v2 + with: + pattern: bannerlord-tmp-* \ No newline at end of file From 221e0eaeb5e688e8ace8be6119895462d79255bc Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 May 2024 21:27:27 +0300 Subject: [PATCH 6/6] Release --- build/common.props | 2 +- changelog.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build/common.props b/build/common.props index 722b11d..228f8cf 100644 --- a/build/common.props +++ b/build/common.props @@ -11,7 +11,7 @@ - 1.5.6 + 1.5.7 2.2.2 3.0.0.139 5.0.222 diff --git a/changelog.txt b/changelog.txt index 3af9ec0..28fe94c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,9 @@ --------------------------------------------------------------------------------------------------- +Version: 1.5.7 +Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1,v1.1.2,v1.1.3,v1.1.4,v1.1.5,v1.1.6,v1.2.x +* BETA Release! +* Better implementation for GPU Acceleration Hints +--------------------------------------------------------------------------------------------------- Version: 1.5.6 Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1,v1.1.2,v1.1.3,v1.1.4,v1.1.5,v1.1.6,v1.2.x * BETA Release!