Decompiled source of TheGodRunTheoryCompat v2.0.2

plugins/TheGodRunTheoryCompat/TheGodRunTheoryCompat.dll

Decompiled 3 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("TheGodRunTheoryCompat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.2.0")]
[assembly: AssemblyInformationalVersion("2.0.2+225a7ea07af57655f16663f5d88f42a5b0427f82")]
[assembly: AssemblyProduct("TheGodRunTheoryCompat")]
[assembly: AssemblyTitle("TheGodRunTheoryCompat")]
[assembly: AssemblyVersion("2.0.2.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 TheGodRunTheoryCompat
{
	internal static class ClassicItemsPatch
	{
		private const string Clover = "ClassicItemsReturns.Items.Uncommon.ElitesDropItems";

		private const string ArmsRace = "ClassicItemsReturns.Items.Uncommon.ArmsRace";

		private const string EnergyCell = "ClassicItemsReturns.Items.Uncommon.EnergyCell";

		private const string FireShield = "ClassicItemsReturns.Items.Common.FireShield";

		private const string Jewel = "ClassicItemsReturns.Items.Uncommon.Jewel";

		private const string Medallion = "ClassicItemsReturns.Items.Uncommon.RoyalMedallion";

		private const string RustyJetpack = "ClassicItemsReturns.Items.Uncommon.RustyJetpack";

		private const string SmartShopper = "ClassicItemsReturns.Items.Uncommon.SmartShopper";

		private const string SnakeEyes = "ClassicItemsReturns.Items.Common.SnakeEyes";

		private const string SnakeTracker = "ClassicItemsReturns.Items.Common.SnakeEyes+MasterSnakeEyesTracker";

		private const string Thallium = "ClassicItemsReturns.Items.Rare.Thallium";

		private const string ToughTimes = "ClassicItemsReturns.Items.Uncommon.BearArmor";

		private static int cloverConstantReplacements;

		private static int energyCellConstantReplacements;

		private static int fireShieldThresholdReplacements;

		private static int fireShieldStackInjections;

		private static int rustyJetpackConstantReplacements;

		private static int snakeEyesCapReplacements;

		internal static void Install(Harmony harmony)
		{
			ApplyFieldsAndLanguage();
			cloverConstantReplacements = 0;
			Patch(harmony, "ClassicItemsReturns.Items.Uncommon.ElitesDropItems", "RollForMaster", "CloverTranspiler");
			if (cloverConstantReplacements != 2)
			{
				throw new InvalidOperationException($"56 Leaf Clover gameplay patch expected 2 constants but replaced {cloverConstantReplacements}.");
			}
			energyCellConstantReplacements = 0;
			Patch(harmony, "ClassicItemsReturns.Items.Uncommon.EnergyCell", "RecalculateStatsAPI_GetStatCoefficients", "EnergyCellTranspiler");
			Patch(harmony, "ClassicItemsReturns.Items.Uncommon.EnergyCell+EnergyCellBehavior", "FixedUpdate", "EnergyCellTranspiler");
			RequireCount("Energy Cell gameplay", energyCellConstantReplacements, 6);
			fireShieldThresholdReplacements = 0;
			fireShieldStackInjections = 0;
			Patch(harmony, "ClassicItemsReturns.Items.Common.FireShield", "ProcFireShield", "FireShieldTranspiler");
			RequireCount("Fire Shield threshold", fireShieldThresholdReplacements, 1);
			RequireCount("Fire Shield stack scaling", fireShieldStackInjections, 1);
			rustyJetpackConstantReplacements = 0;
			Patch(harmony, "ClassicItemsReturns.Items.Uncommon.RustyJetpack", "RecalculateStatsAPI_GetStatCoefficients", "RustyJetpackTranspiler");
			RequireCount("Rusty Jetpack gameplay", rustyJetpackConstantReplacements, 2);
			snakeEyesCapReplacements = 0;
			Patch(harmony, "ClassicItemsReturns.Items.Common.SnakeEyes+MasterSnakeEyesTracker", "Increment", "SnakeEyesCapTranspiler");
			RequireCount("Snake Eyes stage cap", snakeEyesCapReplacements, 1);
		}

		internal static void ApplyFieldsAndLanguage()
		{
			BalanceConfig balance = Plugin.Balance;
			if (balance != null && !(ReflectionUtil.FindType("ClassicItemsReturns.Items.Uncommon.ArmsRace", "com.RiskySleeps.ClassicItemsReturns") == null))
			{
				Set("ClassicItemsReturns.Items.Uncommon.ArmsRace", "cooldown", balance.ArmsRaceCooldown.Value);
				Set("ClassicItemsReturns.Items.Uncommon.ArmsRace", "missileCount", balance.ArmsRaceMissiles.Value);
				Set("ClassicItemsReturns.Items.Uncommon.ArmsRace", "missileCountPerStack", balance.ArmsRaceMissilesPerStack.Value);
				Set("ClassicItemsReturns.Items.Uncommon.ArmsRace", "damageCoeff", balance.ArmsRaceDamage.Value);
				ReflectionUtil.SetStaticField("ClassicItemsReturns.Items.Common.FireShield", "explosionDamageCoefficient", balance.FireShieldExplosion.Value, "com.RiskySleeps.ClassicItemsReturns");
				ReflectionUtil.SetStaticField("ClassicItemsReturns.Items.Common.FireShield", "igniteDamageCoefficient", balance.FireShieldBurnBase.Value, "com.RiskySleeps.ClassicItemsReturns");
				Set("ClassicItemsReturns.Items.Uncommon.Jewel", "moneyToGrant", balance.JewelGold.Value);
				Set("ClassicItemsReturns.Items.Uncommon.Jewel", "barrierInitial", balance.JewelBarrier.Value);
				Set("ClassicItemsReturns.Items.Uncommon.Jewel", "barrierStack", balance.JewelBarrierPerStack.Value);
				Set("ClassicItemsReturns.Items.Uncommon.RoyalMedallion", "procChance", balance.MedallionChance.Value);
				Set("ClassicItemsReturns.Items.Uncommon.RoyalMedallion", "buffDuration", balance.MedallionDuration.Value);
				Set("ClassicItemsReturns.Items.Uncommon.RoyalMedallion", "buffDurationStack", balance.MedallionDurationPerStack.Value);
				Set("ClassicItemsReturns.Items.Uncommon.SmartShopper", "moneyMult", balance.ShopperGold.Value);
				Set("ClassicItemsReturns.Items.Uncommon.SmartShopper", "moneyMultStack", balance.ShopperGold.Value);
				Set("ClassicItemsReturns.Items.Common.SnakeEyes", "critChance", balance.SnakeCrit.Value);
				Set("ClassicItemsReturns.Items.Common.SnakeEyes", "critDamageStack", balance.SnakeCritDamagePerStack.Value);
				Set("ClassicItemsReturns.Items.Rare.Thallium", "chance", balance.ThalliumChance.Value);
				Set("ClassicItemsReturns.Items.Rare.Thallium", "enemyAttackDamageCoef", balance.ThalliumDamage.Value);
				Set("ClassicItemsReturns.Items.Rare.Thallium", "enemyMoveSpeedCoef", balance.ThalliumSlow.Value);
				Set("ClassicItemsReturns.Items.Rare.Thallium", "duration", balance.ThalliumDuration.Value);
				Set("ClassicItemsReturns.Items.Rare.Thallium", "durationPerStack", balance.ThalliumDurationPerStack.Value);
				Set("ClassicItemsReturns.Items.Uncommon.BearArmor", "armor", balance.ToughTimesArmor.Value);
				Set("ClassicItemsReturns.Items.Uncommon.BearArmor", "armorPerStack", balance.ToughTimesArmor.Value);
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_56LEAFCLOVER_DESCRIPTION", $"Elite enemies have a <style=cIsUtility>{balance.CloverBaseChance.Value:0.##}% chance</style> <style=cStack>(+{balance.CloverStackChance.Value:0.##}% chance per stack)</style> to <style=cIsUtility>drop an item</style> on death. <style=cIsUtility>Unaffected by luck</style>.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_ARMSRACE_DESCRIPTION", $"Drones periodically fire a barrage of <style=cIsDamage>{balance.ArmsRaceMissiles.Value}</style> <style=cStack>(+{balance.ArmsRaceMissilesPerStack.Value} per stack)</style> missiles that deal <style=cIsDamage>{balance.ArmsRaceDamage.Value * 100f:0.#}%</style> damage. Recharges every <style=cIsUtility>{balance.ArmsRaceCooldown.Value:0.##}</style> seconds.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_ENERGYCELL_DESCRIPTION", $"Increase attack speed by <style=cIsDamage>{balance.EnergyCellHealthy.Value * 100f:0.#}% per stack</style>, increasing by up to another <style=cIsDamage>{balance.EnergyCellLowHealthExtra.Value * 100f:0.#}% per stack</style> as health falls.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_FIRESHIELD_DESCRIPTION", $"After taking more than <style=cIsHealth>{balance.FireShieldThreshold.Value * 100f:0.#}% of your maximum health</style> as damage, explode for <style=cIsDamage>{balance.FireShieldExplosion.Value * 100f:0.#}%</style> base damage. Additionally, enemies burn for <style=cIsDamage>{balance.FireShieldBurnBase.Value * 100f:0.#}%</style> <style=cStack>(+{balance.FireShieldBurnPerStack.Value * 100f:0.#}% per extra stack)</style> base damage.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_JEWEL_DESCRIPTION", $"Activating an interactable grants a temporary barrier for <style=cIsHealing>{balance.JewelBarrier.Value * 100f:0.#}%</style> <style=cStack>(+{balance.JewelBarrierPerStack.Value * 100f:0.#}% per stack)</style> of maximum health and <style=cIsUtility>${balance.JewelGold.Value}</style>. Scales with time.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_ROYALMEDALLION_DESCRIPTION", $"<style=cIsDamage>{balance.MedallionChance.Value:0.##}%</style> chance on hitting a boss to drop a buffing orb that improves health regeneration, attack speed, movement speed, and base damage for <style=cIsDamage>{balance.MedallionDuration.Value:0.##}s</style> <style=cStack>(+{balance.MedallionDurationPerStack.Value:0.##}s per stack)</style>.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_RUSTYJETPACK_DESCRIPTION", $"Increase jump height by <style=cIsUtility>{balance.RustyJump.Value * 100f:0.#}%</style> <style=cStack>(+{balance.RustyJump.Value * 100f:0.#}% per stack)</style> and gain a short airhop.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_SMARTSHOPPER_DESCRIPTION", $"Enemies drop an extra <style=cIsUtility>{balance.ShopperGold.Value * 100f:0.#}%</style> <style=cStack>(+{balance.ShopperGold.Value * 100f:0.#}% per stack)</style> gold on kill.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_SNAKEEYES_DESCRIPTION", $"Using a shrine increases critical chance by <style=cIsDamage>{balance.SnakeCrit.Value:0.##}%</style> and critical damage by <style=cIsDamage>0%</style> <style=cStack>(+{balance.SnakeCritDamagePerStack.Value * 100f:0.##}% per item stack)</style>, up to <style=cIsDamage>{Math.Max(1, Math.Min(6, balance.SnakeStageActivations.Value))} times</style>. Resets each stage.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_THALLIUM_DESCRIPTION", $"On hit, <style=cIsDamage>{balance.ThalliumChance.Value:0.##}% chance</style> to poison using <style=cIsDamage>{balance.ThalliumDamage.Value * 100f:0.#}% damage scaling</style> and slow movement by <style=cIsDamage>{balance.ThalliumSlow.Value * 100f:0.#}%</style> for <style=cIsDamage>{balance.ThalliumDuration.Value:0.##} seconds</style>.");
				ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_TOUGHTIMES_DESCRIPTION", $"Grants <style=cIsHealing>+{balance.ToughTimesArmor.Value:0.#} armor</style> <style=cStack>(+{balance.ToughTimesArmor.Value:0.#} per stack)</style>.");
			}
		}

		private static void Set(string type, string field, object value)
		{
			ReflectionUtil.SetInstanceField(type, field, value, "com.RiskySleeps.ClassicItemsReturns");
		}

		private static void Patch(Harmony harmony, string typeName, string methodName, string transpilerName)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(ReflectionUtil.RequireType(typeName, "com.RiskySleeps.ClassicItemsReturns"), methodName, (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeName, methodName);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(ClassicItemsPatch), transpilerName, (Type[])null, (Type[])null);
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static IEnumerable<CodeInstruction> CloverTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float left)
				{
					if (Nearly(left, 4.5f))
					{
						instruction.operand = Plugin.Balance.CloverBaseChance.Value;
					}
					else
					{
						if (!Nearly(left, 1.5f))
						{
							yield return instruction;
							continue;
						}
						instruction.operand = Plugin.Balance.CloverStackChance.Value;
					}
					cloverConstantReplacements++;
				}
				yield return instruction;
			}
		}

		private static IEnumerable<CodeInstruction> EnergyCellTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float left)
				{
					if (Nearly(left, 0.2f))
					{
						instruction.operand = Plugin.Balance.EnergyCellHealthy.Value;
					}
					else
					{
						if (!Nearly(left, 0.4f))
						{
							yield return instruction;
							continue;
						}
						instruction.operand = Plugin.Balance.EnergyCellLowHealthExtra.Value;
					}
					energyCellConstantReplacements++;
				}
				yield return instruction;
			}
		}

		private static IEnumerable<CodeInstruction> FireShieldTranspiler(IEnumerable<CodeInstruction> source)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(source);
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if (val.opcode == OpCodes.Ldc_R4 && val.operand is float left && Nearly(left, 0.049f))
				{
					val.operand = Math.Max(0f, Plugin.Balance.FireShieldThreshold.Value - 0.001f);
					fireShieldThresholdReplacements++;
				}
				if (CodeInstructionExtensions.LoadsField(val, AccessTools.Field(ReflectionUtil.RequireType("ClassicItemsReturns.Items.Common.FireShield", "com.RiskySleeps.ClassicItemsReturns"), "igniteDamageCoefficient"), false))
				{
					flag = true;
				}
				else if (flag && val.opcode == OpCodes.Conv_R4)
				{
					list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ClassicItemsPatch), "FireShieldStackMultiplier", (Type[])null, (Type[])null)));
					flag = false;
					fireShieldStackInjections++;
					i++;
				}
			}
			return list;
		}

		private static float FireShieldStackMultiplier(float stacks)
		{
			return 1f + Plugin.Balance.FireShieldBurnPerStack.Value * Math.Max(0f, stacks - 1f);
		}

		private static IEnumerable<CodeInstruction> RustyJetpackTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float left && Nearly(left, 0.25f))
				{
					instruction.operand = Plugin.Balance.RustyJump.Value;
					rustyJetpackConstantReplacements++;
				}
				yield return instruction;
			}
		}

		private static IEnumerable<CodeInstruction> SnakeEyesCapTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			int cap = Math.Max(1, Math.Min(6, Plugin.Balance.SnakeStageActivations.Value));
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldc_I4_6)
				{
					instruction.opcode = OpCodes.Ldc_I4;
					instruction.operand = cap;
					snakeEyesCapReplacements++;
				}
				yield return instruction;
			}
		}

		private static bool Nearly(float left, float right)
		{
			return Math.Abs(left - right) < 0.0001f;
		}

		private static void RequireCount(string patchName, int actual, int expected)
		{
			if (actual != expected)
			{
				throw new InvalidOperationException($"{patchName} patch expected {expected} replacement(s) but made {actual}.");
			}
		}
	}
	internal static class CloudburstPatch
	{
		private const string Glass = "Cloudburst.Items.Gray.GlassHarvester";

		private const string Bismuth = "Cloudburst.Items.Green.BismuthEarrings";

		private const string Fabinhoru = "Cloudburst.Items.Green.FabinhoruDagger";

		private const string Japes = "Cloudburst.Items.Green.JapesCloak";

		private const string Keycard = "Cloudburst.Items.Green.EnigmaticKeycard";

		private static int glassReplacements;

		private static int japesArmorReplacements;

		private static int japesHealingReplacements;

		private static int japesDurationReplacements;

		private static int keycardDamageInjections;

		internal static void Install(Harmony harmony)
		{
			if (!(ReflectionUtil.FindType("Cloudburst.Items.Green.BismuthEarrings", "CloudBurstTeam.Cloudburst") == null))
			{
				ApplyFieldsAndLanguage();
				glassReplacements = 0;
				PatchTranspiler(harmony, "Cloudburst.Items.Gray.GlassHarvester", "RecalculateStatsAPI_GetStatCoefficients", "GlassTranspiler");
				RequireCount("Glass Harvester", glassReplacements, 2);
				PatchPostfix(harmony, "Cloudburst.Items.Green.FabinhoruDagger", "RecalculateStatsAPI_GetStatCoefficients", "FabinhoruPostfix");
				japesArmorReplacements = 0;
				PatchTranspiler(harmony, "Cloudburst.Items.Green.JapesCloak", "RecalculateStatsAPI_GetStatCoefficients", "JapesArmorTranspiler");
				RequireCount("Jape's Cloak armor", japesArmorReplacements, 1);
				japesHealingReplacements = 0;
				PatchTranspiler(harmony, "Cloudburst.Items.Green.JapesCloak", "HealthComponent_Heal", "JapesHealingTranspiler");
				RequireCount("Jape's Cloak healing", japesHealingReplacements, 1);
				japesDurationReplacements = 0;
				PatchTranspiler(harmony, "Cloudburst.Items.Green.JapesCloak", "GenericPickupController_AttemptGrant", "JapesDurationTranspiler");
				RequireCount("Jape's Cloak duration", japesDurationReplacements, 1);
				keycardDamageInjections = 0;
				PatchTranspiler(harmony, "Cloudburst.Items.Green.EnigmaticKeycard", "GlobalEventManager_OnHitEnemy", "KeycardDamageTranspiler");
				RequireCount("Enigmatic Keycard damage", keycardDamageInjections, 1);
			}
		}

		internal static void ApplyFieldsAndLanguage()
		{
			BalanceConfig balance = Plugin.Balance;
			if (balance != null && !(ReflectionUtil.FindType("Cloudburst.Items.Green.BismuthEarrings", "CloudBurstTeam.Cloudburst") == null))
			{
				float num = Math.Max(0f, balance.CloudburstScale.Value);
				ReflectionUtil.SetStaticField("Cloudburst.Items.Green.BismuthEarrings", "BaseBarrier", 15f * num, "CloudBurstTeam.Cloudburst");
				ReflectionUtil.SetStaticField("Cloudburst.Items.Green.BismuthEarrings", "StackingBarrier", 10f * num, "CloudBurstTeam.Cloudburst");
				ReflectionUtil.SetStaticField("Cloudburst.Items.Green.EnigmaticKeycard", "Chance", 4f * num, "CloudBurstTeam.Cloudburst");
				ReflectionUtil.AddLanguage("ITEM_GLASSHARVESTER_DESC", $"Gain <style=cIsDamage>5% critical strike chance</style>. <style=cIsDamage>Critical Strikes</style> deal an additional <style=cIsDamage>{40f * num:0.#}% damage</style> <style=cStack>(+{30f * num:0.#}% per stack)</style>. Taking damage below <style=cIsHealth>25% health</style> breaks this item and grants experience.");
				ReflectionUtil.AddLanguage("ITEM_BARRIERONCRIT_DESCRIPTION", $"Gain <style=cIsDamage>5% bleed chance</style>. Applying bleed grants <style=cIsHealing>{15f * num:0.#} barrier</style> <style=cStack>(+{10f * num:0.#} per stack)</style>.");
				ReflectionUtil.AddLanguage("ITEM_PICKUPBUFF_DESCRIPTION", $"Picking up an item grants a stacking buff for <style=cIsUtility>{10f * balance.JapesDurationScale.Value:0.#} seconds</style>. Each buff retains Jape's original stacking rules with its armor and healing values reduced by {100f * (1f - num):0.#}%.");
				ReflectionUtil.AddLanguage("ITEM_ENIGMATICKEYCARD_DESCRIPTION", $"{4f * num:0.#}% chance on hit to spawn a seeking orb. Its original complete damage calculation is multiplied by {num:0.##}.");
			}
		}

		private static void PatchTranspiler(Harmony harmony, string typeName, string methodName, string patchName)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(ReflectionUtil.RequireType(typeName, "CloudBurstTeam.Cloudburst"), methodName, (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeName, methodName);
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(CloudburstPatch), patchName, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void PatchPostfix(Harmony harmony, string typeName, string methodName, string patchName)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(ReflectionUtil.RequireType(typeName, "CloudBurstTeam.Cloudburst"), methodName, (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeName, methodName);
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(CloudburstPatch), patchName, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static IEnumerable<CodeInstruction> GlassTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			float scale = Math.Max(0f, Plugin.Balance.CloudburstScale.Value);
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float left)
				{
					if (Nearly(left, 0.3f))
					{
						instruction.operand = 0.3f * scale;
					}
					else
					{
						if (!Nearly(left, 0.1f))
						{
							yield return instruction;
							continue;
						}
						instruction.operand = 0.1f * scale;
					}
					glassReplacements++;
				}
				yield return instruction;
			}
		}

		private static void FabinhoruPostfix(object sender, object args)
		{
			object staticField = ReflectionUtil.GetStaticField("Cloudburst.Items.Green.FabinhoruDagger", "fabinhorusBuff", "CloudBurstTeam.Cloudburst");
			int buffCount = ReflectionUtil.GetBuffCount(sender, staticField);
			if (buffCount > 0)
			{
				float num = Math.Max(0f, Plugin.Balance.CloudburstScale.Value);
				float num2 = (float)buffCount * 15f + 15f;
				ReflectionUtil.AddFloatMember(args, "armorAdd", num2 * (1f - num));
			}
		}

		private static IEnumerable<CodeInstruction> JapesArmorTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			return ReplaceFloat(instructions, 5f, 5f * Math.Max(0f, Plugin.Balance.CloudburstScale.Value), delegate
			{
				japesArmorReplacements++;
			});
		}

		private static IEnumerable<CodeInstruction> JapesHealingTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			float num = Math.Max(0f, Plugin.Balance.CloudburstScale.Value);
			return ReplaceFloat(instructions, 1.3f, 1f + 0.3f * num, delegate
			{
				japesHealingReplacements++;
			});
		}

		private static IEnumerable<CodeInstruction> JapesDurationTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			return ReplaceFloat(instructions, 10f, 10f * Math.Max(0f, Plugin.Balance.JapesDurationScale.Value), delegate
			{
				japesDurationReplacements++;
			});
		}

		private static IEnumerable<CodeInstruction> KeycardDamageTranspiler(IEnumerable<CodeInstruction> source)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(source);
			FieldInfo fieldInfo = AccessTools.Field(ReflectionUtil.RequireType("Cloudburst.Items.Green.EnigmaticKeycard", "CloudBurstTeam.Cloudburst"), "BaseDamage");
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.LoadsField(list[i], fieldInfo, false))
				{
					flag = true;
				}
				else if (flag && list[i].opcode == OpCodes.Add)
				{
					list.Insert(i + 1, new CodeInstruction(OpCodes.Ldc_R4, (object)Math.Max(0f, Plugin.Balance.CloudburstScale.Value)));
					list.Insert(i + 2, new CodeInstruction(OpCodes.Mul, (object)null));
					keycardDamageInjections++;
					break;
				}
			}
			return list;
		}

		private static IEnumerable<CodeInstruction> ReplaceFloat(IEnumerable<CodeInstruction> instructions, float oldValue, float newValue, Action replaced)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float left && Nearly(left, oldValue))
				{
					instruction.operand = newValue;
					replaced();
				}
				yield return instruction;
			}
		}

		private static bool Nearly(float left, float right)
		{
			return Math.Abs(left - right) < 0.0001f;
		}

		private static void RequireCount(string patchName, int actual, int expected)
		{
			if (actual != expected)
			{
				throw new InvalidOperationException($"{patchName} patch expected {expected} replacement(s) but made {actual}.");
			}
		}
	}
	internal static class LotusGuard
	{
		private const string LotusType = "vanillaVoid.Items.CrystalLotus";

		private static bool logged;

		internal static void Install(Harmony harmony)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			Type type = ReflectionUtil.FindType("vanillaVoid.Items.CrystalLotus", "com.Zenithrium.vanillaVoid");
			if (!(type == null))
			{
				MethodInfo methodInfo = AccessTools.Method(type, "LotusTeamBuff", (Type[])null, (Type[])null) ?? throw new MissingMethodException("vanillaVoid.Items.CrystalLotus", "LotusTeamBuff");
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(LotusGuard), "Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null);
			}
		}

		private static Exception Finalizer(Exception __exception)
		{
			if (__exception is NullReferenceException)
			{
				if (!logged)
				{
					logged = true;
					Plugin.Instance.Log.LogWarning((object)"Crystalline Lotus skipped one invalid/destroyed visual target. Valid ward behavior remains active.");
				}
				return null;
			}
			return __exception;
		}
	}
	[HarmonyPatch]
	internal static class OppressiveAuraPhysicsPatch
	{
		private const string BehaviourTypeName = "NemesisRisingTides.Contents.Oppressive+AffixOppressive+NemesisAffixOppressiveBehaviour";

		private static MethodBase TargetMethod()
		{
			Type type = ReflectionUtil.FindType("NemesisRisingTides.Contents.Oppressive+AffixOppressive+NemesisAffixOppressiveBehaviour", "prodzpod.NemesisRisingTides");
			if (!(type == null))
			{
				return AccessTools.Method(type, "FixedUpdate", (Type[])null, (Type[])null);
			}
			return null;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo overlapCapsule = AccessTools.Method(typeof(Physics), "OverlapCapsule", new Type[3]
			{
				typeof(Vector3),
				typeof(Vector3),
				typeof(float)
			}, (Type[])null);
			MethodInfo overlapBubble = AccessTools.Method(typeof(OppressiveAuraPhysicsPatch), "OverlapBubble", (Type[])null, (Type[])null);
			bool replaced = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Call && object.Equals(instruction.operand, overlapCapsule))
				{
					instruction.operand = overlapBubble;
					replaced = true;
				}
				yield return instruction;
			}
			if (!replaced)
			{
				throw new InvalidOperationException("Nemesis Rising Tides Oppressive OverlapCapsule call was not found.");
			}
		}

		private static Collider[] OverlapBubble(Vector3 center, Vector3 ignoredEndpoint, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Physics.OverlapSphere(center, radius);
		}
	}
	[HarmonyPatch]
	internal static class OppressiveAuraVisualPatch
	{
		private const string BehaviourTypeName = "NemesisRisingTides.Contents.Oppressive+AffixOppressive+NemesisAffixOppressiveBehaviour";

		private static Mesh bubbleMesh;

		private static MethodBase TargetMethod()
		{
			Type type = ReflectionUtil.FindType("NemesisRisingTides.Contents.Oppressive+AffixOppressive+NemesisAffixOppressiveBehaviour", "prodzpod.NemesisRisingTides");
			if (!(type == null))
			{
				return AccessTools.Method(type, "Start", (Type[])null, (Type[])null);
			}
			return null;
		}

		private static void Postfix(object __instance)
		{
			if (__instance == null)
			{
				return;
			}
			object? obj = AccessTools.Field(__instance.GetType(), "aura")?.GetValue(__instance);
			Component val = (Component)((obj is Component) ? obj : null);
			if (!((Object)(object)val == (Object)null))
			{
				EnsureBubbleMesh();
				if (!((Object)(object)bubbleMesh == (Object)null))
				{
					SetBubbleMesh(val.transform.Find("SphereOuter"));
					SetBubbleMesh(val.transform.Find("SphereInner"));
				}
			}
		}

		private static void EnsureBubbleMesh()
		{
			if (!((Object)(object)bubbleMesh != (Object)null))
			{
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
				MeshFilter component = obj.GetComponent<MeshFilter>();
				bubbleMesh = (((Object)(object)component == (Object)null) ? null : component.sharedMesh);
				Object.Destroy((Object)(object)obj);
			}
		}

		private static void SetBubbleMesh(Transform visual)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)visual == (Object)null))
			{
				MeshFilter component = ((Component)visual).GetComponent<MeshFilter>();
				if ((Object)(object)component != (Object)null)
				{
					component.sharedMesh = bubbleMesh;
				}
				visual.localPosition = Vector3.zero;
				visual.localRotation = Quaternion.identity;
				visual.localScale = Vector3.one * 2f;
			}
		}
	}
	internal static class PerformancePatches
	{
		private const string EffectComponentType = "RoR2.EffectComponent";

		private const string CorpseType = "RoR2.Corpse";

		private const string DamageNumberManagerType = "RoR2.DamageNumberManager";

		private static readonly BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static int? originalCorpseLimit;

		internal static void Install(Harmony harmony)
		{
			PatchPostfix(harmony, "RoR2.EffectComponent", "Start", "EffectComponentStartPostfix");
			PatchPostfix(harmony, "RoR2.DamageNumberManager", "Awake", "DamageNumberManagerAwakePostfix");
			Plugin.Balance.PerformanceEnabled.SettingChanged += SettingsChanged;
			Plugin.Balance.MaximumCorpses.SettingChanged += SettingsChanged;
			ApplyGlobalSettings();
		}

		internal static void RegisterRiskOfOptions()
		{
			Type type = ReflectionUtil.RequireType("RiskOfOptions.ModSettingsManager", "com.rune580.riskofoptions");
			Type optionType = ReflectionUtil.RequireType("RiskOfOptions.Options.CheckBoxOption", "com.rune580.riskofoptions");
			Type optionType2 = ReflectionUtil.RequireType("RiskOfOptions.Options.IntSliderOption", "com.rune580.riskofoptions");
			MethodInfo methodInfo = type.GetMethod("SetModDescription", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
			{
				typeof(string),
				typeof(string),
				typeof(string)
			}, null) ?? throw new MissingMethodException(type.FullName, "SetModDescription");
			MethodInfo methodInfo2 = null;
			MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo3 in methods)
			{
				ParameterInfo[] parameters = methodInfo3.GetParameters();
				if (methodInfo3.Name == "AddOption" && parameters.Length == 3 && parameters[1].ParameterType == typeof(string) && parameters[2].ParameterType == typeof(string))
				{
					methodInfo2 = methodInfo3;
					break;
				}
			}
			if (methodInfo2 == null)
			{
				throw new MissingMethodException(type.FullName, "AddOption(option, modGuid, modName)");
			}
			methodInfo.Invoke(null, new object[3] { "Pack compatibility, balance, stability, and optional client performance controls.", "com.lucie.thegodruntheorycompat", "The GodRun Theory Compatibility" });
			AddOption(methodInfo2, optionType, (ConfigEntryBase)(object)Plugin.Balance.PerformanceEnabled);
			AddOption(methodInfo2, optionType, (ConfigEntryBase)(object)Plugin.Balance.EffectRendererOptimization);
			AddOption(methodInfo2, optionType2, (ConfigEntryBase)(object)Plugin.Balance.MaximumParticles);
			AddOption(methodInfo2, optionType2, (ConfigEntryBase)(object)Plugin.Balance.MaximumCorpses);
			AddOption(methodInfo2, optionType2, (ConfigEntryBase)(object)Plugin.Balance.MaximumDamageNumbers);
			AddOption(methodInfo2, optionType, (ConfigEntryBase)(object)Plugin.Balance.DisableEffectLightShadows);
		}

		private static void AddOption(MethodInfo addOption, Type optionType, ConfigEntryBase entry)
		{
			object obj = (optionType.GetConstructor(new Type[1] { ((object)entry).GetType() }) ?? throw new MissingMethodException(optionType.FullName, ".ctor(" + ((object)entry).GetType().Name + ")")).Invoke(new object[1] { entry });
			addOption.Invoke(null, new object[3] { obj, "com.lucie.thegodruntheorycompat", "The GodRun Theory Compatibility" });
		}

		private static void SettingsChanged(object sender, EventArgs eventArgs)
		{
			ApplyGlobalSettings();
		}

		private static void ApplyGlobalSettings()
		{
			FieldInfo fieldInfo = ReflectionUtil.RequireType("RoR2.Corpse").GetField("maxCorpses", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException("RoR2.Corpse", "maxCorpses");
			if (!originalCorpseLimit.HasValue)
			{
				originalCorpseLimit = (int)fieldInfo.GetValue(null);
			}
			int num = (Plugin.Balance.PerformanceEnabled.Value ? Math.Max(0, Plugin.Balance.MaximumCorpses.Value) : originalCorpseLimit.Value);
			fieldInfo.SetValue(null, num);
		}

		private static void EffectComponentStartPostfix(object __instance)
		{
			if (Plugin.Balance.PerformanceEnabled.Value)
			{
				Component val = (Component)((__instance is Component) ? __instance : null);
				if (val != null)
				{
					OptimizeEffect(val.gameObject);
				}
			}
		}

		private static void DamageNumberManagerAwakePostfix(object __instance)
		{
			if (Plugin.Balance.PerformanceEnabled.Value && __instance != null)
			{
				FieldInfo field = __instance.GetType().GetField("maxDamageNums", AnyInstance);
				if (!(field == null))
				{
					int val = (int)field.GetValue(__instance);
					int val2 = Math.Max(0, Plugin.Balance.MaximumDamageNumbers.Value);
					field.SetValue(__instance, Math.Min(val, val2));
				}
			}
		}

		private static void OptimizeEffect(GameObject effect)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)effect == (Object)null)
			{
				return;
			}
			if (Plugin.Balance.EffectRendererOptimization.Value)
			{
				int num = Math.Max(1, Plugin.Balance.MaximumParticles.Value);
				ParticleSystem[] componentsInChildren = effect.GetComponentsInChildren<ParticleSystem>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					MainModule main = componentsInChildren[i].main;
					if (((MainModule)(ref main)).maxParticles > num)
					{
						((MainModule)(ref main)).maxParticles = num;
					}
				}
				Renderer[] componentsInChildren2 = effect.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren2)
				{
					if (val is ParticleSystemRenderer || val is TrailRenderer || val is LineRenderer)
					{
						val.shadowCastingMode = (ShadowCastingMode)0;
						val.receiveShadows = false;
						val.motionVectorGenerationMode = (MotionVectorGenerationMode)2;
					}
				}
			}
			if (Plugin.Balance.DisableEffectLightShadows.Value)
			{
				Light[] componentsInChildren3 = effect.GetComponentsInChildren<Light>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					componentsInChildren3[i].shadows = (LightShadows)0;
				}
			}
		}

		private static void PatchPostfix(Harmony harmony, string typeName, string methodName, string patchName)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(ReflectionUtil.RequireType(typeName), methodName, (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeName, methodName);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(PerformancePatches), patchName, (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(PerformancePatches).FullName, patchName);
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
	}
	[BepInPlugin("com.lucie.thegodruntheorycompat", "The GodRun Theory Compatibility", "2.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.lucie.thegodruntheorycompat";

		public const string PluginName = "The GodRun Theory Compatibility";

		public const string PluginVersion = "2.0.2";

		internal const string ClassicItemsReturnsGuid = "com.RiskySleeps.ClassicItemsReturns";

		internal const string CloudburstGuid = "CloudBurstTeam.Cloudburst";

		internal const string VanillaVoidGuid = "com.Zenithrium.vanillaVoid";

		internal const string NemesisRisingTidesGuid = "prodzpod.NemesisRisingTides";

		internal const string RiskOfOptionsGuid = "com.rune580.riskofoptions";

		private Harmony harmony;

		internal static Plugin Instance { get; private set; }

		internal static BalanceConfig Balance { get; private set; }

		internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Instance = this;
			Balance = new BalanceConfig(((BaseUnityPlugin)this).Config);
			harmony = new Harmony("com.lucie.thegodruntheorycompat");
			InstallOptional("Oppressive spherical aura", delegate
			{
				PatchClass(typeof(OppressiveAuraPhysicsPatch));
				PatchClass(typeof(OppressiveAuraVisualPatch));
			});
			InstallOptional("ClassicItemsReturns balance", delegate
			{
				ClassicItemsPatch.Install(harmony);
			});
			InstallOptional("Cloudburst balance", delegate
			{
				CloudburstPatch.Install(harmony);
			});
			InstallOptional("Crystalline Lotus null guard", delegate
			{
				LotusGuard.Install(harmony);
			});
			InstallOptional("base-game runtime stability guards", delegate
			{
				RuntimeStabilityPatches.Install(harmony);
			});
			InstallOptional("client performance controls", delegate
			{
				PerformancePatches.Install(harmony);
			});
			InstallOptional("Risk of Options integration", PerformancePatches.RegisterRiskOfOptions);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"The GodRun Theory Compatibility 2.0.2 initialized. Numeric patches are event-driven and perform no per-frame inventory scans.");
		}

		private void Start()
		{
			ClassicItemsPatch.ApplyFieldsAndLanguage();
			CloudburstPatch.ApplyFieldsAndLanguage();
		}

		private void PatchClass(Type patchType)
		{
			harmony.CreateClassProcessor(patchType).Patch();
		}

		private void InstallOptional(string name, Action install)
		{
			try
			{
				install();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied: " + name));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Skipped " + name + ": " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	internal sealed class BalanceConfig
	{
		internal readonly ConfigEntry<float> CloverBaseChance;

		internal readonly ConfigEntry<float> CloverStackChance;

		internal readonly ConfigEntry<int> ArmsRaceMissiles;

		internal readonly ConfigEntry<int> ArmsRaceMissilesPerStack;

		internal readonly ConfigEntry<float> ArmsRaceDamage;

		internal readonly ConfigEntry<float> ArmsRaceCooldown;

		internal readonly ConfigEntry<float> EnergyCellHealthy;

		internal readonly ConfigEntry<float> EnergyCellLowHealthExtra;

		internal readonly ConfigEntry<float> FireShieldThreshold;

		internal readonly ConfigEntry<float> FireShieldExplosion;

		internal readonly ConfigEntry<float> FireShieldBurnBase;

		internal readonly ConfigEntry<float> FireShieldBurnPerStack;

		internal readonly ConfigEntry<float> JewelBarrier;

		internal readonly ConfigEntry<float> JewelBarrierPerStack;

		internal readonly ConfigEntry<int> JewelGold;

		internal readonly ConfigEntry<float> MedallionChance;

		internal readonly ConfigEntry<float> MedallionDuration;

		internal readonly ConfigEntry<float> MedallionDurationPerStack;

		internal readonly ConfigEntry<float> RustyJump;

		internal readonly ConfigEntry<float> ShopperGold;

		internal readonly ConfigEntry<float> SnakeCrit;

		internal readonly ConfigEntry<float> SnakeCritDamagePerStack;

		internal readonly ConfigEntry<int> SnakeStageActivations;

		internal readonly ConfigEntry<float> ThalliumChance;

		internal readonly ConfigEntry<float> ThalliumDamage;

		internal readonly ConfigEntry<float> ThalliumSlow;

		internal readonly ConfigEntry<float> ThalliumDuration;

		internal readonly ConfigEntry<float> ThalliumDurationPerStack;

		internal readonly ConfigEntry<float> ToughTimesArmor;

		internal readonly ConfigEntry<float> CloudburstScale;

		internal readonly ConfigEntry<float> JapesDurationScale;

		internal readonly ConfigEntry<bool> EquipmentSlotGuard;

		internal readonly ConfigEntry<bool> DroneVendorGuard;

		internal readonly ConfigEntry<bool> DelusionChestGuard;

		internal readonly ConfigEntry<bool> PerformanceEnabled;

		internal readonly ConfigEntry<bool> EffectRendererOptimization;

		internal readonly ConfigEntry<int> MaximumParticles;

		internal readonly ConfigEntry<int> MaximumCorpses;

		internal readonly ConfigEntry<int> MaximumDamageNumbers;

		internal readonly ConfigEntry<bool> DisableEffectLightShadows;

		internal BalanceConfig(ConfigFile config)
		{
			//IL_0489: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: Expected O, but got Unknown
			//IL_04b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c2: Expected O, but got Unknown
			//IL_04ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Expected O, but got Unknown
			CloverBaseChance = config.Bind<float>("ClassicItemsReturns - 56 Leaf Clover", "Base elite drop chance percent", 0.5f, "Chance with one stack. Requires a restart.");
			CloverStackChance = config.Bind<float>("ClassicItemsReturns - 56 Leaf Clover", "Additional chance percent per stack", 0.1f, "Additional percentage points for each extra stack. Requires a restart.");
			ArmsRaceMissiles = config.Bind<int>("ClassicItemsReturns - Arms Race", "Base missiles", 2, "Missiles in the first-stack barrage.");
			ArmsRaceMissilesPerStack = config.Bind<int>("ClassicItemsReturns - Arms Race", "Missiles per extra stack", 1, "Additional missiles per stack.");
			ArmsRaceDamage = config.Bind<float>("ClassicItemsReturns - Arms Race", "Damage coefficient", 0.6f, "1.0 means 100% base damage.");
			ArmsRaceCooldown = config.Bind<float>("ClassicItemsReturns - Arms Race", "Recharge seconds", 15f, "Time required to reload a barrage.");
			EnergyCellHealthy = config.Bind<float>("ClassicItemsReturns - Energy Cell", "Healthy attack speed per stack", 0.08f, "0.08 means 8%. Requires a restart.");
			EnergyCellLowHealthExtra = config.Bind<float>("ClassicItemsReturns - Energy Cell", "Low health extra attack speed per stack", 0.16f, "Added progressively as health falls, producing 24% total at low health. Requires a restart.");
			FireShieldThreshold = config.Bind<float>("ClassicItemsReturns - Fire Shield", "Trigger health fraction", 0.08f, "Fraction of maximum combined health lost in one hit. Requires a restart.");
			FireShieldExplosion = config.Bind<float>("ClassicItemsReturns - Fire Shield", "Explosion damage coefficient", 1.2f, "1.2 means 120% base damage.");
			FireShieldBurnBase = config.Bind<float>("ClassicItemsReturns - Fire Shield", "Burn base damage coefficient", 1f, "1.0 means 100% base damage.");
			FireShieldBurnPerStack = config.Bind<float>("ClassicItemsReturns - Fire Shield", "Burn coefficient per extra stack", 0.75f, "0.75 means 75% additional base damage. Requires a restart.");
			JewelBarrier = config.Bind<float>("ClassicItemsReturns - Locked Jewel", "Barrier fraction", 0.1f, "0.10 means 10% maximum health.");
			JewelBarrierPerStack = config.Bind<float>("ClassicItemsReturns - Locked Jewel", "Barrier fraction per extra stack", 0.05f, "0.05 means 5% maximum health.");
			JewelGold = config.Bind<int>("ClassicItemsReturns - Locked Jewel", "Base gold reward", 4, "Value before difficulty/time scaling.");
			MedallionChance = config.Bind<float>("ClassicItemsReturns - Royal Medallion", "Orb chance percent", 5f, "Chance on a valid boss hit.");
			MedallionDuration = config.Bind<float>("ClassicItemsReturns - Royal Medallion", "Buff duration", 6f, "Seconds with one item.");
			MedallionDurationPerStack = config.Bind<float>("ClassicItemsReturns - Royal Medallion", "Duration per extra stack", 3f, "Additional seconds per stack.");
			RustyJump = config.Bind<float>("ClassicItemsReturns - Rusty Jetpack", "Jump power per stack", 0.12f, "0.12 means 12%. Requires a restart.");
			ShopperGold = config.Bind<float>("ClassicItemsReturns - Smart Shopper", "Extra enemy gold per stack", 0.1f, "0.10 means 10%.");
			SnakeCrit = config.Bind<float>("ClassicItemsReturns - Snake Eyes", "Critical chance per activation", 3f, "Percentage points per shrine activation.");
			SnakeCritDamagePerStack = config.Bind<float>("ClassicItemsReturns - Snake Eyes", "Critical damage per item stack and activation", 0.025f, "0.025 means 2.5%.");
			SnakeStageActivations = config.Bind<int>("ClassicItemsReturns - Snake Eyes", "Maximum activations per stage", 4, "Clamped between one and six. Requires a restart.");
			ThalliumChance = config.Bind<float>("ClassicItemsReturns - Thallium", "Proc chance percent", 5f, "Scales with proc coefficient.");
			ThalliumDamage = config.Bind<float>("ClassicItemsReturns - Thallium", "Victim damage coefficient", 0.6f, "0.6 means 60% of the greater attacker/victim damage value per tick calculation.");
			ThalliumSlow = config.Bind<float>("ClassicItemsReturns - Thallium", "Movement reduction", 0.4f, "0.4 means 40%.");
			ThalliumDuration = config.Bind<float>("ClassicItemsReturns - Thallium", "Base duration", 2f, "Seconds.");
			ThalliumDurationPerStack = config.Bind<float>("ClassicItemsReturns - Thallium", "Duration per extra stack", 0.75f, "Stored upstream but unused by CIR 3.6.26; retained for forward compatibility.");
			ToughTimesArmor = config.Bind<float>("ClassicItemsReturns - Tough Times", "Armor per stack", 8f, "Permanent armor per item stack.");
			CloudburstScale = config.Bind<float>("Cloudburst", "Finished item numerical scale", 0.5f, "Scales Glass Harvester crit damage, Bismuth barrier, Fabinhoru armor reduction, Jape healing/armor, and Keycard chance/damage. Requires a restart.");
			JapesDurationScale = config.Bind<float>("Cloudburst", "Japes Cloak duration scale", 0.6f, "0.6 changes ten seconds to six seconds. Requires a restart.");
			EquipmentSlotGuard = config.Bind<bool>("Stability", "Guard uninitialized equipment slots", true, "Prevents null equipment-set arrays from throwing every fixed update.");
			DroneVendorGuard = config.Bind<bool>("Stability", "Guard malformed drone vendor terminals", true, "Skips missing terminals or interactors while preserving valid drone dispatches.");
			DelusionChestGuard = config.Bind<bool>("Stability", "Guard malformed Delusion chests", true, "Disables only a malformed DelusionChestController when its Start method throws a null reference.");
			PerformanceEnabled = config.Bind<bool>("Performance", "Enable performance module", true, "Master switch for local visual performance changes. Does not alter combat or networking.");
			EffectRendererOptimization = config.Bind<bool>("Performance", "Optimize spawned effect renderers", true, "Caps particles and disables shadows and motion vectors on spawned particle, trail, and line effects.");
			MaximumParticles = config.Bind<int>("Performance", "Maximum particles per effect system", 400, new ConfigDescription("Upper limit for each newly spawned effect particle system.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(64, 2000), Array.Empty<object>()));
			MaximumCorpses = config.Bind<int>("Performance", "Maximum retained corpses", 10, new ConfigDescription("RoR2 normally retains up to 25 corpses. Lower values reduce late-stage renderer and physics load.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 25), Array.Empty<object>()));
			MaximumDamageNumbers = config.Bind<int>("Performance", "Maximum simultaneous damage numbers", 40, new ConfigDescription("Caps the existing client-side damage-number pool. Set to 0 to hide damage numbers.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			DisableEffectLightShadows = config.Bind<bool>("Performance", "Disable shadows on spawned effect lights", true, "Keeps effect lighting but removes its dynamic shadow cost.");
		}
	}
	internal static class ReflectionUtil
	{
		private const BindingFlags AnyStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>(StringComparer.Ordinal);

		internal static Type FindType(string name, string pluginGuid = null)
		{
			string key = (pluginGuid ?? string.Empty) + "|" + name;
			lock (TypeCache)
			{
				if (TypeCache.TryGetValue(key, out var value))
				{
					return value;
				}
			}
			Type type = null;
			if (!string.IsNullOrEmpty(pluginGuid) && Chainloader.PluginInfos.TryGetValue(pluginGuid, out var value2) && (Object)(object)value2.Instance != (Object)null)
			{
				type = ((object)value2.Instance).GetType().Assembly.GetType(name, throwOnError: false, ignoreCase: false);
			}
			if (type == null)
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					try
					{
						type = assembly.GetType(name, throwOnError: false, ignoreCase: false);
					}
					catch
					{
					}
					if (type != null)
					{
						break;
					}
				}
			}
			if (type != null)
			{
				lock (TypeCache)
				{
					TypeCache[key] = type;
				}
			}
			return type;
		}

		internal static Type RequireType(string name, string pluginGuid = null)
		{
			return FindType(name, pluginGuid) ?? throw new TypeLoadException(name);
		}

		internal static object GetSingleton(string typeName, string pluginGuid = null)
		{
			Type type = RequireType(typeName, pluginGuid);
			while (type != null)
			{
				PropertyInfo property = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					object value = property.GetValue(null, null);
					if (value != null)
					{
						return value;
					}
				}
				FieldInfo fieldInfo = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (fieldInfo != null)
				{
					object value2 = fieldInfo.GetValue(null);
					if (value2 != null)
					{
						return value2;
					}
				}
				type = type.BaseType;
			}
			throw new MissingMemberException(typeName, "Instance");
		}

		internal static void SetInstanceField(string typeName, string fieldName, object value, string pluginGuid = null)
		{
			object singleton = GetSingleton(typeName, pluginGuid);
			FieldInfo fieldInfo = singleton.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeName, fieldName);
			fieldInfo.SetValue(singleton, ConvertValue(value, fieldInfo.FieldType));
		}

		internal static void SetStaticField(string typeName, string fieldName, object value, string pluginGuid = null)
		{
			FieldInfo fieldInfo = RequireType(typeName, pluginGuid).GetField(fieldName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeName, fieldName);
			fieldInfo.SetValue(null, ConvertValue(value, fieldInfo.FieldType));
		}

		internal static object GetStaticField(string typeName, string fieldName, string pluginGuid = null)
		{
			return (RequireType(typeName, pluginGuid).GetField(fieldName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeName, fieldName)).GetValue(null);
		}

		internal static int GetBuffCount(object body, object buffDef)
		{
			if (body == null || buffDef == null)
			{
				return 0;
			}
			MethodInfo[] methods = body.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (methodInfo.Name == "GetBuffCount" && parameters.Length == 1 && parameters[0].ParameterType.IsInstanceOfType(buffDef))
				{
					return (int)methodInfo.Invoke(body, new object[1] { buffDef });
				}
			}
			return 0;
		}

		internal static void AddFloatMember(object target, string name, float delta)
		{
			if (target == null)
			{
				return;
			}
			FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				field.SetValue(target, Convert.ToSingle(field.GetValue(target), CultureInfo.InvariantCulture) + delta);
				return;
			}
			PropertyInfo property = target.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.CanRead && property.CanWrite)
			{
				property.SetValue(target, Convert.ToSingle(property.GetValue(target, null), CultureInfo.InvariantCulture) + delta, null);
			}
		}

		internal static void AddLanguage(string token, string text)
		{
			Type type = FindType("R2API.LanguageAPI", "com.bepis.r2api.language");
			if (type == null)
			{
				throw new TypeLoadException("R2API.LanguageAPI");
			}
			(AccessTools.Method(type, "Add", new Type[2]
			{
				typeof(string),
				typeof(string)
			}, (Type[])null) ?? throw new MissingMethodException("R2API.LanguageAPI", "Add(string, string)")).Invoke(null, new object[2] { token, text });
		}

		private static object ConvertValue(object value, Type destination)
		{
			if (value == null || destination.IsInstanceOfType(value))
			{
				return value;
			}
			return Convert.ChangeType(value, destination, CultureInfo.InvariantCulture);
		}
	}
	internal static class RuntimeStabilityPatches
	{
		[HarmonyPatch]
		private static class EquipmentSlotStartGuard
		{
			private static readonly Type SlotType = ReflectionUtil.RequireType("RoR2.EquipmentSlot");

			private static readonly FieldInfo ActiveSet = AccessTools.Field(SlotType, "<activeEquipmentSet>k__BackingField");

			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(SlotType, "Start", (Type[])null, (Type[])null);
			}

			private static Exception Finalizer(object __instance, Exception __exception)
			{
				if (__exception is NullReferenceException && ActiveSet.GetValue(__instance) == null)
				{
					ActiveSet.SetValue(__instance, new byte[8]);
					LogOnce(ref equipmentLogged, "Recovered an EquipmentSlot that started before its run/components were fully available.");
					return null;
				}
				return __exception;
			}
		}

		[HarmonyPatch]
		private static class EquipmentSlotInventoryGuard
		{
			private static readonly Type SlotType = ReflectionUtil.RequireType("RoR2.EquipmentSlot");

			private static readonly FieldInfo ActiveSet = AccessTools.Field(SlotType, "<activeEquipmentSet>k__BackingField");

			private static readonly PropertyInfo CharacterBody = AccessTools.Property(SlotType, "characterBody");

			private static readonly Type BodyType = ReflectionUtil.RequireType("RoR2.CharacterBody");

			private static readonly PropertyInfo Inventory = AccessTools.Property(BodyType, "inventory");

			private static readonly Type InventoryType = ReflectionUtil.RequireType("RoR2.Inventory");

			private static readonly PropertyInfo InventoryActiveSet = AccessTools.Property(InventoryType, "activeEquipmentSet");

			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(SlotType, "UpdateInventory", (Type[])null, (Type[])null);
			}

			private static bool Prefix(object __instance)
			{
				object value = CharacterBody.GetValue(__instance, null);
				if (Missing(value))
				{
					LogOnce(ref equipmentLogged, "Skipped an EquipmentSlot inventory update with no CharacterBody.");
					return false;
				}
				object value2 = Inventory.GetValue(value, null);
				if (Missing(value2))
				{
					LogOnce(ref equipmentLogged, "Skipped an EquipmentSlot inventory update before its Inventory was available.");
					return false;
				}
				byte[] array = InventoryActiveSet.GetValue(value2, null) as byte[];
				byte[] array2 = ActiveSet.GetValue(__instance) as byte[];
				int num = Math.Max(8, (array != null) ? array.Length : 0);
				if (array2 == null || array2.Length < num)
				{
					ActiveSet.SetValue(__instance, new byte[num]);
					LogOnce(ref equipmentLogged, "Initialized a missing EquipmentSlot active-equipment array before UpdateInventory.");
				}
				return true;
			}
		}

		[HarmonyPatch]
		private static class DroneVendorDispatchGuard
		{
			private static readonly Type ControllerType = ReflectionUtil.RequireType("RoR2.DroneVendorMultiShopController");

			private static readonly FieldInfo Terminals = AccessTools.Field(ControllerType, "_terminals");

			private static readonly FieldInfo Purchase = AccessTools.Field(ControllerType, "_purchaseInteraction");

			private static readonly FieldInfo Interactor = AccessTools.Field(ControllerType, "_interactor");

			private static readonly Type TerminalType = ReflectionUtil.RequireType("RoR2.DroneVendorTerminalBehavior");

			private static readonly FieldInfo TerminalPurchase = AccessTools.Field(TerminalType, "purchaseInteraction");

			private static readonly MethodInfo Dispatch = AccessTools.Method(TerminalType, "DispatchDrone", (Type[])null, (Type[])null);

			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(ControllerType, "DispatchDrone", (Type[])null, (Type[])null);
			}

			private static bool Prefix(object __instance)
			{
				Array array = Terminals.GetValue(__instance) as Array;
				object value = Purchase.GetValue(__instance);
				object value2 = Interactor.GetValue(__instance);
				if (array == null || Missing(value) || Missing(value2))
				{
					LogOnce(ref vendorLogged, "Skipped malformed Drone Vendor dispatch data instead of throwing a null reference.");
					return false;
				}
				foreach (object item in array)
				{
					if (!Missing(item) && TerminalPurchase.GetValue(item) == value)
					{
						Dispatch.Invoke(item, new object[1] { value2 });
					}
				}
				return false;
			}
		}

		[HarmonyPatch]
		private static class DelusionChestStartGuard
		{
			private static readonly Type ControllerType = ReflectionUtil.RequireType("RoR2.DelusionChestController");

			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(ControllerType, "Start", (Type[])null, (Type[])null);
			}

			private static Exception Finalizer(object __instance, Exception __exception)
			{
				if (__exception is NullReferenceException)
				{
					Behaviour val = (Behaviour)((__instance is Behaviour) ? __instance : null);
					if ((Object)(object)val != (Object)null)
					{
						val.enabled = false;
					}
					LogOnce(ref delusionLogged, "Disabled one malformed DelusionChestController after its required component was missing.");
					return null;
				}
				return __exception;
			}
		}

		private static readonly object LogLock = new object();

		private static bool equipmentLogged;

		private static bool vendorLogged;

		private static bool delusionLogged;

		internal static void Install(Harmony harmony)
		{
			BalanceConfig balance = Plugin.Balance;
			if (balance.EquipmentSlotGuard.Value)
			{
				harmony.CreateClassProcessor(typeof(EquipmentSlotStartGuard)).Patch();
				harmony.CreateClassProcessor(typeof(EquipmentSlotInventoryGuard)).Patch();
			}
			if (balance.DroneVendorGuard.Value)
			{
				harmony.CreateClassProcessor(typeof(DroneVendorDispatchGuard)).Patch();
			}
			if (balance.DelusionChestGuard.Value)
			{
				harmony.CreateClassProcessor(typeof(DelusionChestStartGuard)).Patch();
			}
		}

		private static bool Missing(object value)
		{
			if (value == null)
			{
				return true;
			}
			Object val = (Object)((value is Object) ? value : null);
			if (val != null)
			{
				return !Object.op_Implicit(val);
			}
			return false;
		}

		private static void LogOnce(ref bool flag, string message)
		{
			lock (LogLock)
			{
				if (!flag)
				{
					flag = true;
					Plugin.Instance.Log.LogWarning((object)message);
				}
			}
		}
	}
}