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 DungeonEnvironmentGuard v0.1.0
plugins\DungeonEnvironmentGuard\DungeonEnvironmentGuard.dll
Decompiled 2 days agousing System; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: AssemblyCompany("Daishi11")] [assembly: AssemblyTitle("DungeonEnvironmentGuard")] [assembly: AssemblyDescription("Guards against rapid Crypt/SunkenCrypt forced-environment ping-pong in Valheim")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyProduct("DungeonEnvironmentGuard")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.1.0.0")] namespace Daishi11.DungeonEnvironmentGuard; [BepInPlugin("daishi11.valheim.dungeonenvironmentguard", "Dungeon Environment Guard", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "daishi11.valheim.dungeonenvironmentguard"; public const string PluginName = "Dungeon Environment Guard"; public const string PluginVersion = "0.1.0"; private Harmony harmony; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> ConflictWindowMs; internal static ConfigEntry<int> ReleaseDelayMs; internal static ConfigEntry<bool> DiagnosticLogging; private void Awake() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the Crypt/SunkenCrypt environment conflict guard."); ConflictWindowMs = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ConflictWindowMs", 250, new ConfigDescription("Maximum time between alternating Crypt/SunkenCrypt requests for them to count as the broken ping-pong pattern.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 2000), new object[0])); ReleaseDelayMs = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ReleaseDelayMs", 750, new ConfigDescription("While guarded, allow a real Crypt transition once no SunkenCrypt request has been seen for this long.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 5000), new object[0])); DiagnosticLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DiagnosticLogging", true, "Log one message when a conflict is detected and one summary when the guard releases."); MethodInfo methodInfo = FindSetForceEnvironment(); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find EnvMan.SetForceEnvironment(string). No patches were applied."); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(EnvironmentGuardPatch), "Prefix", (Type[])null, (Type[])null); if (methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Internal prefix method was not found. No patches were applied."); return; } harmony = new Harmony("daishi11.valheim.dungeonenvironmentguard"); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Dungeon Environment Guard active. Target: " + methodInfo.DeclaringType.FullName + "." + methodInfo.Name + "; conflict window=" + ConflictWindowMs.Value + " ms; release delay=" + ReleaseDelayMs.Value + " ms.")); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } } private static MethodInfo FindSetForceEnvironment() { MethodInfo[] methods = typeof(EnvMan).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "SetForceEnvironment")) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { return methodInfo; } } } return null; } } internal static class EnvironmentGuardPatch { private const string Crypt = "Crypt"; private const string SunkenCrypt = "SunkenCrypt"; private static string lastDungeonRequest; private static float lastDungeonRequestAt = -1000f; private static float lastSunkenCryptAt = -1000f; private static int rapidAlternations; private static bool guardActive; private static int suppressedRequests; private static float guardStartedAt; public static bool Prefix(object[] __args) { try { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { ResetState(logRelease: false); return true; } if (__args == null || __args.Length != 1) { return true; } string text = __args[0] as string; if (text == null) { text = string.Empty; } float realtimeSinceStartup = Time.realtimeSinceStartup; bool flag = text == "Crypt"; bool flag2 = text == "SunkenCrypt"; if (guardActive) { if (string.IsNullOrEmpty(text) || (!flag && !flag2)) { ReleaseGuard("forced environment changed to '" + text + "'", realtimeSinceStartup); TrackNormalRequest(text, realtimeSinceStartup); return true; } if (flag2) { lastSunkenCryptAt = realtimeSinceStartup; suppressedRequests++; return false; } float num = (float)Plugin.ReleaseDelayMs.Value / 1000f; if (realtimeSinceStartup - lastSunkenCryptAt >= num) { ReleaseGuard("SunkenCrypt requests stopped for " + Plugin.ReleaseDelayMs.Value + " ms", realtimeSinceStartup); TrackNormalRequest(text, realtimeSinceStartup); return true; } suppressedRequests++; return false; } if (!flag && !flag2) { TrackNormalRequest(text, realtimeSinceStartup); return true; } if (flag2) { lastSunkenCryptAt = realtimeSinceStartup; } float num2 = (float)Plugin.ConflictWindowMs.Value / 1000f; bool flag3 = lastDungeonRequest != null && lastDungeonRequest != text; if (flag3 && realtimeSinceStartup - lastDungeonRequestAt <= num2) { rapidAlternations++; } else if (flag3) { rapidAlternations = 1; } else if (lastDungeonRequest == null) { rapidAlternations = 0; } lastDungeonRequest = text; lastDungeonRequestAt = realtimeSinceStartup; if (rapidAlternations >= 2) { guardActive = true; guardStartedAt = realtimeSinceStartup; suppressedRequests = 0; if (Plugin.DiagnosticLogging.Value) { Plugin.Log.LogWarning((object)"Detected rapid Crypt <-> SunkenCrypt forced-environment conflict. Locking the effective environment to SunkenCrypt until the conflict clears."); } if (flag2) { return true; } suppressedRequests++; return false; } return true; } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogError((object)("Dungeon Environment Guard failed open: " + ex)); } return true; } } private static void TrackNormalRequest(string requested, float now) { if (requested == "Crypt" || requested == "SunkenCrypt") { lastDungeonRequest = requested; lastDungeonRequestAt = now; if (requested == "SunkenCrypt") { lastSunkenCryptAt = now; } } else { lastDungeonRequest = null; lastDungeonRequestAt = -1000f; lastSunkenCryptAt = -1000f; rapidAlternations = 0; } } private static void ReleaseGuard(string reason, float now) { if (guardActive && Plugin.DiagnosticLogging.Value) { Plugin.Log.LogInfo((object)("Dungeon environment guard released after " + (now - guardStartedAt).ToString("0.00") + " s; suppressed " + suppressedRequests + " forced-environment requests; reason: " + reason + ".")); } guardActive = false; suppressedRequests = 0; guardStartedAt = 0f; rapidAlternations = 0; } private static void ResetState(bool logRelease) { if (guardActive && logRelease && Plugin.DiagnosticLogging != null && Plugin.DiagnosticLogging.Value) { Plugin.Log.LogInfo((object)"Dungeon environment guard reset."); } lastDungeonRequest = null; lastDungeonRequestAt = -1000f; lastSunkenCryptAt = -1000f; rapidAlternations = 0; guardActive = false; suppressedRequests = 0; guardStartedAt = 0f; } }