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 NoOrbLimit v1.1.0
NoOrbLimit.dll
Decompiled 4 days agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NoOrbLimit")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("NoOrbLimit")] [assembly: AssemblyTitle("NoOrbLimit")] [assembly: AssemblyVersion("1.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace NoOrbLimit { [BepInPlugin("com.reponoorblimit.host", "NoOrbLimit", "1.1.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.reponoorblimit.host"; public const string PluginName = "NoOrbLimit"; public const string Version = "1.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> RemoveOrbLimit; internal static ConfigEntry<bool> IgnorePlayerProximity; internal static ConfigEntry<int> MaxOrbsPerLevel; internal static ConfigEntry<int> OrbDropChancePercent; internal static ConfigEntry<bool> VerboseLogging; internal static int OrbsThisLevel; private void Awake() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for the mod."); RemoveOrbLimit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RemoveOrbLimit", true, "Ignore the vanilla per-enemy orb cap (EnemyHealth.spawnValuableMax). Enemies whose prefab sets spawnValuable = false or spawnValuableMax = 0 are left untouched."); IgnorePlayerProximity = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IgnorePlayerProximity", true, "Ignore the vanilla 'player within 20 m in the last 10 seconds' rule. When true, an enemy killed anywhere drops its orb. Default: true."); MaxOrbsPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxOrbsPerLevel", 0, new ConfigDescription("Optional safety cap for enemy orbs spawned per level. 0 = no cap (recommended).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>())); OrbDropChancePercent = ((BaseUnityPlugin)this).Config.Bind<int>("General", "OrbDropChancePercent", 100, new ConfigDescription("Extra drop chance applied once per death. 100 = always drop (required for the 'exactly one orb per death' guarantee).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Log every despawn decision: enemy name, spawnValuable, spawnValuableMax, spawnValuableCurrent, healthCurrent, valuableSpawnTimer, difficulty and the final reason."); OrbsThisLevel = 0; try { new Harmony("com.reponoorblimit.host").PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"[NoOrbLimit] v1.1.0 loaded."); Log.LogInfo((object)($"[NoOrbLimit] Settings: Enabled={Enabled.Value}, RemoveOrbLimit={RemoveOrbLimit.Value}, " + $"IgnorePlayerProximity={IgnorePlayerProximity.Value}, MaxOrbsPerLevel={MaxOrbsPerLevel.Value}, " + $"OrbDropChancePercent={OrbDropChancePercent.Value}, VerboseLogging={VerboseLogging.Value}")); Log.LogInfo((object)"[NoOrbLimit] Patched EnemyParent.Despawn, EnemyHealth.OnSpawn and LevelGenerator.Start. Orb drops are decided by the host (master client); clients do not need this mod."); } catch (Exception ex) { Log.LogError((object)("[NoOrbLimit] Harmony patching failed: " + ex)); } } } } namespace NoOrbLimit.Patches { [HarmonyPatch(typeof(EnemyHealth), "OnSpawn")] internal static class EnemyHealthOnSpawnPatch { [HarmonyPostfix] private static void Postfix(EnemyHealth __instance) { OrbDropState.Reset(__instance); } } [HarmonyPatch(typeof(EnemyParent), "Despawn")] internal static class EnemyParentDespawnPatch { private sealed class PatchState { public EnemyHealth Health; public bool OriginalSpawnValuable; public int OriginalSpawnValuableMax; public int OriginalSpawnValuableCurrent; public bool SpawnValuableMaxModified; public bool SpawnValuableModified; public bool Eligible; public bool Blocked; public string BlockReason; public bool ProximityForced; } private static readonly FieldInfo SpawnValuableCurrentField = AccessTools.Field(typeof(EnemyHealth), "spawnValuableCurrent"); private static readonly FieldInfo HealthCurrentField = AccessTools.Field(typeof(EnemyHealth), "healthCurrent"); private static readonly FieldInfo ValuableSpawnTimerField = AccessTools.Field(typeof(EnemyParent), "valuableSpawnTimer"); private static bool _reflectionWarningLogged; [HarmonyPrefix] private static void Prefix(EnemyParent __instance, out PatchState __state) { __state = null; if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } if (SpawnValuableCurrentField == null || HealthCurrentField == null || ValuableSpawnTimerField == null) { if (!_reflectionWarningLogged) { _reflectionWarningLogged = true; Plugin.Log.LogError((object)"[NoOrbLimit] Required EnemyHealth/EnemyParent fields were not found via reflection. The mod stays inactive; vanilla behavior is kept."); } return; } EnemyHealth componentInChildren = ((Component)__instance).GetComponentInChildren<EnemyHealth>(true); if ((Object)(object)componentInChildren == (Object)null) { if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("[NoOrbLimit] Despawn: enemy='" + __instance.enemyName + "' has no EnemyHealth component -> this enemy can never drop an orb (vanilla rule Enemy.HasHealth == false).")); } return; } int num = (int)HealthCurrentField.GetValue(componentInChildren); float num2 = (float)ValuableSpawnTimerField.GetValue(__instance); if (num > 0) { OrbDropState.Reset(componentInChildren); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)($"[NoOrbLimit] Despawn: enemy='{__instance.enemyName}', healthCurrent={num} -> " + "alive, no orb (natural despawn).")); } return; } PatchState patchState = (__state = new PatchState { Health = componentInChildren, OriginalSpawnValuable = componentInChildren.spawnValuable, OriginalSpawnValuableMax = componentInChildren.spawnValuableMax, OriginalSpawnValuableCurrent = GetSpawnValuableCurrent(componentInChildren) }); if (OrbDropState.IsOrbGiven(componentInChildren)) { patchState.Blocked = true; patchState.BlockReason = "duplicate Despawn for the same death"; BlockWithSpawnValuable(componentInChildren, patchState); LogDecision(__instance, num, num2, patchState); return; } bool originalSpawnValuable = patchState.OriginalSpawnValuable; bool flag = patchState.OriginalSpawnValuableMax <= 0; if (!originalSpawnValuable || flag) { patchState.Blocked = true; patchState.BlockReason = (flag ? "prefab spawnValuableMax = 0 (never drops)" : "prefab spawnValuable = false (never drops)"); LogDecision(__instance, num, num2, patchState); return; } patchState.Eligible = true; if (Plugin.IgnorePlayerProximity.Value && !(num2 > 0f)) { ValuableSpawnTimerField.SetValue(__instance, 10f); num2 = 10f; patchState.ProximityForced = true; } bool flag2 = patchState.OriginalSpawnValuableCurrent < patchState.OriginalSpawnValuableMax; if (Plugin.RemoveOrbLimit.Value) { componentInChildren.spawnValuableMax = int.MaxValue; patchState.SpawnValuableMaxModified = true; flag2 = true; } if (!flag2) { patchState.Blocked = true; patchState.BlockReason = "vanilla per-enemy cap reached (RemoveOrbLimit = false)"; BlockWithSpawnValuable(componentInChildren, patchState); LogDecision(__instance, num, num2, patchState); return; } if (!(num2 > 0f)) { patchState.Blocked = true; patchState.BlockReason = "proximity timer is 0 (IgnorePlayerProximity = false)"; BlockWithSpawnValuable(componentInChildren, patchState); LogDecision(__instance, num, num2, patchState); return; } int value = Plugin.MaxOrbsPerLevel.Value; if (value > 0 && Plugin.OrbsThisLevel >= value) { patchState.Blocked = true; patchState.BlockReason = $"level cap reached ({Plugin.OrbsThisLevel}/{value})"; } else { int value2 = Plugin.OrbDropChancePercent.Value; if (value2 < 100 && Random.Range(0, 100) >= value2) { patchState.Blocked = true; patchState.BlockReason = $"drop chance failed ({value2}%)"; } } if (patchState.Blocked) { BlockWithSpawnValuable(componentInChildren, patchState); } LogDecision(__instance, num, num2, patchState); } [HarmonyPostfix] private static void Postfix(EnemyParent __instance, PatchState __state) { if (__state == null || (Object)(object)__state.Health == (Object)null) { return; } int num = GetSpawnValuableCurrent(__state.Health) - __state.OriginalSpawnValuableCurrent; if (num > 0) { Plugin.OrbsThisLevel += num; OrbDropState.MarkOrbGiven(__state.Health); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)($"[NoOrbLimit] Orb spawned: enemy='{__instance.enemyName}', +{num}, " + $"orbs this level={Plugin.OrbsThisLevel}")); } } else if (__state.Blocked) { OrbDropState.MarkOrbGiven(__state.Health); } else if (__state.Eligible && Plugin.VerboseLogging.Value) { Plugin.Log.LogWarning((object)("[NoOrbLimit] Despawn finished without spawning an orb, but no NoOrbLimit gate blocked it. enemy='" + __instance.enemyName + "'. Check the log for an exception or another mod.")); } } [HarmonyFinalizer] private static Exception Finalizer(EnemyParent __instance, PatchState __state, Exception __exception) { RestoreOriginalFields(__state); if (__exception != null) { Plugin.Log.LogWarning((object)("[NoOrbLimit] EnemyParent.Despawn threw an exception; original field values were restored. " + __exception.GetType().Name + ": " + __exception.Message)); } return __exception; } private static void BlockWithSpawnValuable(EnemyHealth health, PatchState state) { health.spawnValuable = false; state.SpawnValuableModified = true; } private static void LogDecision(EnemyParent enemy, int healthCurrent, float valuableSpawnTimer, PatchState state) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (Plugin.VerboseLogging.Value) { string arg = (state.Blocked ? ("result=blocked (" + state.BlockReason + ")") : "result=allowed"); Plugin.Log.LogInfo((object)($"[NoOrbLimit] Despawn: enemy='{enemy.enemyName}', difficulty={enemy.difficulty}, " + $"spawnValuable={state.OriginalSpawnValuable}, spawnValuableMax={state.OriginalSpawnValuableMax}, " + $"spawnValuableCurrent={state.OriginalSpawnValuableCurrent}, healthCurrent={healthCurrent}, " + $"valuableSpawnTimer={valuableSpawnTimer:0.0}, capLifted={state.SpawnValuableMaxModified}, " + $"proximityForced={state.ProximityForced}, eligible={state.Eligible}, {arg}")); } } private static void RestoreOriginalFields(PatchState state) { if (state != null && !((Object)(object)state.Health == (Object)null)) { if (state.SpawnValuableMaxModified) { state.Health.spawnValuableMax = state.OriginalSpawnValuableMax; state.SpawnValuableMaxModified = false; } if (state.SpawnValuableModified) { state.Health.spawnValuable = state.OriginalSpawnValuable; state.SpawnValuableModified = false; } } } private static int GetSpawnValuableCurrent(EnemyHealth health) { object value = SpawnValuableCurrentField.GetValue(health); if (value is int) { return (int)value; } return 0; } } [HarmonyPatch(typeof(LevelGenerator), "Start")] internal static class LevelGeneratorStartPatch { [HarmonyPostfix] private static void Postfix() { int orbsThisLevel = Plugin.OrbsThisLevel; Plugin.OrbsThisLevel = 0; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"[NoOrbLimit] New level detected: orb counter reset ({orbsThisLevel} -> 0)."); } } } internal static class OrbDropState { private sealed class State { public bool OrbGiven; } private static readonly ConditionalWeakTable<EnemyHealth, State> States = new ConditionalWeakTable<EnemyHealth, State>(); private static State Get(EnemyHealth health) { return States.GetValue(health, (EnemyHealth _) => new State()); } public static bool IsOrbGiven(EnemyHealth health) { if ((Object)(object)health != (Object)null) { return Get(health).OrbGiven; } return false; } public static void MarkOrbGiven(EnemyHealth health) { if ((Object)(object)health != (Object)null) { Get(health).OrbGiven = true; } } public static void Reset(EnemyHealth health) { if ((Object)(object)health != (Object)null) { Get(health).OrbGiven = false; } } } }