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 to on death. .");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_ARMSRACE_DESCRIPTION", $"Drones periodically fire a barrage of missiles that deal damage. Recharges every seconds.");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_ENERGYCELL_DESCRIPTION", $"Increase attack speed by , increasing by up to another as health falls.");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_FIRESHIELD_DESCRIPTION", $"After taking more than as damage, explode for base damage. Additionally, enemies burn for base damage.");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_JEWEL_DESCRIPTION", $"Activating an interactable grants a temporary barrier for of maximum health and . Scales with time.");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_ROYALMEDALLION_DESCRIPTION", $" chance on hitting a boss to drop a buffing orb that improves health regeneration, attack speed, movement speed, and base damage for .");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_RUSTYJETPACK_DESCRIPTION", $"Increase jump height by and gain a short airhop.");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_SMARTSHOPPER_DESCRIPTION", $"Enemies drop an extra gold on kill.");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_SNAKEEYES_DESCRIPTION", $"Using a shrine increases critical chance by and critical damage by , up to . Resets each stage.");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_THALLIUM_DESCRIPTION", $"On hit, to poison using and slow movement by for .");
ReflectionUtil.AddLanguage("CLASSICITEMSRETURNS_ITEM_TOUGHTIMES_DESCRIPTION", $"Grants .");
}
}
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 CloverTranspiler(IEnumerable 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 EnergyCellTranspiler(IEnumerable 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 FireShieldTranspiler(IEnumerable source)
{
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Expected O, but got Unknown
List list = new List(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 RustyJetpackTranspiler(IEnumerable 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 SnakeEyesCapTranspiler(IEnumerable 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 . deal an additional . Taking damage below breaks this item and grants experience.");
ReflectionUtil.AddLanguage("ITEM_BARRIERONCRIT_DESCRIPTION", $"Gain . Applying bleed grants .");
ReflectionUtil.AddLanguage("ITEM_PICKUPBUFF_DESCRIPTION", $"Picking up an item grants a stacking buff for . 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 GlassTranspiler(IEnumerable 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 JapesArmorTranspiler(IEnumerable instructions)
{
return ReplaceFloat(instructions, 5f, 5f * Math.Max(0f, Plugin.Balance.CloudburstScale.Value), delegate
{
japesArmorReplacements++;
});
}
private static IEnumerable JapesHealingTranspiler(IEnumerable instructions)
{
float num = Math.Max(0f, Plugin.Balance.CloudburstScale.Value);
return ReplaceFloat(instructions, 1.3f, 1f + 0.3f * num, delegate
{
japesHealingReplacements++;
});
}
private static IEnumerable JapesDurationTranspiler(IEnumerable instructions)
{
return ReplaceFloat(instructions, 10f, 10f * Math.Max(0f, Plugin.Balance.JapesDurationScale.Value), delegate
{
japesDurationReplacements++;
});
}
private static IEnumerable KeycardDamageTranspiler(IEnumerable 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 list = new List(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 ReplaceFloat(IEnumerable 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 Transpiler(IEnumerable 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();
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();
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(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(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(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 CloverBaseChance;
internal readonly ConfigEntry CloverStackChance;
internal readonly ConfigEntry ArmsRaceMissiles;
internal readonly ConfigEntry ArmsRaceMissilesPerStack;
internal readonly ConfigEntry ArmsRaceDamage;
internal readonly ConfigEntry ArmsRaceCooldown;
internal readonly ConfigEntry EnergyCellHealthy;
internal readonly ConfigEntry EnergyCellLowHealthExtra;
internal readonly ConfigEntry FireShieldThreshold;
internal readonly ConfigEntry FireShieldExplosion;
internal readonly ConfigEntry FireShieldBurnBase;
internal readonly ConfigEntry FireShieldBurnPerStack;
internal readonly ConfigEntry JewelBarrier;
internal readonly ConfigEntry JewelBarrierPerStack;
internal readonly ConfigEntry JewelGold;
internal readonly ConfigEntry MedallionChance;
internal readonly ConfigEntry MedallionDuration;
internal readonly ConfigEntry MedallionDurationPerStack;
internal readonly ConfigEntry RustyJump;
internal readonly ConfigEntry ShopperGold;
internal readonly ConfigEntry SnakeCrit;
internal readonly ConfigEntry SnakeCritDamagePerStack;
internal readonly ConfigEntry SnakeStageActivations;
internal readonly ConfigEntry ThalliumChance;
internal readonly ConfigEntry ThalliumDamage;
internal readonly ConfigEntry ThalliumSlow;
internal readonly ConfigEntry ThalliumDuration;
internal readonly ConfigEntry ThalliumDurationPerStack;
internal readonly ConfigEntry ToughTimesArmor;
internal readonly ConfigEntry CloudburstScale;
internal readonly ConfigEntry JapesDurationScale;
internal readonly ConfigEntry EquipmentSlotGuard;
internal readonly ConfigEntry DroneVendorGuard;
internal readonly ConfigEntry DelusionChestGuard;
internal readonly ConfigEntry PerformanceEnabled;
internal readonly ConfigEntry EffectRendererOptimization;
internal readonly ConfigEntry MaximumParticles;
internal readonly ConfigEntry MaximumCorpses;
internal readonly ConfigEntry MaximumDamageNumbers;
internal readonly ConfigEntry 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("ClassicItemsReturns - 56 Leaf Clover", "Base elite drop chance percent", 0.5f, "Chance with one stack. Requires a restart.");
CloverStackChance = config.Bind("ClassicItemsReturns - 56 Leaf Clover", "Additional chance percent per stack", 0.1f, "Additional percentage points for each extra stack. Requires a restart.");
ArmsRaceMissiles = config.Bind("ClassicItemsReturns - Arms Race", "Base missiles", 2, "Missiles in the first-stack barrage.");
ArmsRaceMissilesPerStack = config.Bind("ClassicItemsReturns - Arms Race", "Missiles per extra stack", 1, "Additional missiles per stack.");
ArmsRaceDamage = config.Bind("ClassicItemsReturns - Arms Race", "Damage coefficient", 0.6f, "1.0 means 100% base damage.");
ArmsRaceCooldown = config.Bind("ClassicItemsReturns - Arms Race", "Recharge seconds", 15f, "Time required to reload a barrage.");
EnergyCellHealthy = config.Bind("ClassicItemsReturns - Energy Cell", "Healthy attack speed per stack", 0.08f, "0.08 means 8%. Requires a restart.");
EnergyCellLowHealthExtra = config.Bind("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("ClassicItemsReturns - Fire Shield", "Trigger health fraction", 0.08f, "Fraction of maximum combined health lost in one hit. Requires a restart.");
FireShieldExplosion = config.Bind("ClassicItemsReturns - Fire Shield", "Explosion damage coefficient", 1.2f, "1.2 means 120% base damage.");
FireShieldBurnBase = config.Bind("ClassicItemsReturns - Fire Shield", "Burn base damage coefficient", 1f, "1.0 means 100% base damage.");
FireShieldBurnPerStack = config.Bind("ClassicItemsReturns - Fire Shield", "Burn coefficient per extra stack", 0.75f, "0.75 means 75% additional base damage. Requires a restart.");
JewelBarrier = config.Bind("ClassicItemsReturns - Locked Jewel", "Barrier fraction", 0.1f, "0.10 means 10% maximum health.");
JewelBarrierPerStack = config.Bind("ClassicItemsReturns - Locked Jewel", "Barrier fraction per extra stack", 0.05f, "0.05 means 5% maximum health.");
JewelGold = config.Bind("ClassicItemsReturns - Locked Jewel", "Base gold reward", 4, "Value before difficulty/time scaling.");
MedallionChance = config.Bind("ClassicItemsReturns - Royal Medallion", "Orb chance percent", 5f, "Chance on a valid boss hit.");
MedallionDuration = config.Bind("ClassicItemsReturns - Royal Medallion", "Buff duration", 6f, "Seconds with one item.");
MedallionDurationPerStack = config.Bind("ClassicItemsReturns - Royal Medallion", "Duration per extra stack", 3f, "Additional seconds per stack.");
RustyJump = config.Bind("ClassicItemsReturns - Rusty Jetpack", "Jump power per stack", 0.12f, "0.12 means 12%. Requires a restart.");
ShopperGold = config.Bind("ClassicItemsReturns - Smart Shopper", "Extra enemy gold per stack", 0.1f, "0.10 means 10%.");
SnakeCrit = config.Bind("ClassicItemsReturns - Snake Eyes", "Critical chance per activation", 3f, "Percentage points per shrine activation.");
SnakeCritDamagePerStack = config.Bind("ClassicItemsReturns - Snake Eyes", "Critical damage per item stack and activation", 0.025f, "0.025 means 2.5%.");
SnakeStageActivations = config.Bind("ClassicItemsReturns - Snake Eyes", "Maximum activations per stage", 4, "Clamped between one and six. Requires a restart.");
ThalliumChance = config.Bind("ClassicItemsReturns - Thallium", "Proc chance percent", 5f, "Scales with proc coefficient.");
ThalliumDamage = config.Bind("ClassicItemsReturns - Thallium", "Victim damage coefficient", 0.6f, "0.6 means 60% of the greater attacker/victim damage value per tick calculation.");
ThalliumSlow = config.Bind("ClassicItemsReturns - Thallium", "Movement reduction", 0.4f, "0.4 means 40%.");
ThalliumDuration = config.Bind("ClassicItemsReturns - Thallium", "Base duration", 2f, "Seconds.");
ThalliumDurationPerStack = config.Bind("ClassicItemsReturns - Thallium", "Duration per extra stack", 0.75f, "Stored upstream but unused by CIR 3.6.26; retained for forward compatibility.");
ToughTimesArmor = config.Bind("ClassicItemsReturns - Tough Times", "Armor per stack", 8f, "Permanent armor per item stack.");
CloudburstScale = config.Bind("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("Cloudburst", "Japes Cloak duration scale", 0.6f, "0.6 changes ten seconds to six seconds. Requires a restart.");
EquipmentSlotGuard = config.Bind("Stability", "Guard uninitialized equipment slots", true, "Prevents null equipment-set arrays from throwing every fixed update.");
DroneVendorGuard = config.Bind("Stability", "Guard malformed drone vendor terminals", true, "Skips missing terminals or interactors while preserving valid drone dispatches.");
DelusionChestGuard = config.Bind("Stability", "Guard malformed Delusion chests", true, "Disables only a malformed DelusionChestController when its Start method throws a null reference.");
PerformanceEnabled = config.Bind("Performance", "Enable performance module", true, "Master switch for local visual performance changes. Does not alter combat or networking.");
EffectRendererOptimization = config.Bind("Performance", "Optimize spawned effect renderers", true, "Caps particles and disables shadows and motion vectors on spawned particle, trail, and line effects.");
MaximumParticles = config.Bind("Performance", "Maximum particles per effect system", 400, new ConfigDescription("Upper limit for each newly spawned effect particle system.", (AcceptableValueBase)(object)new AcceptableValueRange(64, 2000), Array.Empty