using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Cryptography; using BepInEx; using BepInEx.Logging; using Mono.Cecil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace SteveFixesPreloader; public static class MacronBinaryCompatibilityPatcher { private sealed class BytePatch { public readonly int Offset; public readonly byte[] Before; public readonly byte[] After; public readonly string Name; public BytePatch(int offset, byte[] before, byte[] after, string name) { Offset = offset; Before = before; After = after; Name = name; } public void Validate(byte[] bytes) { if (Offset < 0 || Offset + Before.Length > bytes.Length) { throw new InvalidOperationException("Macron byte patch outside file bounds: " + Name); } for (int i = 0; i < Before.Length; i++) { if (bytes[Offset + i] != Before[i]) { throw new InvalidOperationException("Macron byte guard failed for: " + Name + ". No changes were written."); } } } public void Apply(byte[] bytes) { for (int i = 0; i < After.Length; i++) { bytes[Offset + i] = After[i]; } } } private const string OriginalHash = "e46f6cfcedc69b46623334a3bc8664831c34e8bb796bbd1d10bf1360185c5b9e"; private const string CompatV122Hash = "11a769576d504c96949b84063ed34e57b8e43175ef46476eaa6fbd5273dc986a"; private const string CompatV123Hash = "5033f0fe3d4d29ad729e2613bcb1b5da6d5c2b114e553f4ddfd533a0ddae535b"; private const string Death9Hash = "bced1e1786954f4be0711d4cdc5b2cba0108c169231d9c18aaaf8b2e073427bd"; private const string LegacyCustomHash = "c9655c4d53cc1a276ae0326f640d5727374706469c27db3cb0e42fd412f78216"; private static ManualLogSource Log; public static IEnumerable TargetDLLs { get { yield break; } } public static void Initialize() { Log = Logger.CreateLogSource("Steve Fixes Preloader"); try { PatchMacronIfKnown(); } catch (Exception ex) { Log.LogError((object)("[SteveFixes][Preloader] Macron preloader failed safely; file left as-is: " + ex)); } } public static void Patch(AssemblyDefinition assembly) { } public static void Finish() { } private static void PatchMacronIfKnown() { string pluginPath = Paths.PluginPath; if (string.IsNullOrEmpty(pluginPath) || !Directory.Exists(pluginPath)) { Log.LogWarning((object)"[SteveFixes][Preloader] BepInEx plugin path not found; Macron patch skipped."); return; } string[] files = Directory.GetFiles(pluginPath, "MacronMod.dll", SearchOption.AllDirectories); if (files.Length == 0) { Log.LogWarning((object)"[SteveFixes][Preloader] MacronMod.dll not found; Macron binary compatibility patch inactive."); return; } if (files.Length != 1) { Log.LogError((object)("[SteveFixes][Preloader] Found " + files.Length + " MacronMod.dll files. Refusing to patch any of them.")); return; } string text = files[0]; string text2 = Sha256(text); Log.LogInfo((object)("[SteveFixes][Preloader] MacronMod.dll SHA256=" + text2)); if (text2 == "bced1e1786954f4be0711d4cdc5b2cba0108c169231d9c18aaaf8b2e073427bd") { Log.LogInfo((object)"[SteveFixes][Preloader] MACRON_BINARY_READY v81=True deathDelay=9s alreadyPatched=True"); return; } if (text2 == "c9655c4d53cc1a276ae0326f640d5727374706469c27db3cb0e42fd412f78216") { Log.LogWarning((object)"[SteveFixes][Preloader] Legacy custom Macron DLL detected. Leaving it untouched; use original MacronEnemy 1.2.0 for the supported path."); return; } if (text2 != "e46f6cfcedc69b46623334a3bc8664831c34e8bb796bbd1d10bf1360185c5b9e" && text2 != "11a769576d504c96949b84063ed34e57b8e43175ef46476eaa6fbd5273dc986a" && text2 != "5033f0fe3d4d29ad729e2613bcb1b5da6d5c2b114e553f4ddfd533a0ddae535b") { Log.LogWarning((object)"[SteveFixes][Preloader] Unknown MacronMod.dll build. Checksum guard refused the binary patch; file left untouched."); return; } byte[] bytes = File.ReadAllBytes(text); List list = new List(); if (text2 == "e46f6cfcedc69b46623334a3bc8664831c34e8bb796bbd1d10bf1360185c5b9e") { list.Add(new BytePatch(3139, new byte[5] { 40, 45, 0, 0, 10 }, new byte[5] { 38, 38, 38, 0, 0 }, "MacronAI.EnableEnemyMesh obsolete base call")); list.Add(new BytePatch(8243, new byte[5] { 111, 45, 0, 0, 10 }, new byte[5] { 111, 16, 0, 0, 6 }, "DespawnBody -> MacronAI.EnableEnemyMesh")); list.Add(new BytePatch(8826, new byte[5] { 111, 45, 0, 0, 10 }, new byte[5] { 111, 16, 0, 0, 6 }, "SelfActivate -> MacronAI.EnableEnemyMesh")); } else if (text2 == "11a769576d504c96949b84063ed34e57b8e43175ef46476eaa6fbd5273dc986a") { list.Add(new BytePatch(8243, new byte[5] { 111, 45, 0, 0, 10 }, new byte[5] { 111, 16, 0, 0, 6 }, "DespawnBody -> MacronAI.EnableEnemyMesh")); } list.Add(new BytePatch(5256, new byte[7] { 2, 3, 40, 94, 0, 0, 10 }, new byte[7] { 2, 23, 125, 48, 0, 0, 10 }, "KillEnemy: defer base death via isEnemyDead")); list.Add(new BytePatch(7993, new byte[5] { 34, 0, 0, 224, 64 }, new byte[5] { 34, 0, 0, 16, 65 }, "DespawnBody wait: 7s -> 9s")); list.Add(new BytePatch(8022, new byte[31] { 0, 4, 2, 34, 0, 0, 64, 64, 125, 34, 0, 0, 4, 2, 34, 0, 0, 0, 0, 125, 35, 0, 0, 4, 56, 172, 0, 0, 0, 2, 2 }, new byte[31] { 0, 4, 7, 22, 125, 48, 0, 0, 10, 7, 22, 40, 94, 0, 0, 10, 56, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, "DespawnBody: exact delayed base-death finalization")); foreach (BytePatch item in list) { item.Validate(bytes); } string text3 = text + ".stevefixes-original.bak"; if (text2 == "e46f6cfcedc69b46623334a3bc8664831c34e8bb796bbd1d10bf1360185c5b9e" && !File.Exists(text3)) { File.Copy(text, text3, overwrite: false); } if (text2 == "5033f0fe3d4d29ad729e2613bcb1b5da6d5c2b114e553f4ddfd533a0ddae535b") { string text4 = text + ".stevefixes-v123-predeath.bak"; if (!File.Exists(text4)) { File.Copy(text, text4, overwrite: false); } } foreach (BytePatch item2 in list) { item2.Apply(bytes); Log.LogDebug((object)("[SteveFixes][Preloader] Patched: " + item2.Name)); } string text5 = text + ".stevefixes.tmp"; try { File.WriteAllBytes(text5, bytes); string text6 = Sha256(text5); if (text6 != "bced1e1786954f4be0711d4cdc5b2cba0108c169231d9c18aaaf8b2e073427bd") { throw new InvalidOperationException("Patched Macron hash mismatch: " + text6); } File.Copy(text5, text, overwrite: true); } finally { if (File.Exists(text5)) { File.Delete(text5); } } Log.LogInfo((object)"[SteveFixes][Preloader] MACRON_BINARY_READY v81=True deathDelay=9s alreadyPatched=False"); } private static string Sha256(string path) { using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(path); byte[] array = sHA.ComputeHash(inputStream); return BitConverter.ToString(array).Replace("-", "").ToLowerInvariant(); } }