Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SteveFixes v1.2.8
BepInEx\patchers\SteveFixes\SteveFixes.Preloader.dll
Decompiled 7 hours agousing 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<string> 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<BytePatch> list = new List<BytePatch>(); 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(); } }
BepInEx\plugins\SteveFixes\SteveFixes.dll
Decompiled 7 hours agousing System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace SteveFixesMod; [BepInPlugin("boogie.stevefixes", "Steve Fixes", "1.2.8")] public sealed class SteveFixes : BaseUnityPlugin { private sealed class MacronState { public bool ShovelAlreadySpawned; public bool HitPointsInitialized; public int DanceIndex = -1; } private sealed class LevelBaseline { public int LevelInstanceId; public string StableKey; public string PlanetName; public readonly List<EnemySnapshot> Entries = new List<EnemySnapshot>(); } private sealed class EnemySnapshot { public EnemyType EnemyType; public string EnemyName; public int Rarity; } public const string PluginGuid = "boogie.stevefixes"; public const string PluginName = "Steve Fixes"; public const string PluginVersion = "1.2.8"; private const float PollInterval = 0.2f; private const float FirstBaselineDelay = 0.75f; private const float RepairPass1Delay = 0.15f; private const float RepairPass2Delay = 1f; private const float RepairPass3Delay = 3f; private const float CurrentLevelSanityInterval = 1f; private ConfigEntry<bool> enemyPoolLifecycleFixEnabled; private ConfigEntry<bool> verboseLogging; private ConfigEntry<bool> lllBundleStatusLifecycleFixEnabled; private ConfigEntry<bool> lllVerboseLogging; private ConfigEntry<bool> macronCompatibilityFixEnabled; private ConfigEntry<int> macronHitsToKill; private float nextPoll; private float nextCurrentSanity; private int lastSorInstanceId = int.MinValue; private int lastCurrentLevelInstanceId = int.MinValue; private int lobbyGeneration; private bool baselineCaptured; private float baselineCaptureAt = -1f; private int repairStage; private float nextRepairAt = -1f; private static ManualLogSource SharedLog; private static Type lllNetworkBundleManagerType; private static MethodInfo lllRefreshLoadStatusMethod; private static MemberInfo lllInstanceMember; private static bool lllPatchInstalled; private static bool lllVerbose; private static float lastLllRedirectAt = -100f; private Harmony harmony; private static Type macronAiType; private static MethodInfo macronSpawnShovelMethod; private static MethodInfo macronHitEnemyMethod; private static MethodInfo macronPlayDanceMusicMethod; private static MethodInfo macronPlayMusicMethod; private static MethodInfo macronNetworkObjectIdGetter; private static FieldInfo macronEnemyHpField; private static int macronConfiguredHitsToKill = 8; private static bool macronPatchInstalled; private static bool macronDancePatchInstalled; private static bool macronDancePlaylistReady; private static int macronDanceClipCount; private static float nextMacronPatchAttempt; private static readonly AudioClip[] MacronDanceClips = (AudioClip[])(object)new AudioClip[10]; private static readonly ConditionalWeakTable<object, MacronState> MacronStates = new ConditionalWeakTable<object, MacronState>(); private Harmony macronHarmony; private readonly Dictionary<int, LevelBaseline> baselineByInstanceId = new Dictionary<int, LevelBaseline>(); private readonly Dictionary<string, LevelBaseline> baselineByStableKey = new Dictionary<string, LevelBaseline>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> LethalLibBlock = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Locker", "ImmortalSnail", "Macron", "Light Eater", "Doctor's Brain", "MysteryButton", "SCP 106", "SCP 939", "scp1507", "scp1507Alpha", "Shy guy", "CountryRoadCreature", "Cabinet", "Scary Lamp", "Thing" }; private void Awake() { enemyPoolLifecycleFixEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("EnemyPoolLifecycleFix", "Enabled", true, "Restore only missing LethalLib enemy entries after recreating a lobby in the same game process."); verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("EnemyPoolLifecycleFix", "VerboseLogging", false, "Log individual repaired moon names in addition to summary lines."); lllBundleStatusLifecycleFixEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("LLLBundleStatusLifecycleFix", "Enabled", true, "Reroute stale LethalLevelLoader NetworkBundleManager refresh callbacks to the current spawned manager after lobby recreation."); lllVerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("LLLBundleStatusLifecycleFix", "VerboseLogging", false, "Log every LethalLevelLoader bundle-status refresh decision. Leave disabled for normal play."); macronCompatibilityFixEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("MacronCompatibilityFix", "Enabled", true, "Enable the pack-specific Macron Enemy v81 compatibility/runtime fixes."); macronHitsToKill = ((BaseUnityPlugin)this).Config.Bind<int>("MacronCompatibilityFix", "HitsToKill", 8, "Base Macron HP in shovel-force units. 8 means eight force=1 hits; stronger damage upgrades naturally reduce the hit count."); macronConfiguredHitsToKill = Math.Max(1, Math.Min(100, macronHitsToKill.Value)); SharedLog = ((BaseUnityPlugin)this).Logger; lllVerbose = lllVerboseLogging.Value; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SteveFixes] Loaded v1.2.8. EnemyPoolLifecycleFix=" + enemyPoolLifecycleFixEnabled.Value + " LLLBundleStatusLifecycleFix=" + lllBundleStatusLifecycleFixEnabled.Value + " MacronCompatibilityFix=" + macronCompatibilityFixEnabled.Value)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[SteveFixes] EnemyPoolLifecycleFix is the validated v1.0.2 implementation (15/15 restoration, idempotent)."); if (lllBundleStatusLifecycleFixEnabled.Value) { InstallLllBundleStatusPatch(); } nextMacronPatchAttempt = 0f; } private void Update() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (macronCompatibilityFixEnabled.Value && !macronPatchInstalled && realtimeSinceStartup >= nextMacronPatchAttempt) { nextMacronPatchAttempt = realtimeSinceStartup + 1f; TryInstallMacronRuntimePatches(); } if (!enemyPoolLifecycleFixEnabled.Value || realtimeSinceStartup < nextPoll) { return; } nextPoll = realtimeSinceStartup + 0.2f; StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return; } int num = SafeInstanceId((Object)(object)instance); if (num != lastSorInstanceId) { OnStartOfRoundChanged(instance, num, realtimeSinceStartup); } if (!baselineCaptured) { if (baselineCaptureAt > 0f && realtimeSinceStartup >= baselineCaptureAt) { CaptureBaseline(instance); } return; } if (lobbyGeneration >= 2 && repairStage > 0 && nextRepairAt > 0f && realtimeSinceStartup >= nextRepairAt) { RepairAllLevels(instance, "new-lobby-pass-" + repairStage); if (repairStage == 1) { repairStage = 2; nextRepairAt = realtimeSinceStartup + 0.85f; } else if (repairStage == 2) { repairStage = 3; nextRepairAt = realtimeSinceStartup + 2f; } else { repairStage = 0; nextRepairAt = -1f; } } if (lobbyGeneration < 2 || !(realtimeSinceStartup >= nextCurrentSanity)) { return; } nextCurrentSanity = realtimeSinceStartup + 1f; SelectableLevel currentLevel = instance.currentLevel; int num2 = SafeInstanceId((Object)(object)currentLevel); if (num2 != lastCurrentLevelInstanceId) { lastCurrentLevelInstanceId = num2; if ((Object)(object)currentLevel != (Object)null) { RepairLevel(currentLevel, "current-level-change", logWhenRepaired: true); } } else if ((Object)(object)currentLevel != (Object)null) { RepairLevel(currentLevel, "current-level-sanity", logWhenRepaired: false); } } private void OnStartOfRoundChanged(StartOfRound sor, int sorId, float now) { int num = lastSorInstanceId; lastSorInstanceId = sorId; lastCurrentLevelInstanceId = int.MinValue; lobbyGeneration++; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes] StartOfRound changed " + num + " -> " + sorId + "; lobbyGeneration=" + lobbyGeneration)); if (!baselineCaptured) { baselineCaptureAt = now + 0.75f; repairStage = 0; nextRepairAt = -1f; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SteveFixes] First lobby detected. Baseline capture scheduled in " + 0.75f.ToString("0.00") + "s.")); } else { repairStage = 1; nextRepairAt = now + 0.15f; nextCurrentSanity = now + 0.5f; ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes] Later lobby detected. Enemy pool repair armed."); } } private void CaptureBaseline(StartOfRound sor) { baselineCaptureAt = -1f; if ((Object)(object)sor == (Object)null || sor.levels == null || sor.levels.Length == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes] Baseline capture delayed: StartOfRound.levels unavailable."); baselineCaptureAt = Time.realtimeSinceStartup + 1f; return; } baselineByInstanceId.Clear(); baselineByStableKey.Clear(); int num = 0; int num2 = 0; int num3 = 0; for (int i = 0; i < sor.levels.Length; i++) { SelectableLevel val = sor.levels[i]; if ((Object)(object)val == (Object)null) { continue; } num++; LevelBaseline levelBaseline = BuildLevelBaseline(val); if (levelBaseline != null && levelBaseline.Entries.Count != 0) { num2++; num3 += levelBaseline.Entries.Count; int num4 = SafeInstanceId((Object)(object)val); if (num4 != 0) { baselineByInstanceId[num4] = levelBaseline; } string text = StableLevelKey(val); if (!string.IsNullOrEmpty(text) && !baselineByStableKey.ContainsKey(text)) { baselineByStableKey.Add(text, levelBaseline); } } } baselineCaptured = num3 > 0; if (!baselineCaptured) { ((BaseUnityPlugin)this).Logger.LogError((object)"[SteveFixes] Baseline capture found ZERO tracked LethalLib entries. Fix will stay disarmed and retry in 1s."); baselineCaptureAt = Time.realtimeSinceStartup + 1f; return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SteveFixes] BASELINE_CAPTURED levelsSeen=" + num + " levelsWithLL=" + num2 + " entries=" + num3 + " trackedNames=" + LethalLibBlock.Count)); } private LevelBaseline BuildLevelBaseline(SelectableLevel level) { if ((Object)(object)level == (Object)null || level.Enemies == null) { return null; } LevelBaseline levelBaseline = new LevelBaseline(); levelBaseline.LevelInstanceId = SafeInstanceId((Object)(object)level); levelBaseline.StableKey = StableLevelKey(level); levelBaseline.PlanetName = Safe(level.PlanetName); for (int i = 0; i < level.Enemies.Count; i++) { SpawnableEnemyWithRarity val = level.Enemies[i]; if (val != null && !((Object)(object)val.enemyType == (Object)null)) { string text = Safe(val.enemyType.enemyName); if (LethalLibBlock.Contains(text)) { EnemySnapshot enemySnapshot = new EnemySnapshot(); enemySnapshot.EnemyType = val.enemyType; enemySnapshot.EnemyName = text; enemySnapshot.Rarity = val.rarity; levelBaseline.Entries.Add(enemySnapshot); } } } return levelBaseline; } private void RepairAllLevels(StartOfRound sor, string reason) { if ((Object)(object)sor == (Object)null || sor.levels == null) { return; } int num = 0; int num2 = 0; int num3 = 0; for (int i = 0; i < sor.levels.Length; i++) { SelectableLevel val = sor.levels[i]; if ((Object)(object)val == (Object)null) { continue; } LevelBaseline levelBaseline = FindBaseline(val); if (levelBaseline == null || levelBaseline.Entries.Count == 0) { continue; } num++; int num4 = RepairLevelWithBaseline(val, levelBaseline); if (num4 > 0) { num2++; num3 += num4; if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes] REPAIRED planet='" + Safe(val.PlanetName) + "' added=" + num4 + " reason=" + reason)); } } } if (num3 > 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes] REPAIR_SUMMARY reason=" + reason + " checked=" + num + " repairedLevels=" + num2 + " entriesAdded=" + num3)); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SteveFixes] REPAIR_SUMMARY reason=" + reason + " checked=" + num + " repairedLevels=0 entriesAdded=0")); } } private int RepairLevel(SelectableLevel level, string reason, bool logWhenRepaired) { LevelBaseline levelBaseline = FindBaseline(level); if (levelBaseline == null || levelBaseline.Entries.Count == 0) { return 0; } int num = RepairLevelWithBaseline(level, levelBaseline); if (num > 0 && (logWhenRepaired || verboseLogging.Value)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes] REPAIRED_CURRENT planet='" + Safe(level.PlanetName) + "' added=" + num + " reason=" + reason)); } return num; } private int RepairLevelWithBaseline(SelectableLevel level, LevelBaseline baseline) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown if ((Object)(object)level == (Object)null || baseline == null || level.Enemies == null) { return 0; } int num = 0; for (int i = 0; i < baseline.Entries.Count; i++) { EnemySnapshot enemySnapshot = baseline.Entries[i]; if (enemySnapshot != null && !((Object)(object)enemySnapshot.EnemyType == (Object)null) && !ContainsEnemy(level.Enemies, enemySnapshot)) { SpawnableEnemyWithRarity item = new SpawnableEnemyWithRarity(enemySnapshot.EnemyType, enemySnapshot.Rarity); level.Enemies.Add(item); num++; } } return num; } private bool ContainsEnemy(List<SpawnableEnemyWithRarity> list, EnemySnapshot expected) { if (list == null || expected == null) { return false; } for (int i = 0; i < list.Count; i++) { SpawnableEnemyWithRarity val = list[i]; if (val != null && !((Object)(object)val.enemyType == (Object)null)) { if (object.ReferenceEquals(val.enemyType, expected.EnemyType)) { return true; } string a = Safe(val.enemyType.enemyName); if (!string.IsNullOrEmpty(expected.EnemyName) && string.Equals(a, expected.EnemyName, StringComparison.OrdinalIgnoreCase)) { return true; } } } return false; } private LevelBaseline FindBaseline(SelectableLevel level) { if ((Object)(object)level == (Object)null) { return null; } int num = SafeInstanceId((Object)(object)level); if (num != 0 && baselineByInstanceId.TryGetValue(num, out var value)) { return value; } string text = StableLevelKey(level); if (!string.IsNullOrEmpty(text) && baselineByStableKey.TryGetValue(text, out value)) { return value; } return null; } private void InstallLllBundleStatusPatch() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown try { lllNetworkBundleManagerType = AccessTools.TypeByName("LethalLevelLoader.NetworkBundleManager"); if (lllNetworkBundleManagerType == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes][LLL] NetworkBundleManager type not found. LLL bundle-status fix disabled for this process."); return; } lllRefreshLoadStatusMethod = AccessTools.Method(lllNetworkBundleManagerType, "RefreshLoadStatus", (Type[])null, (Type[])null); if (lllRefreshLoadStatusMethod == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes][LLL] RefreshLoadStatus method not found. LLL bundle-status fix disabled for this process."); return; } PropertyInfo property = lllNetworkBundleManagerType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { lllInstanceMember = property; } else { FieldInfo field = lllNetworkBundleManagerType.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { field = lllNetworkBundleManagerType.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } lllInstanceMember = field; } harmony = new Harmony("boogie.stevefixes.lll_bundle_status"); HarmonyMethod val = new HarmonyMethod(typeof(SteveFixes).GetMethod("LllRefreshLoadStatusPrefix", BindingFlags.Static | BindingFlags.NonPublic)); HarmonyMethod val2 = new HarmonyMethod(typeof(SteveFixes).GetMethod("LllRefreshLoadStatusFinalizer", BindingFlags.Static | BindingFlags.NonPublic)); harmony.Patch((MethodBase)lllRefreshLoadStatusMethod, val, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null); lllPatchInstalled = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SteveFixes][LLL] LLL_BUNDLE_STATUS_PATCH_READY method=" + lllNetworkBundleManagerType.FullName + "." + lllRefreshLoadStatusMethod.Name + " singletonMember=" + ((lllInstanceMember == null) ? "<fallback-scan>" : lllInstanceMember.Name))); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[SteveFixes][LLL] Failed to install bundle-status patch: " + ex)); } } private static bool LllRefreshLoadStatusPrefix(object __instance) { if (!lllPatchInstalled || __instance == null) { return true; } try { object obj = ResolveCurrentLllNetworkBundleManager(__instance); if (obj == null || object.ReferenceEquals(obj, __instance)) { if (lllVerbose && SharedLog != null) { SharedLog.LogInfo((object)("[SteveFixes][LLL] REFRESH_OK manager=" + DescribeLllManager(__instance))); } return true; } if (!IsUsableLllManager(obj)) { return true; } if (SharedLog != null) { SharedLog.LogWarning((object)("[SteveFixes][LLL] STALE_REFRESH_REDIRECT stale=" + DescribeLllManager(__instance) + " current=" + DescribeLllManager(obj))); } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup - lastLllRedirectAt > 0.05f) { lastLllRedirectAt = realtimeSinceStartup; lllRefreshLoadStatusMethod.Invoke(obj, null); } else if (lllVerbose && SharedLog != null) { SharedLog.LogInfo((object)"[SteveFixes][LLL] STALE_REFRESH_REDIRECT coalesced duplicate callback."); } return false; } catch (Exception ex) { if (SharedLog != null) { SharedLog.LogError((object)("[SteveFixes][LLL] Prefix failed open; allowing original RefreshLoadStatus. " + Unwrap(ex))); } return true; } } private static Exception LllRefreshLoadStatusFinalizer(object __instance, Exception __exception) { if (__exception == null || !lllPatchInstalled || __instance == null) { return __exception; } Exception ex = Unwrap(__exception); if (!(ex is KeyNotFoundException)) { return __exception; } try { object obj = ResolveCurrentLllNetworkBundleManager(__instance); if (obj == null || object.ReferenceEquals(obj, __instance) || !IsUsableLllManager(obj)) { if (SharedLog != null) { SharedLog.LogError((object)("[SteveFixes][LLL] CURRENT_MANAGER_RPC_FAILURE preserved: " + ex.Message)); } return __exception; } if (SharedLog != null) { SharedLog.LogWarning((object)("[SteveFixes][LLL] STALE_RPC_RECOVERY retrying RefreshLoadStatus on current manager after: " + ex.Message)); } lllRefreshLoadStatusMethod.Invoke(obj, null); return null; } catch (Exception ex2) { if (SharedLog != null) { SharedLog.LogError((object)("[SteveFixes][LLL] STALE_RPC_RECOVERY failed: " + Unwrap(ex2))); } return __exception; } } private static object ResolveCurrentLllNetworkBundleManager(object invokingInstance) { object obj = ReadLllSingleton(); if (IsUsableLllManager(obj)) { return obj; } if (lllNetworkBundleManagerType != null) { Object[] array = Resources.FindObjectsOfTypeAll(lllNetworkBundleManagerType); object obj2 = null; foreach (object obj3 in array) { if (IsUnityAlive(obj3)) { if (obj2 == null) { obj2 = obj3; } if (ReadBool(obj3, "IsSpawned") == true) { return obj3; } } } if (obj2 != null && object.ReferenceEquals(obj2, invokingInstance)) { return invokingInstance; } return obj2; } return null; } private static object ReadLllSingleton() { if (lllInstanceMember == null) { return null; } try { PropertyInfo propertyInfo = lllInstanceMember as PropertyInfo; if (propertyInfo != null) { return propertyInfo.GetValue(null, null); } FieldInfo fieldInfo = lllInstanceMember as FieldInfo; if (fieldInfo != null) { return fieldInfo.GetValue(null); } } catch { } return null; } private static bool IsUsableLllManager(object candidate) { if (!IsUnityAlive(candidate)) { return false; } bool? flag = ReadBool(candidate, "IsSpawned"); if (flag.HasValue) { return flag.Value; } return true; } private static bool IsUnityAlive(object candidate) { if (candidate == null) { return false; } Object val = (Object)((candidate is Object) ? candidate : null); if (val != (Object)null) { return true; } if (candidate is Object) { return false; } return true; } private static bool? ReadBool(object instance, string propertyName) { if (instance == null) { return null; } try { PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType == typeof(bool)) { return (bool)property.GetValue(instance, null); } } catch { } return null; } private static string DescribeLllManager(object manager) { if (manager == null) { return "<null>"; } int num = 0; Object val = (Object)((manager is Object) ? manager : null); if (val != (Object)null) { try { num = val.GetInstanceID(); } catch { } } bool? flag = ReadBool(manager, "IsSpawned"); return manager.GetType().Name + "#" + num + " IsSpawned=" + (flag.HasValue ? flag.Value.ToString() : "?"); } private static Exception Unwrap(Exception ex) { Exception ex2 = ex; while (ex2 is TargetInvocationException && ex2.InnerException != null) { ex2 = ex2.InnerException; } return ex2; } private void TryInstallMacronRuntimePatches() { //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown if (macronPatchInstalled || !macronCompatibilityFixEnabled.Value) { return; } try { macronAiType = AccessTools.TypeByName("MacronAI"); if (macronAiType == null) { return; } macronSpawnShovelMethod = AccessTools.Method(macronAiType, "SpawnShovel", Type.EmptyTypes, (Type[])null); if (macronSpawnShovelMethod == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes][Macron] SpawnShovel() not found. Macron runtime fix left inactive."); return; } MethodInfo[] methods = macronAiType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (string.Equals(methodInfo.Name, "HitEnemy", StringComparison.Ordinal)) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 4 && parameters[0].ParameterType == typeof(int)) { macronHitEnemyMethod = methodInfo; } } } macronPlayDanceMusicMethod = AccessTools.Method(macronAiType, "PlayDanceMusic", Type.EmptyTypes, (Type[])null); macronPlayMusicMethod = AccessTools.Method(macronAiType, "PlayMusic", new Type[1] { typeof(AudioClip) }, (Type[])null); macronNetworkObjectIdGetter = AccessTools.PropertyGetter(macronAiType, "NetworkObjectId"); Type baseType = macronAiType; while (baseType != null && macronEnemyHpField == null) { macronEnemyHpField = baseType.GetField("enemyHP", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); baseType = baseType.BaseType; } if (macronHitEnemyMethod == null || macronEnemyHpField == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes][Macron] HitEnemy/enemyHP not found. Refusing partial runtime patch so combat balance remains predictable."); return; } macronHarmony = new Harmony("boogie.stevefixes.macron_runtime"); macronHarmony.Patch((MethodBase)macronSpawnShovelMethod, new HarmonyMethod(typeof(SteveFixes).GetMethod("MacronSpawnShovelPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); macronHarmony.Patch((MethodBase)macronHitEnemyMethod, new HarmonyMethod(typeof(SteveFixes).GetMethod("MacronHitEnemyPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (macronPlayDanceMusicMethod != null && macronPlayMusicMethod != null) { macronHarmony.Patch((MethodBase)macronPlayDanceMusicMethod, new HarmonyMethod(typeof(SteveFixes).GetMethod("MacronPlayDanceMusicPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); macronDancePatchInstalled = true; } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes][Macron] Dance API shape not found. dance1-10 override disabled; stock dance audio remains available."); } macronPatchInstalled = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SteveFixes][Macron] MACRON_FIX_READY safeMode=True oneShovel=True hitsToKill=" + macronConfiguredHitsToKill + " dancePatch=" + macronDancePatchInstalled + " deathPatch=Binary9s")); if (!macronDancePatchInstalled) { return; } string text = null; try { if (macronAiType.Assembly != null && !string.IsNullOrEmpty(macronAiType.Assembly.Location)) { text = Path.GetDirectoryName(macronAiType.Assembly.Location); } } catch { } if (!string.IsNullOrEmpty(text)) { ((MonoBehaviour)this).StartCoroutine(LoadMacronDancePlaylist(text)); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes][Macron] Could not resolve MacronMod.dll folder. dance1-10 override disabled; stock dance audio remains available."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[SteveFixes][Macron] Failed to install runtime patches: " + Unwrap(ex))); } } private IEnumerator LoadMacronDancePlaylist(string macronDir) { macronDancePlaylistReady = false; macronDanceClipCount = 0; for (int i = 0; i < MacronDanceClips.Length; i++) { MacronDanceClips[i] = null; } for (int j = 1; j <= 10; j++) { string path = Path.Combine(macronDir, "macron_dance" + j + ".mp3"); if (!File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes][Macron] Missing macron_dance" + j + ".mp3")); continue; } string uri = "file:///" + path.Replace("\\", "/"); UnityWebRequest request; try { request = UnityWebRequestMultimedia.GetAudioClip(uri, (AudioType)13); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes][Macron] Could not create audio request for dance" + j + ": " + ex.Message)); continue; } yield return request.SendWebRequest(); if ((int)request.result != 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes][Macron] Failed loading dance" + j + ": " + request.error)); request.Dispose(); continue; } AudioClip clip = null; try { clip = DownloadHandlerAudioClip.GetContent(request); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[SteveFixes][Macron] Failed decoding dance" + j + ": " + ex2.Message)); } request.Dispose(); if ((Object)(object)clip != (Object)null) { ((Object)clip).name = "SteveFixes_MacronDance" + j; MacronDanceClips[j - 1] = clip; macronDanceClipCount++; } } macronDancePlaylistReady = macronDanceClipCount == 10; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SteveFixes][Macron] DANCE_PLAYLIST_READY clips=" + macronDanceClipCount + "/10 active=" + macronDancePlaylistReady)); if (!macronDancePlaylistReady) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[SteveFixes][Macron] dance1-10 playlist incomplete. Falling back to Macron's original dance1-3 behavior."); } } private static bool MacronSpawnShovelPrefix(object __instance) { if (!macronPatchInstalled || __instance == null) { return true; } try { MacronState orCreateValue = MacronStates.GetOrCreateValue(__instance); if (orCreateValue.ShovelAlreadySpawned) { return false; } orCreateValue.ShovelAlreadySpawned = true; return true; } catch (Exception ex) { if (SharedLog != null) { SharedLog.LogWarning((object)("[SteveFixes][Macron] One-shovel guard failed open: " + Unwrap(ex).Message)); } return true; } } private static bool MacronPlayDanceMusicPrefix(object __instance) { if (!macronPatchInstalled || !macronDancePatchInstalled || !macronDancePlaylistReady || __instance == null) { return true; } try { ulong num = 0uL; bool flag = false; int num2; if (macronNetworkObjectIdGetter != null) { object obj = macronNetworkObjectIdGetter.Invoke(__instance, null); if (obj != null) { num = Convert.ToUInt64(obj); num2 = (int)(num % 10); flag = true; } else { num2 = 0; } } else { num2 = 0; } if (!flag) { MacronState orCreateValue = MacronStates.GetOrCreateValue(__instance); if (orCreateValue.DanceIndex < 0 || orCreateValue.DanceIndex >= 10) { orCreateValue.DanceIndex = Random.Range(0, 10); } num2 = orCreateValue.DanceIndex; } AudioClip val = MacronDanceClips[num2]; if ((Object)(object)val == (Object)null) { return true; } macronPlayMusicMethod.Invoke(__instance, new object[1] { val }); if (SharedLog != null) { string text = (flag ? num.ToString() : "fallback"); SharedLog.LogInfo((object)("[SteveFixes][Macron] DANCE_PICK " + (num2 + 1) + "/10 mode=DirectStable networkObjectId=" + text)); } return false; } catch (Exception ex) { if (SharedLog != null) { SharedLog.LogWarning((object)("[SteveFixes][Macron] Dance override failed open: " + Unwrap(ex).Message)); } return true; } } private static void MacronHitEnemyPrefix(object __instance) { if (!macronPatchInstalled || __instance == null || macronEnemyHpField == null) { return; } try { MacronState orCreateValue = MacronStates.GetOrCreateValue(__instance); if (!orCreateValue.HitPointsInitialized) { int num = Convert.ToInt32(macronEnemyHpField.GetValue(__instance)); macronEnemyHpField.SetValue(__instance, macronConfiguredHitsToKill); orCreateValue.HitPointsInitialized = true; if (SharedLog != null) { SharedLog.LogInfo((object)("[SteveFixes][Macron] HP_INIT " + num + " -> " + macronConfiguredHitsToKill)); } } } catch (Exception ex) { if (SharedLog != null) { SharedLog.LogWarning((object)("[SteveFixes][Macron] HP initialization failed open: " + Unwrap(ex).Message)); } } } private static string StableLevelKey(SelectableLevel level) { if ((Object)(object)level == (Object)null) { return string.Empty; } string text = Safe(((Object)level).name); string text2 = Safe(level.PlanetName); return text + "|" + text2; } private static int SafeInstanceId(Object obj) { if (obj == (Object)null) { return 0; } try { return obj.GetInstanceID(); } catch { return 0; } } private static string Safe(string text) { return text ?? string.Empty; } }